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


Поддержка клиентов 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.

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

См. также раздел Поддержка клиентов Kernel-Mode в UMDF 2.x.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Если запрос ввода-вывода содержит код элемента управления вводом-выводом , указывающий метод доступа к буферу ,драйвер режима ядра должен отправить запрос ввода-вывода в контексте процесса приложения, создавшего запрос ввода-вывода. Дополнительные сведения о поддержке метода "ни один" в драйвере UMDF-base см. в разделе Использование буферизованного ввода-вывода и прямого ввода-вывода в драйверах 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 для создания значения реестра UpperDriverOk REG_DWORD размера в подразделе WUDFаппаратного ключа устройства.

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

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