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


Поддержка клиентов Kernel-Mode в драйверах UMDF 1.x

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

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

Архивные примеры UMDF 1 можно найти в Windows 11, версии 22H2 — обновление примеров драйверов от мая 2022 года.

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

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

  • Драйвер режима ядра, который существует над драйвером UMDF в стеке драйверов устройства.

  • Драйвер режима ядра для одного стека устройств, который поддерживает одно устройство, открывает дескриптор для другого устройства, а стек драйверов последнего устройства содержит драйвер UMDF.

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

Чтобы определить, должен ли драйвер UMDF поддерживать клиенты в режиме ядра, необходимо понять стек драйверов, в который будет добавлен драйвер, и где будет находиться драйвер. Кроме того, необходимо определить, может ли драйвер из другого стека отправлять запросы ввода-вывода на устройство драйвера.

Драйвер должен поддерживать клиенты в режиме ядра, если:

  • Драйвер в режиме ядра может находиться непосредственно над драйвером UMDF в стеке драйверов. Например, драйвер фильтра в режиме ядра может находиться непосредственно над драйвером функции на основе UMDF.

  • Драйвер режима ядра из другого стека может отправлять запросы ввода-вывода на устройство драйвера. Например, ваш драйвер может создать символьную ссылку, которую драйвер в режиме ядра в другом стеке может использовать для открытия дескриптора на устройстве вашего драйвера. Затем драйвер режима ядра может отправлять запросы ввода-вывода на устройство.

Поддержка клиентов в режиме ядра в драйвере UMDF

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

Чтобы включить поддержку драйвера UMDF для клиентов в режиме ядра, INF-файл драйвера UMDF должен содержать директиву UmdfKernelModeClientPolicy в разделе INF-DDInstallWDF. Если INF-файл драйвера UMDF не включает эту директиву, UMDF не разрешает запуск драйвера в режиме ядра, установленного над драйвером UMDF.

Платформа предоставляет два метода, которые полезны для драйверов, поддерживающих клиенты в режиме ядра. Драйвер может вызвать метод IWDFIoRequest2::GetRequestorMode , чтобы определить, поступил ли запрос ввода-вывода из режима ядра или пользовательского режима. Если запрос ввода-вывода поступил из пользовательского режима, драйвер может вызвать IWDFIoRequest2::IsFromUserModeDriver , чтобы определить, поступил ли запрос из приложения или другого драйвера пользовательского режима.

Ограничения драйверов в режиме ядра

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

  • Драйвер режима ядра должен работать на уровне IRQL = PASSIVE_LEVEL при отправке запроса на ввод-вывод.

  • Если драйвер не установил директиву INF UmdfFileObjectPolicy в значение AllowNullAndUnknownFileObjects, каждый запрос ввода-вывода, который драйвер режима ядра отправляет драйверу пользовательского режима, должен иметь связанный объект файла. Платформа должна быть ранее уведомлена о том, что диспетчер ввода-вывода создал объект файла. (Такое уведомление заставляет платформу вызвать необязательную функцию обратного вызова IQueueCallbackCreate::OnCreateFile в режиме пользователя драйвера.)

  • Запрос ввода-вывода не может содержать код функции IRP_MJ_INTERNAL_DEVICE_CONTROL.

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

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

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

  • Клиент режима ядра обычно должен проверять значение Information, которое драйвер UMDF передает в IWDFIoRequest::CompleteWithInformation. Если клиент является драйвером KMDF, он может вызывать WdfRequestGetCompletionParams, чтобы получить эти сведения в структуре IO_STATUS_BLOCK.

    Как правило, платформа не проверяет значение информации, которое драйвер UMDF передает iWDFIoRequest::CompleteWithInformation. (Обычно этот параметр указывает количество переданных байтов.) Платформа проверяет значение информации только для выходных буферов и только для метода доступа к данным буферизованного ввода-вывода. (Например, платформа проверяет, что количество передаваемых байтов не превышает размер выходного буфера операции чтения, если метод доступа буферен ввода-вывода.)

Обработка возвращаемых значений состояния в драйвере UMDF 1.x

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

  • Драйверы UMDF версии 1 обычно получают возвращаемые значения HRESULT, а драйверы режима ядра на основе KMDF и WDM обычно получают значения типа NTSTATUS. Драйвер UMDF 1.x завершает запрос ввода-вывода, и если у драйвера есть клиент в режиме ядра, то вызов драйвера к IWDFIoRequest::Complete или IWDFIoRequest::CompleteWithInformation должен указать значение HRESULT, которое драйвер генерирует из значения NTSTATUS. Как правило, драйверы UMDF версии 1.x должны использовать макрос HRESULT_FROM_NT (определенный в Winerror.h), чтобы возвращать статус клиенту, работающему в режиме ядра. В следующем примере показано, как использовать этот макрос при выполнении запроса.

    hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW)
    request->Complete(HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW);
    return hr;
    

    Чтобы вернуть определенное значение HRESULT клиенту в режиме ядра, следующие обратные вызовы должны использовать макрос HRESULT_FROM_NT:

    Чтобы использовать значения NTSTATUS, определенные в ntstatus.h, UMDF 1. Драйвер x должен включать эти две строки, прежде чем включать дополнительные заголовки.

    #define UMDF_USING_NTSTATUS
    #include <ntstatus.h>
    

    Не используйте макрос HRESULT_FROM_NT для преобразования STATUS_SUCCESS из значения NTSTATUS в значение HRESULT. Просто верните S_OK, как показано в следующем примере.

    request->Complete(S_OK);
    
  • Платформа завершает некоторые запросы ввода-вывода от имени драйверов UMDF. Иногда фреймворк не преобразует возвращаемые значения типа HRESULT в эквивалентные значения NTSTATUS, поэтому он может передавать статус завершения типа HRESULT клиенту режима ядра.

    Из-за этой ситуации клиенты в режиме ядра не должны использовать макрос NT_ERROR при тестировании состояния завершения запроса ввода-вывода, так как макрос NT_ERROR не возвращает значение TRUE для значений ошибок HRESULT. Драйверы режима ядра должны использовать макрос NT_SUCCESS при тестировании состояния завершения запроса ввода-вывода.

Поддержка клиентов в режиме ядра в более ранних версиях UMDF

Для версий UMDF, предшествующих версии 1.9, INF-файл драйвера может включать директиву INF AddReg для создания значения реестра REG_DWORD размера UpperDriverOk в подразделе WUDFаппаратного ключа устройства.

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

Для версий UMDF версии 1.9 и более поздних версий значение реестра UpperDriverOk устарело и поддерживается только для существующих драйверов. Новые драйверы должны использовать директиву UmdfKernelModeClientPolicy .