Устройства 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 и выполняет настройку устройства - ваша память передается вам.