Доступ к буферам данных в драйверах UMDF 1.x

Предупреждение

UMDF 2 является последней версией UMDF и заменяет UMDF 1. Все новые драйверы UMDF должны быть написаны с помощью UMDF 2. В UMDF 1 новые функции не добавляются, а поддержка UMDF 1 в более новых версиях Windows 10 ограничена. Универсальные драйверы Windows должны использовать UMDF 2.

Дополнительные сведения см. в разделе начало работы с помощью UMDF.

Сведения о доступе к буферам данных для UMDF 2 см. в статье Доступ к буферам данных в драйверах WDF.

Когда драйвер получает запрос на чтение, запись или управление вводом-выводом устройства, объект запроса содержит либо входной буфер, либо буфер вывода, либо и то, и другое. (Несколько запросов управления вводом-выводом устройства предоставляют два входных, двух выходных данных или два буфера ввода-вывода.)

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

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

Метод, используемый драйвером для доступа к буферам данных запроса, может зависеть от метода драйвера для доступа к буферам данных для устройства. UMDF поддерживает следующие методы доступа к буферу:

Третий метод доступа, который не называется ни буферным, ни прямым вводом-выводом, недоступен для драйверов на основе UMDF, но UMDF может преобразовать некоторые запросы ввода-вывода из метода "ни один" в метод, поддерживаемый версией UMDF.

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

В следующих разделах этой статьи объясняется следующее:

Указание предпочтительного метода доступа к буферу

UMDF версии 1.9 и более поздних поддерживают методы доступа к буферизованному и прямому вводу-выводу. Драйверы могут указать метод доступа, который вы предпочитаете использовать для всех запросов на управление чтением, записью и вводом-выводом устройства, вызывая IWDFDeviceInitialize2::SetIoTypePreference перед вызовом IWDFDriver::CreateDevice для создания объекта устройства. Например, если драйвер задает предпочтение только для буферизованного метода ввода-вывода для запросов на чтение и запись для одного из своих устройств, хост-процесс драйвера UMDF использует метод буферизованного ввода-вывода при доставке запросов на чтение и запись в драйвер для этого устройства. Если драйвер задает предпочтение для прямого ввода-вывода, UMDF может (но не может) использовать прямой ввод-вывод. Дополнительные сведения о том, когда UMDF использует прямой ввод-вывод, см. в разделе Как UMDF выбирает метод доступа к буферу для запроса ввода-вывода.

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

Для запросов управления вводом-выводом устройства код управления вводом-выводом (IOCTL) указывает метод доступа к буферу. (Дополнительные сведения о том, как IOCTL определяют метод доступа, см. в разделе Определение кодов управления вводом-выводом.) Однако метод доступа, используемый UMDF, может не соответствовать методу доступа, указанному в IOCTL.

  • В версиях UMDF до версии 1.9 UMDF всегда использует метод буферизованного доступа для всех запросов управления вводом-выводом.

  • В UMDF версии 1.9 и более поздних используется метод доступа к буферизованному вводу-выводу, если IOCTL указывает буферизованное ввод-вывод. Если IOCTL задает прямой ввод-вывод, а драйвер вызывает IWDFDeviceInitialize2::SetIoTypePreference , чтобы указать, что для прямого ввода-вывода задано предпочтение, UMDF может использовать прямой ввод-вывод или буферизованный ввод-вывод, как описано в статье Выбор метода доступа к буферу для запроса ввода-вывода. Сведения о том, как UMDF поддерживает ioCTL, определяющие метод "ни буферизованного ввода-вывода, ни прямого ввода-вывода", см. в статье Использование не только буферизованного ввода-вывода, ни прямого ввода-вывода в драйверах UMDF.

Указание режима извлечения буфера

В версиях UMDF, предшествующих версии 1.9, UMDF всегда делает буферы запроса ввода-вывода доступными для драйвера (путем копирования буферов в процесс узла драйвера UMDF), как только UMDF получит запрос ввода-вывода. Этот режим извлечения буфера называется немедленным получением. В случае сбоя UMDF завершает запрос ввода-вывода со значением состояния сбоя и не доставляет запрос ввода-вывода драйверу.

