Поделиться через


Использование прямого ввода-вывода с PIO

Драйвер, использующий программируемый ввод-вывод (PIO), а не DMA, должен дважды сопоставлять буферы пространства пользователя с диапазоном адресов системного пространства. На следующем рисунке показано, как менеджер ввода-вывода настраивает запрос IRP_MJ_READ для операции передачи PIO, которая использует прямой ввод-вывод.

схема, иллюстрирующая прямой ввод-вывод для устройств, использующих pio.

На рисунке показано, как устройство, использующее ПИО, обрабатывает ту же задачу.

  1. Определённый диапазон виртуальных адресов пользовательского пространства представляет буфер текущего потока, и содержимое этого буфера может фактически храниться на некотором количестве физически несмежных страниц. Если длина буфера ненулевой, диспетчер ввода-вывода создает MDL для описания этого буфера.

  2. Диспетчер операций ввода-вывода обрабатывает текущий запрос потока на чтение, при котором поток передает диапазон виртуальных адресов пользовательского пространства, которые представляют собой буфер.

  3. Диспетчер ввода-вывода или FSD проверяет доступность предоставленного пользователем буфера. Если диспетчер ввода-вывода создал MDL, он вызывает MmProbeAndLockPages с MDL, который задает диапазон виртуальных адресов для буфера пользователя. MmProbeAndLockPages также заполняет соответствующий диапазон физических адресов в MDL.

  4. Диспетчер ввода-вывода предоставляет указатель на MDL (MdlAddress) в IRP, запрашивающем операцию передачи. Пока диспетчер ввода-вывода или файловая система не вызывает MmUnlockPages после завершения IRP, физические страницы, описанные в MDL, остаются заблокированными и назначены буферу. Однако виртуальные адреса в таком MDL могут стать невидимыми (и недопустимыми), даже до отправки IRP драйверу устройства или любому промежуточному драйверу, который может быть расположен выше драйвера устройства.

  5. Если драйверу требуются системные (виртуальные) адреса, драйвер вызывает MmGetSystemAddressForMdlSafe с указателем MdlAddress IRP, чтобы вдвойне сопоставить виртуальные адреса пространства пользователя в MDL с диапазоном адресов системного пространства. На приведенном выше рисунке AliasBuff представляет MDL, описывающий двузначные адреса.

  6. Драйвер использует диапазон виртуальных адресов в системном пространстве от дважды отображаемого MDL (AliasBuff) для чтения данных в память.

Когда драйвер завершает IRP, вызывая IoCompleteRequest, диспетчер ввода-вывода или файловая система освобождает двойной сопоставленный системный диапазон MDL, если драйвер вызвал MmGetSystemAddressForMdlSafe. Диспетчер ввода-вывода или файловая система разблокирует страницы, описанные в MDL, и удаляет MDL и IRP от имени драйвера. Для повышения производительности драйверы должны избегать удвоенной сопоставления физических адресов MDL с системным пространством, как описано на шаге 3, если они не должны использовать виртуальные адреса. Использование записей таблицы системной страницы без необходимости может снизить производительность драйвера и масштабируемость. Кроме того, система может завершиться сбоем, если у неё заканчиваются записи таблицы страниц, так как большинство старых драйверов не могут справиться с подобной ситуацией.

Буферы текущего потока пользователя и сам поток гарантированно будут находиться в физической памяти только в то время как этот поток является текущим. Для потока, показанного на предыдущем рисунке, содержимое буфера пользователя можно вывести в дополнительное хранилище во время выполнения потоков другого процесса. При запуске потока другого процесса системная физическая память буфера запрашивающего потока может быть перезаписана, если диспетчер памяти не заблокировал и сохранил соответствующие физические страницы, содержащие буфер исходного потока.

Однако виртуальные адреса буфера исходного потока не остаются видимыми, когда актуален другой поток, даже если диспетчер памяти сохраняет физические страницы буфера. Следовательно, драйверы не могут использовать виртуальный адрес, возвращаемый MmGetMdlVirtualAddress для доступа к памяти. Вызывающие эту подпрограмму должны передавать её результаты в MapTransfer (вместе с указателем MdlAddress IRP) для передачи данных с использованием системы, основанной на пакетах, или прямого доступа к памяти с управлением шиной (DMA).