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


Использование прямого ввода-вывода с 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), чтобы передавать данные с помощью системы на основе пакетов или master DMA на шине.