Compartir a través de


Compatibilidad con clientes de Kernel-Mode en controladores UMDF 1.x

Advertencia

UMDF 2 es la versión más reciente de UMDF y sustituye a UMDF 1. Todos los controladores UMDF nuevos deben escribirse con UMDF 2. No se agregan nuevas características a UMDF 1 y hay compatibilidad limitada con UMDF 1 en versiones más recientes de Windows 10. Los controladores universales de Windows deben usar UMDF 2.

Los ejemplos de UMDF 1 archivados se pueden encontrar en la actualización de ejemplos de controladores de Windows 11, versión 22H2 - mayo de 2022.

Para obtener más información, consulta Introducción con UMDF.

Las versiones 1.9 y posteriores de UMDF permiten que los controladores UMDF admitan clientes en modo kernel. Un cliente en modo kernel puede ser cualquiera de los siguientes:

  • Un controlador en modo kernel que existe encima de un controlador UMDF en la pila de controladores de un dispositivo.

  • Un controlador en modo kernel para una pila de dispositivos, que admite un dispositivo, abre un identificador para otro dispositivo y la pila de controladores del último dispositivo contiene un controlador UMDF.

En otras palabras, un controlador UMDF que admite clientes en modo kernel puede recibir solicitudes de E/S de un controlador en modo kernel. El controlador en modo kernel puede reenviar solicitudes de E/S que ha recibido de una aplicación en modo de usuario, o puede crear nuevas solicitudes de E/S y enviarlas al controlador en modo de usuario.

Para determinar si el controlador UMDF debe admitir clientes en modo kernel, debe comprender la pila de controladores a la que se agregará el controlador y dónde residirá el controlador en esa pila. También debe determinar si un controlador de otra pila podría enviar solicitudes de E/S al dispositivo del controlador.

El controlador debe admitir clientes en modo kernel si:

  • Un controlador en modo kernel se puede ubicar directamente encima del controlador UMDF en una pila de controladores. Por ejemplo, un controlador de filtro en modo kernel podría residir directamente encima de un controlador de funciones basado en UMDF.

  • Un controlador en modo kernel de otra pila puede enviar solicitudes de E/S al dispositivo del controlador. Por ejemplo, el controlador puede crear un vínculo simbólico que un controlador en modo kernel de otra pila puede usar para abrir un identificador en el dispositivo del controlador. Después, el controlador en modo kernel puede enviar solicitudes de E/S al dispositivo.

Cómo admitir clientes en modo kernel en un controlador UMDF

Un controlador UMDF puede recibir solicitudes de E/S de un controlador en modo kernel solo si el controlador UMDF ha habilitado la compatibilidad con los clientes en modo kernel. Además, si una instalación de dispositivo intenta cargar controladores en modo kernel por encima de un controlador UMDF en la pila de controladores del dispositivo, el marco permite que los controladores se carguen solo si el controlador UMDF ha habilitado la compatibilidad con los clientes en modo kernel.

Para habilitar la compatibilidad de un controlador UMDF con clientes en modo kernel, el archivo INF del controlador UMDF debe incluir una directiva UmdfKernelModeClientPolicy en su DDInstall inf. Sección WDF . Si el archivo INF del controlador UMDF no incluye esta directiva, UMDF no permite que se ejecute un controlador en modo kernel instalado encima del controlador UMDF.

El marco proporciona dos métodos útiles para los controladores que admiten clientes en modo kernel. Un controlador puede llamar al método IWDFIoRequest2::GetRequestorMode para determinar si una solicitud de E/S procede del modo kernel o del modo de usuario. Si la solicitud de E/S procede del modo de usuario, el controlador puede llamar a IWDFIoRequest2::IsFromUserModeDriver para determinar si la solicitud procede de una aplicación u otro controlador en modo de usuario.

Restricciones en los controladores en modo kernel

