3

У меня есть 2 вопроса, связанных с шиной PCI:

Как драйверы устройств получают доступ к устройствам на шине PCI? Достаточно ли записи в область памяти, выделенную для устройства (mov memory_space_allocated_for_dev, something , если устройство отображено в памяти, или out io_space_allocated for_dev, something если это не так) (аппаратно переведет эту попытку для доступа к памяти в серию команд PCI на Шина PCI и т.д.?).

Верно ли, что после настройки всех устройств на всех шинах PCI (т. Е. Выделения пространства памяти, перечисления шин и т.д.) Драйверам устройств не нужно знать, существует ли шина PCI или декодирование памяти выполняется простым декодером (как на старых компьютерах).) (т.е. они просто пишут и читают из некоторых областей памяти для доступа к устройству)?

2 ответа2

6

Устройства PCI(e) с отображенной памятью будут иметь BAR (регистры базовых адресов), которые позволяют хосту знать, сколько памяти должно быть выделено для устройства. BIOS (и ОС позже) будет выделять запрошенное пространство памяти для целевого устройства - не то, что это адрес памяти, физические биты не выделяются. Кроме того, это, как правило, адрес физической памяти, а не адрес виртуальной памяти. Ядро Linux будет разрешать доступ к этим устройствам с помощью таких функций, как mmap (), которые позволяют отображать физическую память на адреса виртуальной памяти.

Например, скажем, у вас есть устройство PCIe, которое контролирует 8 светодиодов. Как создатель устройства, я могу запросить очень маленький бар в 1K адресного пространства. BIOS может дать мне физический адрес в 32-битной системе от 0xE000_0000 до 0xE000_0400 (примечание: теперь вы должны увидеть, почему 32-битные системы и графические процессоры с большой VRAM не работали вместе).

Теперь, если я запишу 0xF0 в ячейку памяти 0xE000_0000 с однобайтовой записью, это включит светодиоды с 7 по 4 и оставит 3 по 0 выключенным. Вот и все - это простой ввод-вывод с отображением в память. Добавляя к уровням абстракции, в Linux, вы будете использовать ее превосходную подсистему PCI и написать драйвер, который загружается для данной строки Vendor ID + Device ID. Затем вы могли бы написать приложение пользовательского пространства, которое обращается к этому драйверу ядра, где вызов mmap() может отобразить память в пользовательское пространство, позволяя вашему приложению пользовательского пространства выполнять чтение / запись байтов по некоторому адресу виртуальной памяти, который будет преобразован и завершится в физическом пространстве памяти, где он принадлежит.

x86, конечно, имеет пространство ввода / вывода, и поведение довольно похоже, за исключением низкого уровня в ядре, инструкции outb / outw / outl (и их входные двоюродные братья) будут использоваться для записи / чтения из пространства ввода / вывода, против памяти чтения / записи инструкции. Опять же, пользовательское приложение должно обмениваться данными через ioctls () и сопоставленный сегмент памяти, поскольку ядро отвечает за безопасность / доступ к памяти, подобной этой.

Что касается вашего второго вопроса, вроде смешанного с вышеупомянутым, но современный драйвер PCIe для Linux будет опираться на подсистему PCI для многих низкоуровневых служебных вещей. Вы в основном определяете, за какие идентификаторы поставщиков / устройств вы несете ответственность, а затем пишете функцию .probe(), которая захватывает ваши IRQ и выполняет настройку устройства - ваша память передается вам.

0

Прошло какое-то время, но, если я правильно помню, ваш драйвер ядра настроит устройство в /dev, которое сопоставляется с адресами памяти, выделенными для устройств PCI либо BIOS, либо ядром. Программы пользовательского пространства с соответствующими разрешениями затем будут открывать, читать / писать / искать и закрывать этот /dev / файл для взаимодействия с устройством PCI. См. Главу 12 «Драйверы устройств Linux»: https://lwn.net/Kernel/LDD3/.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .