Linux generic

psycho 2015. 1. 2. 07:54

 이 글에서는 필자가 실제로 겪은 상황을 바탕으로 Linux를 사용하면서 문제를 겪을 때 해결할 수 있는 수많은 방안 중 하나를 이야기해보려 한다. 혹시 자신이 비슷한 문제를 겪고 있고 단순히 해결법이 알고 싶은 독자라면 중간 부분 일부와 맨 마지막 부분만 읽어도 될 것이다. 그러나, 뭔가를 배우고자 하는 독자라면 지루할지라도 반드시 처음부터 정독할 것을 권한다.




 필자는 이 글을 쓰고 있는 현재 LG FLATRON LX20CP 모델의 모니터를 사용하고 있다. 이 모니터는 4:3 화면비의 20인치 크기로, 1600x1200 해상도를 지원한다. DVI 입력과 D-SUB 입력을 한 개씩 지원하며, 여기에 두 대의 컴퓨터를 물려 화면을 전환해가며 사용하고 있다. 어째서 요새는 나오지도 않는 "구식" 모니터의 스펙을 줄줄이 늘어놓냐면, 이 녀석의 특이성 때문에 발생한 문제가 있고, 이 글에서는 그 사건을 철저하게 이용할 것이기 때문이다.


 이 모니터의 D-SUB 입력 쪽에는 무려 AGP 방식의 그래픽카드 - ATI1 RADEON 8500 - 를 사용하는 구형 컴퓨터가 물려있다. Windows XP 지원이 종료되어 이 컴퓨터에서는 더 이상 Windows 운영체제를 정상적으로 사용할 수 없게 되었는데, 그 이유는 구시대의 유물이라 불러도 좋을 그래픽카드 모델만 보아도 충분히 짐작하리라 믿는다. 그렇다. 전용 드라이버가 제공되지 않아 현재 사용하는 모니터에 맞는 1600x1200 해상도를 쓸 수가 없게 되어버린 거다. 물론 이후 운영체제에서 기본으로 사용하는 1024x768 해상도로 만족하겠다면 못 쓸 일이야 없겠지만, LCD모니터를 사용하면서 최적화된 해상도로 사용하지 못한다면 단순히 화면 영역이 작다는 것 이상의 난감함이 있음을 독자들도 이해할 것이다.


 그렇다고 못 써먹을 수준의 물건은 또 아닌 탓에 별수없이 Linux를 깔아서 활용하게 되었다. 다행히 Linux의 경우엔 드라이버들이 죄다 open source인데다 어지간하면 구형 장비에 대한 지원을 빼지 않는지라 단순히 Kernel을 컴파일하는 것으로 사용할 수 있기 때문이다. 요즘엔 그래픽 지원이 대폭 강화되어 어지간하면 설정 삽질(?) 없이 그래픽 환경을 이용할 수 있게 된 점도 있다.


 Linux가 멀쩡하게 구동됨을 확인한 기쁨도 잠시, 문제가 발생했다. 어찌된 일인지 이 녀석마저도 1024x768 해상도로 떠버리는 것이다. 혹시나 싶어 DVI로 연결하자(다행히도 필자가 사용하는 그래픽카드는 그 연세(...)에 믿기지 않을지도 모르지만 DVI 출력단자와 D-SUB 출력단자가 각각 하나씩 있다) 멀쩡하게 1600x1200 해상도로 출력이 된다. 다시 D-SUB로 모니터를 연결하고 dmesg로 로그를 확인해봤지만, 아무것도 연결되어 있지 않은 DVI 단자에도 무언가가 연결되어 있는 것처럼 동작한다는 것2을 빼면 별다른 이상을 찾을 수 없었다.


 일단 Xorg만 제 해상도로 쓸 수 있어도 큰 문제는 없었기에, xorg.conf 설정 파일에다 1600x1200 해상도를 사용하도록 설정해보았다. 결과는 당연히 실패. Xorg의 로그 파일을 확인하자, 그래도 문제의 원인이 될 만한 것을 파악할 수 있었다. 호랑이 담배 먹던 시절의 그래픽 드라이버들은 화면 해상도라든가 수직 동기, 수평 동기 값 등을 전부 수동으로 입력해줘야 했지만, 요즘의 드라이버들은 DRM-KMS라는 Kernel 내 모듈과 연동되어 그런 값들을 자동으로 설정한다. 그런데 모니터가 1600x1200 해상도를 지원함에도 불구하고 D-SUB로 연결하면 이 해상도를 감지하지 못하는 것이었다.


 모니터를 다시 DVI로 연결한 다음 Xorg 로그를 확인해보았다. 당연하다는 듯이 1600x1200 해상도가 나온다. 좀 더 자세하게 살펴보자 "EDID for output DVI-0"이라는 메시지가 있고 그 밑으로 모니터에 대한 정보가 주르륵 나오는 것을 확인할 수 있었다. 이 EDID 정보라는 것은 모니터가 자신이 지원하는 해상도나 입력 신호 주파수 등을 저장해둔 것으로, 그래픽 드라이버는 이 정보를 바탕으로 화면 출력에 대한 설정을 하는 것이다. 이게 정상적으로 작동하려면 D-SUB로 연결했을 때에도 똑같은 정보가 나와야 할 것인데, D-SUB로 연결했을 때는 아무런 정보도 나오지 않는 것을 확인할 수 있었다. 즉, 필자의 그래픽카드는 모니터를 D-SUB로 연결했을 때 모니터의 EDID 정보를 제대로 받아오지 못해 거의 모든 모니터에서 지원하는 표준 parameter(즉, 1024x768 해상도)로 화면 출력을 하게 된 것이었다.


 다시 검색을 해보니 Xorg 설정 파일에서 EDID 정보를 수동으로 불러오는 옵션이 있었다. 이를 사용하려면 이 모니터의 정상적인 EDID 정보를 추출할 필요가 있기 때문에, 다시 DVI 단자에 모니터를 연결하고 작업을 시작했다. 필자는 read-edid 패키지에 포함된 get-edid를 사용했다. (Kernel 수준에서 아무런 조작을 하지 않았다는 가정하에)Xorg 로그 파일에 나오는 "EDID (in hex):" 다음에 나오는 128바이트의 데이터를 이진 파일로 입력해도 된다.


 # get-edid > LX20CP.bin


 그 다음 http://www.x.org/archive/X11R7.5/doc/man/man4/radeon.4.html 페이지를 참고하여 Xorg 설정 파일을 만들었다.


