Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Когда драйвер Windows Driver Frameworks (WDF) получает запрос на чтение, запись или ввод-вывод устройства, объект запроса содержит входной буфер, выходной буфер или оба.
Входные буферы содержат сведения, необходимые драйверу. Для запросов на запись эти сведения обычно являются данными, которые драйвер-функция должен отправлять на устройство. Для запросов элементов управления ввода-вывода устройства входной буфер может содержать сведения, указывающие тип операции, которую должен выполнить драйвер.
Выходные буферы получают сведения от драйвера. Для запросов на чтение эти сведения обычно являются данными, которые драйвер функции получает от устройства. Для запросов управления ввода-вывода устройства выходной буфер может получить состояние или другие сведения, указанные кодом элемента управления ввода-вывода запроса.
Метод, используемый драйвером для доступа к буферам данных запроса, зависит от метода драйвера для доступа к буферам данных для устройства. Существует три метода доступа:
- Буферизованный ввод-вывод. Диспетчер ввода-вывода создает промежуточные буферы, которыми он предоставляет общий доступ к драйверу.
- Прямые операции ввода-вывода. Диспетчер ввода-вывода блокирует буферное пространство в физическую память, а затем предоставляет драйверу прямой доступ к буферу.
- ни буферизованного, ни прямого ввода-вывода. Диспетчер ввода-вывода предоставляет драйверу виртуальные адреса буферного пространства запроса. Диспетчер ввода-вывода не проверяет буферное пространство запроса, поэтому драйвер должен убедиться, что буферное пространство доступно и заблокирует буферное пространство в физической памяти.
Драйвер Kernel-Mode Driver Framework (KMDF) может использовать любой из трех методов доступа. Драйвер User-Mode Driver Framework (UMDF) может использовать буферированные или прямые операции ввода-вывода для запросов чтения, записи и IOCTL, а также может преобразовать запросы, указывающие метод METHOD_NEITHER.
указание метода доступа к буферу
Для запросов на чтение и запись все драйверы в стеке драйверов должны использовать один и тот же метод для доступа к буферам устройства, за исключением драйвера верхнего уровня, который может использовать метод "ни один" независимо от того, какой метод используется более низкими драйверами.
Начиная с версии 1.13 драйвер KMDF указывает метод доступа для всех запросов на чтение и запись устройства путем вызова WdfDeviceInitSetIoTypeEx для каждого устройства. Например, если драйвер задает буферный метод ввода-вывода для одного из своих устройств, диспетчер операций ввода-вывода использует буферный метод ввода-вывода при доставке запросов на чтение и запись в драйвер для этого устройства.
Для запросов управления ввода-вывода устройства код элемента управления ввода-вывода (IOCTL) содержит биты, указывающие метод доступа к буферу. В результате драйвер KMDF не должен предпринимать никаких действий для выбора метода буферизации для IOCTLs. Дополнительные сведения об IOCTLs см. в разделе Определение кодов управления вводом-выводом. В отличие от запросов на чтение и запись, не все IOCTL устройства обязаны указывать один и тот же метод доступа.
Драйвер UMDF указывает настройки для метода доступа, который фреймворк использует для запросов на чтение и запись, а также для запросов на управление устройством. Значения, предоставляемые драйвером UMDF, являются только предпочтениями и не гарантируются для использования платформой. Дополнительные сведения см. в статье Управление методами доступа к буферу в драйверах UMDF.
Драйвер UMDF указывает метод доступа для всех запросов на чтение, запись и IOCTL устройства путем вызова WdfDeviceInitSetIoTypeEx для каждого устройства. Например, если драйвер задает буферный метод ввода-вывода для одного из своих устройств, платформа использует буферный метод ввода-вывода при доставке запросов на чтение, запись и передачу запросов IOCTL драйверу для этого устройства.
Обратите внимание на разницу в методе доступа к буферу для ioCTLs между KMDF и UMDF. Драйверы KMDF не указывают метод доступа к буферу для IOCTLs, в то время как драйверы UMDF указывают метод доступа к буферу для IOCTLs.
Если драйвер WDF описывает буфер запроса ввода-вывода с помощью метода ввода-вывода, неправильного для метода ввода-вывода, используемого целевым объектом ввода-вывода, платформа исправляет описание буфера. Например, если драйвер использует MDL для описания буфера, который он передает в WdfIoTargetSendReadSynchronously, и если целевой объект ввода-вывода использует буферный ввод-вывод (который требует, чтобы буферы были заданы с помощью виртуальных адресов вместо MDL), фреймворк преобразует описание буфера из MDL в виртуальный адрес и длину. Тем не менее, это более эффективно, если драйвер задает буферы в правильном формате.
Сведения об объектах памяти фреймворка, списках Lookaside, списках дескрипторов памяти и локальных буферах см. в разделе Использование буферов памяти.
Сведения о удалении буферов памяти см. в разделе жизненный цикл буфера памяти.
доступ к буферам данных для буферизованного ввода-вывода
Если драйвер использует буферизированный ввод-вывод, его поведение изменяется в зависимости от типа запроса данных и того, использует ли он KMDF или UMDF.
Когда драйвер KMDF использует буферизированный ввод-вывод, диспетчер ввода-вывода создает один промежуточный буфер, к которому драйвер может получить доступ для каждого типа запроса. Происходит следующее:
- Отправка запросов. Диспетчер ввода-вывода передает входные данные из входного буфера вызывающего приложения перед вызовом стека драйверов. Затем драйвер KMDF считывает входные данные из промежуточного буфера и записывает его на устройство.
- Читать запросы Драйвер KMDF считывает сведения с устройства и сохраняет его в промежуточном буфере. Затем диспетчер ввода-вывода копирует выходные данные из промежуточного буфера в выходной буфер приложения.
- Запросы на управление операцией ввода-вывода устройства. Драйвер KMDF считывает или записывает данные для этого запроса в промежуточный буфер или из него.
Когда драйвер UMDF использует буферизированный ввод-вывод, процесс узла драйвера создает один или два промежуточных буфера в зависимости от типа запроса. Происходит следующее:
- Отправка запросов. Платформа создает один буфер, передает входные данные из входного буфера вызывающего приложения, а затем вызывает стек драйверов. Драйвер UMDF считывает входные данные из промежуточного буфера и записывает его на устройство.
- Чтение запросов. Драйвер UMDF считывает сведения с устройства и сохраняет его в буфере, созданном платформой. Процесс узла драйвера копирует выходные данные из промежуточного буфера в выходной буфер приложения.
- Запросы на управление операцией ввода-вывода устройства. Платформа создает два буфера, соответствующие входным и выходным буферам IOCTL, к которому драйвер может получить доступ. Платформа копирует входные данные из IOCTL в новый промежуточный буфер и делает его доступным для драйвера. Платформа не копирует содержимое выходного буфера, поэтому драйвер не должен пытаться считывать его (в противном случае это приведет к чтению данных мусора). Все данные, которые драйвер записывает в выходной буфер, копируются обратно в исходный буфер IOCTL и возвращаются в приложение после успешного завершения запроса ввода-вывода. Обратите внимание, что все данные, которые драйвер записывает в входной буфер, удаляются и не возвращаются в вызывающее приложение.
Чтобы получить дескриптор объекта памяти платформы, представляющего буфер, драйверы KMDF и UMDF вызывают WdfRequestRetrieveInputMemory или WdfRequestRetrieveOutputMemoryв зависимости от того, является ли это запрос на чтение или запись. Затем драйвер может получить указатель на буфер, вызвав WdfMemoryGetBuffer. Для чтения и записи буфера драйвер вызывает WdfMemoryCopyFromBuffer или WdfMemoryCopyToBuffer.
Чтобы получить виртуальный адрес и длину буфера, драйвер вызывает WdfRequestRetrieveInputBuffer или WdfRequestRetrieveOutputBuffer.
Чтобы выделить и создать список дескрипторов памяти (MDL) для буфера, драйвер KMDF вызывает WdfRequestRetrieveInputmMdl или WdfRequestRetrieveOutputmMdl.
доступ к буферам данных для прямого ввода-вывода
Если драйвер использует прямой ввод-вывод, диспетчер операций ввода-вывода проверяет доступность буферного пространства, указанного источником запроса ввода-вывода (как правило, приложения пользовательского режима), блокирует буферное пространство в физической памяти, а затем предоставляет драйверу прямой доступ к буферу.
Если драйвер указал предпочтение прямого ввода-вывода и все требования UMDF для прямых операций ввода-вывода были выполнены (см. управление методами доступа к буферу в драйверах UMDF), платформа сопоставляет буфер памяти, который он получает от диспетчера операций ввода-вывода непосредственно в адресное пространство процесса драйвера, и таким образом предоставляет драйверу прямой доступ к буферу.
Чтобы получить дескриптор объекта памяти платформы, представляющего буферное пространство, драйвер вызывает WdfRequestRetrieveInputMemory или WdfRequestRetrieveOutputMemory. Затем драйвер может получить указатель на буфер, вызвав WdfMemoryGetBuffer. Для чтения и записи буфера драйвер вызывает WdfMemoryCopyFromBuffer или WdfMemoryCopyToBuffer.
Чтобы получить виртуальный адрес и длину буферного пространства, драйвер вызывает WdfRequestRetrieveInputBuffer или WdfRequestRetrieveOutputBuffer.
Если драйверы устройства используют прямые операции ввода-вывода, диспетчер операций ввода-вывода описывает буферы с помощью многомерных выражений. Чтобы получить указатель на MDL буфера, драйвер KMDF вызывает WdfRequestRetrieveInputWdmMdl или WdfRequestRetrieveOutputWdmMdl. Драйвер UMDF не может получить доступ к MDLs.
Доступ к данным для операций без буферного и прямого ввода-вывода
Если ваш драйвер использует метод доступа к буферу, известный как метод без буферизованного и прямого ввода-вывода (или, кратко, «ни то, ни другое»), менеджер ввода-вывода просто предоставляет драйверу виртуальные адреса, которые указаны инициатором запроса ввода-вывода для буферного пространства запроса. Диспетчер ввода-вывода не проверяет буферное пространство запроса ввода-вывода, поэтому драйвер должен убедиться, что буферное пространство доступно и заблокирует буферное пространство в физической памяти.
Виртуальные адреса, которые предоставляет диспетчер ввода-вывода, могут быть доступны только в контексте процесса инициатора запроса на ввод-вывод. Только драйвер самого высокого уровня в стеке драйверов гарантированно выполняется в контексте процесса инициатора.
Чтобы получить доступ к буферу запроса ввода-вывода, драйвер высокого уровня должен предоставить функцию обратного вызова EvtIoInCallerContext. Платформа вызывает эту функцию обратного вызова при каждом получении запроса ввода-вывода для драйвера.
Если метод доступа к буферу запроса равен "ни одному", драйвер KMDF должен выполнять следующие действия для каждого буфера:
Для получения виртуального адреса буфера вызовите WdfRequestRetrieveUnsafeUserInputBuffer или WdfRequestRetrieveUnsafeUserOutputBuffer.
Вызовите WdfRequestProbeAndLockUserBufferForRead или WdfRequestProbeAndLockUserBufferForWrite для проверки и блокировки буфера и чтобы получить дескриптор к объекту памяти платформы для буфера.
Сохраните дескрипторы объектов памяти в контекстном пространстве запроса.
Вызов WdfDeviceEnqueueRequestвозвращает запрос во фреймворк.
Платформа впоследствии добавляет запрос к одной из очередей ввода-вывода драйвера. Если драйвер предоставил обработчики запросов , фреймворк в конечном итоге вызовет соответствующий обработчик запросов.
Обработчик запросов может получить дескрипторы объектов памяти из пространства контекста запроса. Драйвер может передать дескриптор в WdfMemoryGetBuffer для получения адреса буфера.
Иногда драйвер самого высокого уровня должен использовать предыдущие шаги для доступа к буферу в пользовательском режиме, даже если драйвер не использует метод доступа "ни один из двух". Например, предположим, что драйвер использует буферный ввод-вывод. Код элемента управления ввода-вывода, использующий буферный метод доступа, может передать структуру, содержащую внедренный указатель на буфер пользовательского режима. В таком случае драйвер должен предоставить функцию обратного вызова EvtIoInCallerContext, которая извлекает указатели из структуры, а затем использует предыдущие шаги 2–4.
UMDF не поддерживает ни буферизированные, ни прямые буферы типов ввода-вывода, поэтому драйвер UMDF никогда не должен обрабатывать этот тип буфера напрямую.
Однако если платформа получает такие буферы для чтения или записи из диспетчера операций ввода-вывода, он делает их доступными для драйвера UMDF как буферизованного ввода-вывода или прямого ввода-вывода в зависимости от метода доступа, выбранного драйвером. Если фреймворк получает IOCTL с указанием метода буферизации «ни один из», он может при необходимости преобразовать метод доступа к буферу запроса IOCTL в ввод-вывод с буферизацией или с прямым доступом в зависимости от наличия директивы INF. См. Управление методами доступа к буферу в драйверах UMDF для получения дополнительной информации.