|
2.2. Драйверы пользовательского уровняНе всегда нужно писать драйвер для устройства, особенно если за устройством следит всего одно приложение. Наиболее полезным примером этому является устройство карты памяти, однако вы можете сделать карту памяти с помощью устройств ввода/вывода (доступ к устройствам осуществляется с помощью функций inpb() и outpb()). Если вы работаете в режиме superuser, вы можете использовать функцию mmap для того, чтобы поместить вашу функцию в какую-то область памяти. С помощью этой процедуры вы сможете весьма просто работать с адресами памяти, как с обычными переменными. Если ваш драйвер использует прерывание, то вам придется работать внутри ядра, так как не существует других путей для прерываний обычных пользовательских процессов. В проекте DOSEMU однако, есть Простейший Генератор прерываний - SIG, но он работает недостаточно быстро, как это можно было ожидать от последней версии DOSEMU. Прерывание - это жестко определенная процедура. Также вы при установке своего аппаратного обеспечения вы определяете линию IRQ для физического сигнала прерываний, возникающего, когда устройство обращается к драйверу. Это происходит, когда устройство пересылает или запрашивает информацию, а также при обнаружении каких-либо исключительных ситуаций, о которых должен знать драйвер. Для обработки прерываний в ядре и для обработки сигналов на пользовательском уровне используется одна и та же структура данных - sigaction. Таким образом, где сигналы аппаратных прерываний доставляются ядру точно так же, как системные сигналы на уровне пользовательского обеспечения. Если ваш драйвер должен обращаться к нескольким процессам сразу или управлять общими ресурсами, тогда вы должны написать драйвер устройства, и драйвер пользовательского уровня вам не подходит. 2.2.1. Пример - 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) ) В начале программа открывает /dev/mem, затем выделят достаточное количество памяти для распределения на страницу, затем меняет карту памяти. GRAPHSIZE - размер памяти vga. GRAPHBASE - адрес начала памяти VGA в /dev/mem. Затем, записывая в адрес возвращаемый mmap(), программа осуществляет запись в память экрана. |
helloworld.ru © 2001-2021 Все права защищены |
|
|