▣ 원문 출처: http://lethean.pe.kr/2006/12/19/uio-linux-userspace-kernel-driver/
리눅스에서 디바이스 드라이버는 대개 동적으로 로딩 가능한 커널 모듈 방식이나 커널 자체에 포함시키는 방식으로 구성된다. 사용자공간(userspace)에서 일반 어플리케이션처럼 동작하는 디바이스 드라이버 구조는 X서버, Cupsys 프린터 드라이버 등에서 이미 사용되고 있듯이 새로운 개념은 아니다. 하지만 그 용도가 제한되어 있고, 인터럽트 처리와 성능에 대한 한계로 인해 아직도 대부분의 리눅스용 디바이스 드라이버는 커널 모듈로 작성되는 것이 일반적이다.
예전에 리눅스용 사용자공간 드라이버 개발 프레임워크가 제안된 적이 있다가 많은 관심과 비판을 함께 받고 사라진 듯 싶더니 이번에 다시 -mm 커널 트리에 UIO 코어라는 이름으로 다시 포함이 된 것 같다. 정식 커널에 포함될지는 아직 잘 모르지만 그 구조가 흥미로울 것 같아 한번 들여다 보았다.
UIO 코어는 하드웨어가 발생하는 인터럽트를 처리하기 위한 최소한의 커널 드라이버만 작성하고, 나머지 모든 작업은 사용자공간 프로그램으로 작성하도록 한다. 이를 통해 다양한 라이브러리와 개발도구를 사용할 수 있기 때문에 유지보수와 디버깅이 훨씬 쉬워진다. 드라이버 개발자가 느끼는 리눅스 커널의 가장 큰 장점이자 단점인 커널이 변경되어도 드라이버는 거의 변경할 필요도 없어진다. 또한 라이센스 문제도 피해갈 수 있다.
UIO가 동작하는 방식은 다음과 같다.
각각의 UIO 장치는 하나의 디바이스 파일과 sysfs 속성 파일을 통해 접근한다. 디바이스 파일 이름은 /dev/uio0, /dev/uio1 식이다. 이 디바이스 파일은 mmap()을 이용해 장치의 특정한 레지스터나 램 영역을 주소 공간처럼 접근하는데 이용한다. 인터럽트는 디바이스 파일을 읽는 작업을 통해 이루어진다. read() 시스템콜을 호출하면 블럭킹 상태에 있다가 인터럽트가 발생하면 깨어나 총 인터럽트 발생 횟수를 돌려준다. 이렇게 돌려받은 총 인터럽트 발생 횟수를 이용해 놓친 인터럽트에 대한 처리도 가능하다.
인터럽트를 제대로 처리하기 위해 드라이버만의 고유한 커널 모듈 인터럽트 핸들러를 구현할 경우라도 내부 핸들러가 자동으로 호출해 준다. 인터럽트를 발생하지 않고 폴링 방식으로 동작하는 장치일 경우 타이머를 이용해 주기적으로 강제로 인터럽트 핸들러를 호출하게 할 수도 있다.
드라이버는 sysfs를 통해 추가적인 접근 가능한 속성을 제공할 수도 있는데 다음은 UIO가 제공하는 기본 속성으로, /sys/class/uio/uioX 디렉토리에서 볼 수 있다.
- name : 장치 이름
- addr : 맵핑 가능 영역 시작 주소
- size : 맵핑 가능 영역 크기
- version : 드라이버 버전 정보
- event: 마지막으로 장치를 읽은 이후 드라이버가 처리한 인터럽트 총 갯수
커널 모듈에서 동작하는 인터럽트 핸들러를 작성하려면 struct uio_info 구조체에 정보를 채워 uio_register_device()를 이용해 등록하면 된다. 이 정보에는 인터럽트 핸들러 방식, 메모리 맵핑 정보 등을 담고 있다.
많 은 하드웨어들이 인터럽트 발생후 드라이버 ACK 작업을 해주어야하는데, 사용자공간 프로그램은 동작하지 않을 수도 있고, 어떠한 원인으로 종료할 수도 있으므로 이런 작업은 직접 작성한 인터럽트 핸들러에서 처리하도록 하고 있다. 또한 인터럽트 발생할때마다 데이터를 하드웨어에서 읽어 커널 내부 버퍼에 저장하고 사용자공간 프로그램에게 전달할 수도 있다.
모노리식 커널의 한계일지도 모르지만 약간 조잡하다는 느낌을 지울 수 없다. 조금 더 편하게 커널 API를 통해 인터럽트 이벤트를 처리할 수 있으면 좋을 것 같다. 또한 커널 내부의 PCI, USB 등의 서브시스템과의 연동은 어떻게 할 것인가? 물론 PCI나 USB 정보 사용자공간에서 접근이 가능하긴 하지만, 아직은 이론적으로 이상적인 프레임웍으로만 보인다. 그렇다면 마이크로커널 기반에서 디바이스 드라이버는 어떤 식으로 인터럽트를 처리할까? 음…
참고:
'【Fundamental Tech】 > Linux' 카테고리의 다른 글
Kernel 2.6 Makefile 분석 (0) | 2011.10.14 |
---|---|
ioctl() 디바이스 제어 (0) | 2011.10.14 |
sudo 비밀번호 안물어보게 하기 (0) | 2011.10.08 |
Linux Kernel I/O Scheduling - Priority (0) | 2011.10.08 |
Device Mapper by RedHat (0) | 2011.10.08 |