UMDF версии 1.9 и более поздних поддерживают режимы немедленного и отложенного извлечения . Режим отложенного извлечения откладывает копирование буфера запроса ввода-вывода в процесс узла драйвера до тех пор, пока драйвер не попытается получить доступ к буферу. В случае сбоя функции доступа к буферу возвращают драйверу значение состояния ошибки.

Драйвер может указать режим извлечения буфера при вызове IWDFDeviceInitialize2::SetIoTypePreference для каждого устройства. Используйте следующие правила:

  • Если драйвер указывает прямой метод доступа ввода-вывода, он также должен указать режим отложенного извлечения. Прямой ввод-вывод работает только с отложенным извлечением.

  • Все драйверы, которые записываются для работы с UMDF версии 1.9 и более поздних, должны указывать режим отложенного извлечения для всех запросов ввода-вывода, независимо от того, выбирает ли драйвер буферный или прямой метод доступа ввода-вывода. Отложенное извлечение обеспечивает лучшую производительность, так как не обращается к буферам, которые не использует драйвер.

Если драйвер не задает режим извлечения буфера, UMDF использует немедленное извлечение.

Все драйверы на основе UMDF в стеке драйверов должны использовать один и тот же режим извлечения. Если некоторые драйверы указывают немедленное получение, а некоторые — отложенное извлечение, UMDF использует немедленное извлечение.

Как UMDF выбирает метод доступа к буферу для запроса ввода-вывода

Метод доступа, который указывает драйвер при вызове IWDFDeviceInitialize2::SetIoTypePreference, может не быть методом, используемым UMDF. UMDF использует следующие правила, чтобы определить, какой метод доступа использовать:

  • Все драйверы на основе UMDF в стеке драйверов должны использовать один и тот же метод для доступа к буферам устройства. Если UMDF определяет, что некоторые драйверы предпочитают буферизацию ввода-вывода или прямой ввод-вывод для устройства, а другие драйверы предпочитают только буферизированные операции ввода-вывода для устройства, UMDF использует буферизованное ввод-вывод для всех драйверов. Если один или несколько драйверов стека предпочитают только буферизацию операций ввода-вывода, а другие предпочитают только прямой ввод-вывод, UMDF записывает событие в журнал системных событий и не запускает стек драйверов.

    Драйвер может вызвать IWDFDevice2::GetDeviceStackIoTypePreference , чтобы определить методы доступа к буферу, назначенные UMDF запросам на чтение и запись устройства и запросам управления вводом-выводом.

  • В некоторых случаях драйвер задает предпочтение для прямого ввода-вывода при вызове IWDFDeviceInitialize2::SetIoTypePreference, но для наилучшей производительности UMDF использует буферизированный ввод-вывод для одного или нескольких запросов устройства. Например, UMDF использует буферный ввод-вывод для небольших буферов, если может копировать данные в буфер драйвера быстрее, чем сопоставлять буферы для прямого доступа.

    При необходимости можно задать REG_DWORD типизированное значение реестра DirectTransferThreshold , которое платформа использует для определения наименьшего размера буфера, для которого платформа будет использовать прямой ввод-вывод. Как правило, не требуется предоставлять это значение реестра, так как платформа использует значение, обеспечивающее наилучшую производительность. Значение DirectTransferThreshold находится в подразделе Device Parameters\WUDF устройства, который находится под аппаратным ключом устройства.

    Платформа использует следующие правила для определения порогового значения на основе значения, указанного в DirectTransferThreshold. В предоставленных числах предполагается , что PAGE_SIZE 4096, что допустимо, за исключением систем на основе Itanium.

    • Если задать для DirectTransferThreshold любое значение, меньшее или равное 8192 (или 2 * PAGE_SIZE), платформа устанавливает пороговое значение 8192. Платформа использует буферизированные операции ввода-вывода для буферов размером менее 8192 байт, а прямые операции ввода-вывода — для буферов размером или больше 8192 байт.

    • Если задать для DirectTransferThreshold любое значение больше 8192, платформа округляется до следующего точного кратного PAGE_SIZE. Опять же, платформа использует буферный ввод-вывод для буферов меньше порогового значения и прямой ввод-вывод для буферов, равных или превышающих пороговое значение.

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

  • Для запросов управления вводом-выводом устройства UMDF использует прямой ввод-вывод только в том случае, если код элемента управления ввода-вывода (IOCTL) указывает прямой ввод-вывод, и только если все драйверы на основе UMDF устройства вызвали IWDFDeviceInitialize2::SetIoTypePreference для указания метода прямого доступа.

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

