Userspace I/O(UIO)
Userspace I/O(UIO)
UIO(Userspace I/O)는 사용자 공간에서 실행되는 I/O 기술입니다. Linux 시스템에서 일반 장치 드라이버는 커널 공간에서 실행되며 사용자 공간에서 응용 프로그램에 의해 호출될 수 있습니다. 그리고 UIO는 커널 공간에서 장치 드라이버의 작은 부분을 실행하고 사용자 공간에서 드라이버의 대부분의 기능을 구현합니다. 그런 다음 커널 공간 UIO에서 수행할 작업은 두 가지 유형으로 나누어 매우 간단해집니다.
- 장치에 필요한 리소스 할당 및 기록 및 UIO 장치 등록
- 커널 공간에서 구현해야 하는 인터럽트 처리기 구현
Linux 시스템에서 UIO 드라이버의 위치를 이해한 후, UIO에 대한 이해를 심화하기 위해 참조 자료(Linux User Space Device Drivers)를 정리하였습니다.
1. Device Driver Architectures
- Linux 장치 드라이버는 일반적으로 커널 공간에서 실행되는 커널 드라이버로 설계되었습니다.
- 사용자 공간 I/O는 Linux 커널 2.6.24 이후로 지원되는 또 다른 대체 장치 드라이버 아키텍처입니다.
- Linux 커널 커뮤니티의 사람들은 사용자 공간 I /O의 필요성에 항상 동의하지 않을 수 있습니다.
- 산업용 I/O 카드는 오랫동안 사용자 공간 I/O를 활용해 왔습니다.
- 일부 유형의 장치에서는 Linux 커널 드라이버를 만드는 것이 과도 할 수 있습니다.
- FPGA의 Soft IP에는 고유한 요구 사항이 있으며 드라이버로 구현함에 있어 항상 적합한 것은 아닙니다.
2. Legacy User Space Driver Methods (/dev/mem)
- 장치 메모리를 사용자 공간에 매핑하는 /dev/mem이라는 문자 드라이버가 커널에 존재합니다.
- 이 드라이버를 사용하면 사용자 공간 응용 프로그램이 장치 메모리에 액세스할 수 있습니다.
-
이는 큰 보안 허점이기 때문에 커널 구성에서 메모리 액세스를 비 활성화할 수 있습니다(CONFIG_STRICT_DEVMEM).
- 루트 사용자여야 합니다.
- 새 하드웨어의 프로토타이핑 또는 테스트를 위한 훌륭한 도구이지만, 사용자 공간 장치 드라이버에 적합한 프로덕션 솔루션으로 간주되지 않습니다.
- 모든 주소를 사용자 공간에 매핑할 수 있기 때문에 버그가 있는 사용자 공간 드라이버가 커널을 중단시킬 수 있습니다.
3. Introduction to UIO
-
Linux 커널은 UIO라는 사용자 공간 드라이버를 수행하기 위한 프레임워크를 제공합니다.
- 프레임워크는 사용자 공간 드라이버 아래 계층으로 실행되는 문자 모드 커널 드라이버(drivers/uio)입니다.
- UIO는 드라이버 개발 작업의 일부를 오프로드 하는데 도움이 됩니다.
- UIO의 “U”는 Universal이 아닙니다.
- 커널 프레임워크에서 잘 처리되는 장치는 이상적으로는 커널에 있어야 합니다(많은 커널 개발자에게 묻는 경우).
- 네트워킹은 반도체 공급업체가 향상된 성능을 얻기 위해 사용자 공간 I/O를 수행하는 영역 중 하나입니다.
- UIO는 간단한 장치 드라이버를 정말 잘 처리합니다.
- 간단한 드라이버: 커널 프레임워크에 액세스할 필요 없는 장치 액세스 및 인터럽트 처리
4. Kernel Space Driver Characteristics
4.1 Advantages
- 인터럽트 및 하드웨어 리소스에 대한 액세스를 허용하기 위해 최고 권한 모드로 커널 공간에서 실행됩니다.
- 커널 공간 드라이버가 복잡한 장치용으로 설계될 수 있는 커널 서비스가 많이 있습니다.
- 커널은 여러 응용 프로그램이 커널 공간 드라이버에 동시에 액세스할 수 있도록 사용자 공간에 API를 제공합니다.
- 더 크고 확장 가능한 소프트웨어 시스템을 설계할 수 있습니다.
- 많은 드라이버가 커널 공간인 경향이 있습니다.
- 오픈 소스 커뮤니티에서 질문하기가 더 유리합니다.
- 드라이버를 오픈 소스 커뮤니티로 쉽게 푸시할 수 있습니다.
4.2 Disadvantages
- 드라이버 액세스를 위한 시스템 호출 오버헤드
- 사용자 공간에서 커널 공간으로(또는 그 반대로) 전환이 필요합니다.
- 실시간 애플리케이션에 영향을 미치는 오버헤드가 비 결정적입니다.
- 학습의 어려움
- 커널 API는 응용 프로그램 수준 API와 달라 생산성이 높아지는데 시간이 걸립니다.
- 버그는 커널 중단을 일으켜 치명적입니다.
- 디버깅의 어려움
- 커널 코드는 고도로 최적화되어 있으며 다양한 디버그 도구가 있습니다.
- 빈번한 커널 API 변경
- 어떤 커널 버전용으로 빌드된 커널 드라이버가 다른 버전용으로 빌드되지 않을 수 있습니다.
5. User Space Device Driver Characteristics
5.1 Advantages
- 디버그 도구를 더 쉽게 사용할 수 있고 일반 응용 프로그램 개발과 같이 디버깅이 덜 어렵습니다.
- 부동 소수점과 같은 사용자 공간 서비스를 사용할 수 있습니다.
- 시스템 호출이 필요하지 않으므로 장치 액세스가 매우 효율적입니다.
- Linux의 애플리케이션 API는 매우 안정적입니다.
- 드라이버는 “C” 뿐만 아니라 모든 언어로 작성할 수 있습니다.
5.2 Disadvantages
- 커널 프레임워크 및 서비스에 대한 액세스 권한이 없습니다.
- 연속 메모리 할당, 직접 캐시 제어 및 DMA를 사용할 수 없습니다.
- 보완을 위해 커널 코드를 복제하거나 커널 드라이버를 사용해야 할 수 있음
- 인터럽트 처리는 사용자 공간에서 수행할 수 없습니다.
- 약간의 지연을 야기하는 사용자 공간으로 커널 드라이버에 의해 처리되어야 합니다.
- 응용 프로그램이 장치 드라이버에 액세스할 수 있도록 미리 정의된 API가 없습니다.
- 여러 애플리케이션이 드라이버에 액세스하는 경우 동시성도 고려해야 합니다.
6. UIO Framework Features
- drivers/uio에는 Linux에서 제공하는 두 가지 별개의 UIO 장치 드라이버가 있습니다.
- UIO 드라이버(drivers/uio.c)
- 고급 사용자의 경우 UIO 프레임워크를 설정하려면 최소 커널 공간 드라이버가 필요합니다.
- 커널 공간 드라이버가 맞춤화될 수 있기 때문에 가장 보편적이며 모든 상황을 처리할 가능성이 높습니다.
- 대부분의 작업은 사용자 공간 드라이버에서 수행할 수 있습니다.
- UIO 플랫폼 장치 드라이버(drivers/uio_pdev_irqgen.c)
- 이 드라이버는 커널 공간 드라이버가 필요하지 않도록 UIO 드라이버를 보강합니다.
- uio에 필요한 커널 공간 드라이버를 제공합니다.
- 장치 트리와 함께 작동하여 사용하기 쉽습니다.
- 장치의 장치 트리 노드는 호환되는 “generic uio”를 사용해야 합니다.
- 커널 공간 코드가 필요하지 않기 때문에 최상의 출발점
- 이 드라이버는 커널 공간 드라이버가 필요하지 않도록 UIO 드라이버를 보강합니다.
7. UIO Driver Kernel Configuration
- UIO 드라이버는 Linux 커널에서 구성해야 합니다.
CONFIG_UIO=y
CONFIG_UIO_PDRV_GENIRQ=y
8. UIO Platform Device Driver Details
- 사용자는 사용자 공간 드라이버만 제공합니다.
- UIO 플랫폼 장치 드라이버는 장치 트리에서 구성하고 UIO 장치를 등록합니다.
- 사용자 공간 드라이버는 하드웨어에 직접 액세스할 수 있습니다.
- 사용자 공간 드라이버는 UIO 장치 파일 디스크립터를 읽어 인터럽트를 알립니다.
9. Kernel UIO API - Sys Filesystem
- 커널의 UIO 드라이버는 UIO 장치를 설명하는 sys 파일 시스템에 파일 속성을 생성합니다.
- /sys/class/uio는 모든 파일 속성의 루트 디렉토리입니다.
- 각 UIO 장치에 대해 /sys/class/uio 아래에 별도의 번호가 지정된 디렉토리 구조가 생성됩니다.
- 첫 번째 UIO 장치: /sys/class/uio/uio0
- /sys/class/uio/uio0/name에는 uio_info 구조의 이름과 관련된 장치의 이름이 포함됩니다.
- /sys/class/uio/uio0/maps는 장치에 대한 모든 메모리 범위가 있는 디렉토리입니다.
- 번호가 매겨진 각 맵 디렉토리에는 주소, 이름, 오프셋 및 크기를 포함하여 장치 메모리를 설명하는 속성이 있습니다.
- /sys/class/uio/uio0/maps/map0
10. User Space Driver Flow
-
커널 공간 UIO 장치 드라이버는 사용자 공간 드라이버가 시작되기 전에 로드되어야 합니다(모듈을 사용하는 경우).
- 사용자 공간 응용 프로그램이 시작되고 UIO 장치 파일이 열립니다(/dev/uioX 여기서 X는 0, 1, 2 …)
- 사용자 공간에서 UIO 장치는 다른 장치와 마찬가지로 파일 시스템의 장치 노드입니다.
-
장치 메모리 주소 정보는 관련 sysfs 디렉토리에서 찾을 수 있으며 크기만 필요합니다.
-
장치 메모리는 UIO 드라이버의 mmap() 함수를 호출하여 프로세스 주소 공간에 매핑됩니다.
-
애플리케이션이 장치 하드웨어에 액세스하여 장치를 제어합니다.
-
munmap()을 호출하여 장치 메모리가 매핑 해제됩니다.
- UIO 장치 파일이 닫힙니다.
11. User Space Driver Example
1 #define UIO_SIZE "/sys/class/uio/uio0/maps/map0/size"
2
3 int main(int argc, char **argv)
4 {
5 int uio_fd;
6 unsigned int uio_size;
7 FILE *size_fp;
8 void *base_address;
9
10 /*
11 * 1. Open the UIO device so that it is ready to use
12 */
13 uio_fd = open("/dev/uio0", O_RDWR);
14
15 /*
16 * 2. Get the size of the memory region from the size sysfs file
17 * attribute
18 */
19 size_fp = fopen(UIO_SIZE, O_RDONLY);
20 fscanf(size_fp, "0x%08X", &uio_size);
21
22 /*
23 * 3. Map the device registers into the process address space so they
24 * are directly accessible
25 */
26 base_address = mmap(NULL, uio_size,
27 PROT_READ|PROT_WRITE,
28 MAP_SHARED, uio_fd, 0);
29
30 // Access to the hardware can now occur ...
31
32 /*
33 * 4. Unmap the device registers to finish
34 */
35 munmap(base_address, uio_size);
36
37 ...
38 }
12. Mapping Device Memory Details
- Linux의 문자 장치 드라이버 프레임워크는 장치 메모리를 사용자 공간 프로세스 주소 공간에 매핑하는 기능을 제공합니다.
- 문자 드라이버는 사용자 공간 응용 프로그램이 호출할 수 있는 mmap() 함수를 구현할 수 있습니다.
- mmap() 함수는 호출 프로세스의 가상 주소 공간에 새 매핑을 만듭니다.
- 지정된 물리적 주소에 해당하는 가상 주소가 반환됩니다.
- 파일 내용이 메모리 읽기 및 쓰기에 의해 액세스되도록 파일을 메모리 공간에 매핑하는 데 사용할 수도 있습니다.
- 사용자 공간 프로그램이 가상 주소 범위에서 읽거나 쓸 때마다 장치에 액세스하고 있습니다.
- 시스템 호출이 필요하지 않으므로 향상된 성능을 제공합니다.
13. Mapping Device Memory Flow
14. User Space Application Interrupt Processing
- 인터럽트는 사용자 공간에서 직접 처리되지 않습니다.
- 인터럽트는 UIO 커널 드라이버에 의해 처리될 수 있으며, UIO 장치 파일 디스크립터를 통해 사용자 공간으로 인터럽트를 릴레이 합니다.
- 인터럽트가 발생할 때 알림을 받으려는 사용자 공간 드라이버는 UIO 장치 파일 설명자에서 select() 또는 read()를 호출합니다.
- 읽기는 blocking 또는 non-blocking 모드로 수행할 수 있습니다.
- read()는 이벤트(인터럽트) 수를 반환합니다.
- 스레드를 사용하여 인터럽트를 처리할 수 있습니다.
- 또는 사용자 제공 커널 드라이버가 인터럽트를 처리한 다음 공유 메모리와 같은 다른 메커니즘을 통해 사용자 공간 드라이버에 데이터를 전달할 수 있습니다.
- 인터럽트가 매우 빠른 장치에 필요할 수 있습니다.
15. User Space Application Interrupt Processing Example
1 int pending = 0;
2 int reenable = 1;
3
4 /*
5 * 1. The UIO device is opened as previously described
6 */
7 int uio_fd = open("/dev/uio0", O_RDWR);
8
9 /*
10 * 2. Read the UIO device file descriptor to wait for an interrupt,
11 * the read blocks by default, a non blocking read can also be used
12 *
13 * NOTE: The pending variable contains the number of interrupts that have
14 * occurred if multiple
15 */
16 read(uio_fd, (void *)&pending, sizeof(int));
17
18
19 //
20 // add device specific processing like acking the interrupt in the device here
21 //
22
23
24 /*
25 * 3. Re-enable the interrupt at the interrupt controller level
26 */
27 write(uio_fd, (void *)&reenable, sizeof(int));
16. UIO Driver Details
- 사용자는 커널 드라이버와 사용자 공간 드라이버를 제공합니다.
- 커널 공간 드라이버는 장치 트리에서 구성하고 UIO 장치를 등록하는 플랫폼 드라이버입니다.
- 커널 공간 드라이버는 커널 공간에서 인터럽트 핸들러를 제공할 수도 있습니다.
- 사용자 공간 드라이버는 하드웨어에 직접 액세스할 수 있습니다.
17. Kernel UIO API - Basics
- API는 작고 사용하기 쉽습니다 .
struct uio_info
-- name : device name
-- version : device driver version
-- irq : interrupt number
-- irq_flags : flags for request_irq()
-- handler : driver irq handler (optional)
-- mem[] : memory regions that can be mapped to user space
o addr : memory address
o memtype : type of memory region (physical, logical, virtual)
18. Kernel UIO API - Registration
-
uio_register_device() 함수는 드라이버를 UIO 프레임워크에 연결합니다.
- 입력으로 struct uio_info가 필요합니다.
- 일반적으로 플랫폼 장치 드라이버의 probe() 함수에서 호출됩니다.
- 장치 파일 /dev/uio#(#부터 시작) 및 모든 관련 sysfs 파일 속성 생성
-
uio_unregister_device() 함수는 UIO 프레임워크에서 드라이버 연결을 끊습니다.
- 일반적으로 플랫폼 장치 드라이버의 정리 기능에서 호출됩니다.
- 장치 파일 삭제 /dev/uio#
19. Kernel Space Driver Example
1 probe()
2 {
3 /*
4 * 1. Platform device driver initialization in the driver probe() function
5 */
6 dev = devm_kzalloc(&pdev->dev, (sizeof(struct uio_timer_dev)), GFP_KERNEL);
7 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8 dev->regs = devm_ioremap_resource(&pdev->dev, res);
9 irq = platform_get_irq(pdev, 0);
10
11 /*
12 * 2. Add basic UIO structure initialization
13 */
14 dev->uio_info.name = "uio_timer";
15 dev->uio_info.version = 1;
16 dev->uio_info.priv = dev;
17
18 /*
19 * 3. Add the memory region initialization for the UIO
20 */
21 dev->uio_info.mem[0].name = "registers";
22 dev->uio_info.mem[0].addr = res->start;
23 dev->uio_info.mem[0].size = resource_size(res);
24 dev->uio_info.mem[0].memtype = UIO_MEM_PHYS;
25
26 /*
27 * 4. Add the interrupt initialization for the UIO
28 */
29 dev->uio_info.irq = irq;
30 dev->uio_info.handler = uio_irq_handler;
31
32 /*
33 * 5. Register the UIO device with the kernel framework
34 */
35 uio_register_device(&pdev->dev, &dev->info);
36 }
20. UIO Framework Details
- UIO 드라이버
- 장치의 장치 트리 노드는 호환 속성에서 원하는 모든 것을 사용할 수 있습니다. 플랫폼 장치 드라이버와 마찬가지로 커널 공간 드라이버에서 사용되는 것과 일치하기만 하면 되기 때문입니다.
- UIO 플랫폼 장치 드라이버
- 장치의 장치 트리 노드는 호환 속성에서 “generic - uio”를 사용해야 합니다.