Пример - vgalib.
Хорошим примером драйвера пользовательского уровня является библиотека vgalib. Стандартные функции read() и write() не подходят для написания действительно быстрого графического драйвера, и поэтому существует библиотека функций, которая концептуально работает как драйвер устройства, но на пользовательском уровне. Все функции, которые используют ее, должны запускать setuid, так как она использует системную функцию ioperm(). Функции, которые не запускают setuid, обладают возможностью записи в /DEV/MEM, если у вас есть группы mem или kmem, которые позволяют это, но только корневые процессы могут запускать ioperm().
Есть несколько портов ввода/вывода, относящихся к графике VGA. Vgalib дает им символические имена с помощью #define, и далее используют ioperm() для разрешения функции правильного прочтения и записи в эти порты.
if (ioperm(CRT_IC, 1, 1)) { printf("VGAlib: can't get I/O permission \n"); exit(-1); } ioperm(CRT_IM, 1, 1); ioperm(ATT_IW, 1, 1); [--]
Это требует лишь однократной проверки, так как единственной причиной нефункционирования ioperm() может быть обращение к ней не в статусе superuser или во время смены статуса.
/\
\/ После вызова этой функции разрешается использование inb и outb инструкций, однако лишь с определенными портами. Эти инструкции могут быть доступны без использования прямого ассемблерного кода , но работают они лишь в случае компиляции с параметром optimization on и с ключом -0?. Для более подробных сведений читай .
После обращения в порты ввода вывода vgalib засылает информацию в область ядра следующим образом :
/* open /dev/mem */ if ((mem_fd = open("/dev/mem", 0_RDWR) ) < 0) { prntf( "VGAlib: can' t open /dev/mem \n"); exit (-1); }
/* mmap graphics memory */ if ((graph_mem = malloc(GRAPH*SIZE + (PAGE-SIZE-1))) == NULL) { printf( " VGAlib: allocation error \n "); exit (-1); } if ((unsigned long)graph_mem % PAGE_SIZE) graph_mem += PAGE_SIZE - ((unsigned long)graph_mem % PAGE_SIZE); graph_mem = (unsigned char *)mmap( (caddr_t)graph_mem, GRAPH_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, GRAPH_BASE ); if ((long)graph_mem < 0) { printf(" VGAlib: mmap error \n"); exit (-1); }
В начале программа открывает /dev/mem, затем выделят достаточное количество памяти для распределения на страницу, затем меняет карту памяти.
GRAPHSIZE - размер памяти vga. GRAPHBASE - адрес начала памяти VGA в /dev/mem.
Затем, записывая в адрес возвращаемый mmap(), программа осуществляет запись в память экрана.