Как драйвер может получить метод доступа для запроса ввода-вывода

В некоторых случаях можно повысить производительность устройства и драйвера, если известный метод доступа. В таких случаях драйвер может вызвать IWDFIoRequest2::GetEffectiveIoType , чтобы получить метод доступа к буферу запроса ввода-вывода.

Например, рассмотрим устройство с высокой пропускной способностью, которое обычно использует прямой ввод-вывод. Так как он использует прямой ввод-вывод, драйвер должен скопировать параметры, заданные приложением, в локальную память драйвера перед проверкой параметров, чтобы убедиться, что приложение не изменяет параметры после проверки.

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

Использование буферизованного ввода-вывода в драйверах UMDF

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

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

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

Однако для запросов управления вводом-выводом устройства процесс узла драйвера создает два отдельных буфера, к которым драйвер может получить доступ. Обратите внимание, что это отличается от поведения драйверов WDM и KMDF, для которых запросы на чтение, запись и управление вводом-выводом устройства, отправленные с использованием буферизованного ввода-вывода, приводят к тому, что драйвер получает доступ к одному промежуточному буферу. В этом случае выходной буфер изначально ничего не содержит, и драйвер не должен считывать из него. Кроме того, все данные, записываемые драйвером во входной буфер, удаляются и не возвращаются в вызывающее приложение.

Рекомендации по выбору буферизованного ввода-вывода см. в разделе WDF_DEVICE_IO_TYPE.

UMDF версии 1.9 и более поздних версий может поддерживать немедленное или отложенное получение буферов запросов. Дополнительные сведения см. в разделе WDF_DEVICE_IO_BUFFER_RETRIEVAL.

Драйвер, использующий режим немедленного получения буфера, должен использовать IWDFIoRequest::GetInputMemory и IWDFIoRequest::GetOutputMemory для доступа к буферам.

Драйвер, использующий режим отложенного извлечения буфера, может получить доступ к буферам, вызвав IWDFIoRequest2::RetrieveInputBuffer, IWDFIoRequest2::RetrieveInputMemory, IWDFIoRequest2::RetrieveOutputBuffer или IWDFIoRequest2::RetrieveOutputMemory.

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

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

Рекомендации по выбору прямого ввода-вывода см. в разделе WDF_DEVICE_IO_TYPE.

Драйвер может получить доступ к буферам, вызвав IWDFIoRequest2::RetrieveInputBuffer, IWDFIoRequest2::RetrieveInputMemory, IWDFIoRequest2::RetrieveOutputBuffer или IWDFIoRequest2::RetrieveOutputMemory.

Использование в драйверах UMDF ни буферизованного ввода-вывода, ни прямого ввода-вывода

Метод доступа к буферу, который называется методом не буферизованного ввода-вывода или прямым методом ввода-вывода (или, короче говоря, методом "ни в коем случае"), позволяет драйверам напрямую обращаться к указателям буфера запросов приложения. Драйверы на основе UMDF не могут использовать этот метод доступа.

Однако определения некоторых кодов управления вводом-выводом устройства (IOCTL) указывают, что запросы используют метод "ни то, ни". При необходимости UMDF может преобразовать метод доступа к буферу для таких запросов управления вводом-выводом устройства в буферный или прямой ввод-вывод. Выполните указанные ниже действия.

  1. Включите директиву UmdfMethodNeitherAction в раздел INF DDInstall INF-файла драйвера. Можно задать значение директивы, чтобы указать, что UMDF должна передавать запросы на управление вводом-выводом устройства, использующие метод доступа "ни", в драйвер. (В противном случае UMDF завершает эти запросы ввода-вывода со значением состояния ошибки.)

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

Следует включить поддержку запросов IOCTL, использующих метод "ни", только если вы уверены, что UMDF может преобразовать метод доступа в буферный или прямой ввод-вывод. Например, если IOCTL указывает настраиваемый запрос, который не соответствует правилам спецификации буфера, описанным в разделе Описания буфера для кодов управления вводом-выводом, UMDF не сможет преобразовать буферы.