Section "Device"

  Identifier "ATI Radeon 8500 QL (AGP)" # Xorg 로그 파일에 나오는 그래픽 카드 이름을 그대로 사용.

  Driver "radeon"

  Option "CustomEDID" "/etc/X11/xorg.conf.d/LX20CP.bin"

EndSection


 그리고 다시 Xorg를 구동했다. 이 시점에서 제대로 작동했으면 좋았겠지만, 아쉽게도 역시 실패했다. 로그를 다시 살펴보니 도대체 무엇 때문인지 CustomEDID 옵션 자체를 무시해버린다. 구글신에게 좀 더 의지해봤지만 왜 이 옵션을 무시하고 어떻게 하면 사용할 수 있는지에 대한 정보를 더 얻을 수는 없었다.


 다른 방법이 없나 싶어 더 찾아보니, Kernel 수준에서 EDID 정보를 강제로 설정하는 기능이 있다고 한다. 그래서 https://wiki.archlinux.org/index.php/kernel_mode_setting 페이지를 참고하여 /lib/firmware/edid 디렉토리를 만들어 아까 만든 EDID 데이터 파일을 옮겨둔 후(필자가 사용한 시스템은 initrd를 사용하지 않는다) 부트로더 설정을 수정하여 부팅시에 데이터를 읽어올 수 있도록 했다3.


 재부팅을 하며 기대감을 가진 것도 잠시, 여전히 무엇 하나 변하지 않은 저해상도의 화면이 필자를 반겨주었다. dmesg로 확인해보니 멀쩡하게 제 경로에 잘 있는 파일을 못 읽어온다고 한다. 이 역시 어째서 제대로 작동하는지에 대한 확실한 정보는 얻을 수 없었으나, 필자의 짐작으로는 initrd를 사용하지 않는 것과 연관이 있는 듯하다. Kernel에서 부팅 중에 filesystem 상에서 필요한 데이터를 읽어들이는 기능은 대개 initrd를 사용하는 것을 전제로 하고 있기 때문이다.


 Kernel 설정의 설명을 읽어보니, 고맙게도 EDID 정보를 Kernel 자체에 내장을 시킬 수가 있는 모양이다. 문제는 최근의 그래픽카드 드라이버에서 요구하는 Firmware 파일과는 다르게, EDID 정보를 가진 파일의 경로를 설정해서 컴파일시에 내장시킬 수가 없고, source 자체를 수정해서 집어넣는 것이 유일한 해결책이라는 것이다. 다행히 검색을 통해 drivers/gpu/drm/drm_edid_load.c 파일에 내장되는 EDID 정보가 정의되어 있는 것을 알아내어, 이전에 추출한 데이터를 C에서 사용하는 char형 배열 형태로 바꾸어 내장시키는 데 성공했다. 그리고 이 EDID 정보를 불러오도록 부트로더 설정을 수정하고 재부팅하였다.


 여기까지만 해도 참 긴 여정을 거쳤는데, 완전하게 해결되었으면 얼마나 좋았을까. 일단 절반은 성공하였다. 이제 콘솔 화면이 제대로 1600x1200으로 잡혀서 나온다. 그런데, 어찌된 일인지 메시지 출력이 화면 전체를 사용하질 않는다. Xorg를 구동시키니 여전히 작은 화면이다. 도대체 어찌된 일일까?


 앞에서 이 그래픽카드가 도대체 어찌된 일인지 D-SUB 단자에만 모니터를 연결하고 사용하는데도 불구하고 DVI 단자에 모니터가 연결된 것처럼 인식한다는 언급을 했을 것이다. 다시 Xorg 로그를 보니 명확해졌다. DVI 단자에 뭔가가 연결되어 있다고 주장하니 당연히 EDID 데이터를 읽어들이려고 하는데, 정상적으로 모니터가 연결된 것이 아니니 제대로 데이터가 올 리가 없다. 그래서 그래픽 드라이버 쪽에서는 EDID 강제 설정 이전의 D-SUB처럼 처리하여 1024x768 화면 출력을 잡아버리고, 더 큰 해상도를 지원하는 D-SUB 출력에다가 일종의 출력 동기화를 시켜버린 것이다. 다행히도 아까 언급한 Archwiki에 특정 포트에 대한 출력을 강제로 꺼버리는 기능에 대한 설명도 있어 그것을 참고하여 부트로더 설정을 수정하고 재부팅을 하였다.


 드디어 성공했다. 이놈의 모니터 출력 문제 때문에 몇 시간을 허비하였는가. 과정을 다 알고 그것을 글로 옮기는 데만도 두어 시간이 흘렀는데, 아무것도 모르는 상태에서 좌충우돌하며 상술한 과정을 알아가는 데 걸린 시간은 오죽할 것인가. 그러나 이 글에서 진짜로 중요한 것은 필자의 푸념이 아니라, Source를 수정해서라도 문제를 해결할 수 있는 open source의 유연함과 문제를 진단하고 해결을 시도하는 과정들일 것이다. 물론 source를 공개하지 않는 소프트웨어도 그 나름의 장점이 있으며, open source에도 단점이 있다. 그러나, 당면한 문제를 해결함과 동시에 지적 호기심도 충족시켜줄 수 있는 점이야말로 우리가 Linux를 사용하는 이유일 것이다.

각주 1

AMD가 아니다! 이 그래픽카드는 엄연히 ATI와 AMD가 합병되기 이전에 생산된 카드다.

각주 2

이것을 여기에서 언급만 하고 넘어가는 이유는, 이 사실이 중요해지는 시점에 서술하기 위해서이다.

각주 3

이 기능을 사용하기 위해서는 다음 Kernel 옵션을 활성화해야 한다: DRM_LOAD_EDID_FIRMWARE

  1. AMD가 아니다! 이 그래픽카드는 엄연히 ATI와 AMD가 합병되기 이전에 생산된 카드다. [본문으로]
  2. 이것을 여기에서 언급만 하고 넘어가는 이유는, 이 사실이 중요해지는 시점에 서술하기 위해서이다. [본문으로]
  3. 이 기능을 사용하기 위해서는 다음 Kernel 옵션을 활성화해야 한다: DRM_LOAD_EDID_FIRMWARE [본문으로]