Un controlador UMDF puede procesar solicitudes de E/S desde un controlador en modo kernel solo si el controlador en modo kernel cumple los siguientes requisitos:

  • El controlador en modo kernel debe ejecutarse en IRQL = PASSIVE_LEVEL cuando envía la solicitud de E/S.

  • A menos que el controlador haya establecido la directiva UmdfFileObjectPolicy INF en AllowNullAndUnknownFileObjects, cada solicitud de E/S que un controlador en modo kernel envíe a un controlador en modo de usuario debe tener un objeto de archivo asociado. El marco debe haber sido notificado previamente de que el administrador de E/S creó el objeto de archivo. (Esta notificación hace que el marco llame a la función de devolución de llamada IQueueCallbackCreate::OnCreateFile del controlador en modo de usuario, pero esa función de devolución de llamada es opcional).

  • La solicitud de E/S no puede contener un código de función IRP_MJ_INTERNAL_DEVICE_CONTROL .

  • Los búferes de la solicitud de E/S no deben contener punteros a información adicional, ya que el controlador en modo de usuario no puede desreferenciar los punteros.

  • Si la solicitud de E/S contiene un código de control de E /S que especifica el método de acceso de búfer "ninguno", el controlador en modo kernel debe enviar la solicitud de E/S en el contexto de proceso de la aplicación que creó la solicitud de E/S. Para obtener más información sobre cómo admitir el método "ni" en un controlador base de UMDF, vea Usar E/S almacenada en búfer ni E/S directa en controladores UMDF.

  • El controlador UMDF puede modificar los datos de salida de una solicitud de E/S, en modo de usuario. Por lo tanto, el controlador en modo kernel debe validar los datos de salida que recibe del controlador en modo de usuario.

  • Normalmente, el cliente en modo kernel debe validar el valor de información que pasa un controlador UMDF a IWDFIoRequest::CompleteWithInformation. Si el cliente es un controlador KMDF, puede llamar a WdfRequestGetCompletionParams para obtener esta información en una estructura de IO_STATUS_BLOCK.

    Normalmente, el marco no valida el valor de información que pasa un controlador UMDF a IWDFIoRequest::CompleteWithInformation. (Este parámetro suele especificar el número de bytes transferidos). El marco valida el valor de información solo para los búferes de salida y solo para el método de acceso a datos de E/S almacenado en búfer . (Por ejemplo, el marco comprueba que el número de bytes transferidos no supera el tamaño del búfer de salida de una operación de lectura, si el método de acceso está almacenado en búfer de E/S).

Control de los valores de estado devueltos en un controlador UMDF 1.x

Pasar valores de estado devueltos del modo de usuario al modo kernel requiere atención especial, como se indica a continuación:

  • Los controladores de la versión 1 de UMDF suelen recibir valores devueltos con tipo HRESULT, mientras que los controladores en modo kernel basados en KMDF y WDM suelen recibir valores con tipo NTSTATUS. Si es una UMDF 1. El controlador x completa una solicitud de E/S y, si el controlador tiene un cliente en modo kernel, la llamada del controlador a IWDFIoRequest::Complete o IWDFIoRequest::CompleteWithInformation debe especificar un valor HRESULT que el controlador genera a partir de un valor NTSTATUS. En general, UMDF 1. Los controladores x deben usar la macro HRESULT_FROM_NT (definida en Winerror.h) para devolver el estado a un cliente en modo kernel. En el ejemplo siguiente se muestra cómo usar esta macro al completar una solicitud.

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

    Para devolver un valor HRESULT específico a un cliente en modo kernel, las siguientes devoluciones de llamada deben usar la macro HRESULT_FROM_NT:

    Para usar los valores NTSTATUS que se definen en ntstatus.h, un UMDF 1. El controlador x debe incluir estas dos líneas antes de incluir encabezados adicionales.

    #define UMDF_USING_NTSTATUS
    #include <ntstatus.h>
    

    No utilice la macro HRESULT_FROM_NT para convertir STATUS_SUCCESS de un valor NTSTATUS a un valor HRESULT. Solo tiene que devolver S_OK, como se muestra en el ejemplo siguiente.

    request->Complete(S_OK);
    
  • El marco completa algunas solicitudes de E/S en nombre de los controladores de UMDF. A veces, el marco no convierte los valores devueltos con tipo HRESULT en valores NTSTATUS equivalentes, por lo que el marco podría pasar un estado de finalización con tipo HRESULT a un cliente en modo kernel.

    Debido a esta situación, los clientes en modo kernel no deben usar la macro NT_ERROR al probar el estado de finalización de una solicitud de E/S, porque la macro NT_ERROR no devuelve TRUE para los valores de error HRESULT. Los controladores en modo kernel deben usar la macro NT_SUCCESS al probar el estado de finalización de una solicitud de E/S.

Compatibilidad con cliente en modo kernel en versiones anteriores de UMDF

En el caso de las versiones de UMDF anteriores a la versión 1.9, el archivo INF de un controlador puede incluir una directiva AddReg de INF para crear un valor del Registro UpperDriverOk de tamaño REG_DWORD en la subclave WUDF de la clave de hardware del dispositivo.

Si el valor del Registro UpperDriverOk se establece en un número distinto de cero, el marco permite que los controladores en modo kernel se carguen por encima del controlador en modo de usuario. Los controladores en modo kernel pueden reenviar solicitudes de E/S desde aplicaciones en modo de usuario al controlador UMDF, pero los controladores en modo kernel no pueden enviar solicitudes de E/S creadas en modo kernel al controlador UMDF.

En el caso de las versiones 1.9 y posteriores de UMDF, el valor del Registro UpperDriverOk está obsoleto y solo se admite para los controladores existentes. Los nuevos controladores deben usar la directiva UmdfKernelModeClientPolicy .