2 | Содержание
| 4
Управление вводом-выводом: железо с точки зрения приложений.
Но бывают устройства, о которых система ничего не знает. Тут появляются два
варианта работы с ними.
Вариант A. Напрямую из приложений.
Ядро предоставляет API, позволяющие приложениям самостоятельно обрабатывать
железо напрямую. Для общения с железом нужно:
1. иметь возможность доступа к соответствующим портам ввода/вывода;
и/или
2. иметь возможность доступа к пространству PCI;
и/или
3. иметь возможность доступа к нужной области физической памяти;
и/или
4. обрабатывать IRQ от устройства.
1. Приложение может попытаться зарезервировать диапазон портов, нужный для
общения с устройством (сисфункция 46). Ядро хранит
список уже зарезервированных портов (статический массив на 255 входов по
адресу RESERVED_PORTS, каждый вход содержит TID владельца, начало и конец
зарезервированной области) и не даст зарезервировать диапазон,
перекрывающийся с чем-то уже занятым. Если же всё в порядке, то
[kernel.asm, rpal2] ядро разрешает в карте разрешения ввода/вывода
процессора для запрашивающего потока обращения к запрошенным портам (кстати,
при создании потока его карта инициализируется общей разделяемой между всеми
потоками, которая запрещена для записи; при попытке первой записи процессор
бросает #PF, его обработчик отслеживает эту ситуацию, выделяет новую
страницу для карты с разрешённой записью, записывает её в структуру потока и
возвращает управление), а также добавляет диапазон в общий список
зарезервированных. После этого приложение получает возможность из ring-3
обращаться напрямую к нужным портам. При загрузке ядро резервирует для себя
некоторые системные порты. Функция 46 позволяет потоку также освободить
ранее выделенные им же порты.
2. Здесь ядро берёт на себя все операции, а приложениям выделяет сисфункцию
62. Которая в принципе может быть запрещена (функция
21.12), но по умолчанию разрешена.
3. Доступ из приложения к любым конкретным адресам в физической памяти
безусловно запрещен. К "бортовой" памяти устройств (называемой также блоками
ввода-вывода с отображением на память, Memory-Mapped I/O или MMIO)
прикладные программы должны обращаться через API-функции и драйверы
устройств.
Но что делать с нестандартными устройствами и "бездрайверным железом"?
Колибри предоставляет пользовательскому приложению возможность отображения
(page mapping) скрытых от него физических адресов MMIO на видимое ему "своё"
адресное пространство, используя для этого подфункции 11-13 той же функции
62. Разработчик нового драйвера или инженер-электронщик, тестирующий новое
устройство, должен заранее указать его PCI-адрес в системной константе
mmio_pci_addr. По умолчанию эта константа в ядре не определена и
пользовательский доступ к MMIO закрыт.
4. Для этого есть набор из трёх функций: 42, 44, 45. Когда приходит IRQ, поведение
системы зависит от того, какое именно IRQ пришло. - IRQ0, IRQ1, IRQ6, IRQ13,
IRQ14, IRQ15 - специальные номера, их ядро обрабатывает самостоятельно
(обработка IRQ0=таймера и IRQ1=клавиатуры описана в предыдущем посте, IRQ6
- дискета, IRQ14 и IRQ15 - жёсткие диски)
Oстальные IRQ разбиваются на две категории в зависимости от определения
константы USE_COM_IRQ при компиляции ядра: если она ненулевая, то первая
состоит из IRQ3 и IRQ4, иначе первая пуста; вторая состоит из всех
остальных. IRQ из первой группы может перехватить приложение, IRQ из второй
группы может перехватить драйвер (о драйверах - ниже). Перехват приложением
заключается в вызове функции 45 для нужного IRQ и
определения действий при поступлении IRQ функцией 44.
Если IRQ перехвачено, то его обработка заключается в считывании значений из
определённых портов (определённых функцией 44) и складывания их в буфер.
Приложение в любой момент может прочитать этот буфер функцией 42.
Вариант Б. Из соответствующего драйвера.
Подробно про то, что из себя представляет драйвер, как его можно загрузить и
как приложение (и другие драйвера) может с ним общаться, рассказано здесь.
Драйвер выполняется в ring-0 и, как следствие, получает доступ ко всему,
чему можно. В частности, с чтением/записью в порты никаких проблем не
возникает. Кроме того, ядро предоставляет некоторые сервисы драйверам. В их
числе:
- AttachIntHandler (и GetIntHandler) для перехвата IRQ из второй
категории; при приходе такого IRQ ядро просто вызывает функцию драйвера,
адрес которой драйвер указывает в AttachIntHandler;
- ReservePortArea - точный аналог (с точностью до сдвига регистров) функции 46; в принципе всё будет работать и без её вызова,
но желательно всё-таки дать ядру знать об используемых портах;
- PciApi - точный аналог (с точностью до сдвига регистров) функции 62
- Pci{Read/Write}{8/16/32} для чтения/записи PCI-регистров
- GetPgAddr для получения физического адреса по известному виртуальному
- и другие [core/exports.inc]
2 | Содержание
| 4
Pterox' DocPack R6. Last Edition: 29.05.2010. История выпусков