Señalización de un evento de CPU desde un controlador en modo kernel

Hay casos en los que el controlador en modo kernel (KMD) necesita indicar un evento de CPU para notificar al controlador en modo de usuario (UMD) algo; por ejemplo:

  • Cuando KMD detecta que uno de sus objetos está en un estado incorrecto y necesita notificar a UMD.
  • Durante la depuración de GPU donde KMD necesita comunicarse con UMD que se produjo algún evento. En el caso de los IHD con paneles de control para GPU, la señalización de eventos de CPU por KMD permite a KMD notificar a la aplicación Paneles de control sobre eventos internos.

Normalmente, UMD puede crear un evento de CPU y pasar su identificador NT a KMD en datos privados de escape. Este método no funciona en el escenario de paravirtualización de GPU (GPU-PV) porque los identificadores NT no se pueden usar a través de los límites de la máquina virtual.

A partir de Windows 11 versión 21H2 (WDDM 3.0), la API de WDDM se extendió para permitir que UMD cree un objeto de evento de CPU que KMD pueda indicar. Esta característica funciona cuando UMD se ejecuta en el host o en una máquina virtual mediante GPU-PV.

Flujo de característica

El objeto de sincronización no se puede insertar en una cola de contexto. Solo se puede señalar mediante KMD mediante DXGKCB_SIGNALEVENT.

API en modo de usuario para controlar objetos de sincronización de eventos de CPU

Creación del objeto de evento de CPU de KMD

El objeto de evento de CPU de KMD se crea como un objeto de sincronización de GPU llamando a D3D12DDICB_CREATESYNCHRONIZATIONOBJECT2 con:

  • Escriba establecido en D3DDDI_CPU_NOTIFICATION.

  • Marcas establecidas en SignalByKmd para especificar que el objeto será señalado por KMD. Esta marca solo se puede establecer cuando el miembro Type deD3DDDI_SYNCHRONIZATIONOBJECTINFO2 es D3DDDI_CPU_NOTIFICATION.

Cuando se establece la marca SignalByKmd , se llamará a DXGKDDI_CREATECPUEVENT para crear el objeto de evento de CPU de KMD. Tenga en cuenta que el identificador del dispositivo debe especificarse al crear el objeto de sincronización.

El objeto de sincronización no se puede usar en las API de señal y espera (D3DKMTSignalSynchronizationObject, D3DKMTWaitForSynchronizatioObject). Solo se puede indicar mediante KMD y UMD puede esperar en el evento de CPU correspondiente.

Escape umD para definir el uso de un objeto de sincronización de eventos de CPU de KMD

Se agregó un escape conocido a D3DDDI_DRIVERESCAPETYPE. D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE se usa para notificar a KMD el uso previsto de un objeto de evento de CPU de KMD. Se define un escape conocido estableciendo DXGKARG_ESCAPE::Flags.DriverKnownEscape = 1. Los escapes conocidos se envían al host incluso desde máquinas virtuales seguras.

El siguiente fragmento de código es un ejemplo de uso.

D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE Command = {};
Command.EscapeType = D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE;
Command.hSyncObject = SyncObjectHandle;
Command.Usage[0] = 1;

D3DKMT_ESCAPE Args = {};
Args.hAdapter = AdapterHandle;
Args.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
Args.Flags.DriverKnownEscape = 1;
Args.Flags.NoAdapterSynchronization = 1; // Prevent waking up the device from D3
Args.pPrivateDriverData = &Command;
Args.PrivateDriverDataSize = sizeof(Command);

NTSTATUS Status = D3DKMTEscape(&Args);

Dxgkrnl llamará a DXGKDDI_ESCAPE con lo siguiente:

  • hDevice establecido en el identificador del dispositivo de miniporte que se usó para crear el objeto de sincronización
  • pPrivateDriverData que apunta a una estructura de D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE
  • PrivateDriverDataSize establecido en sizeof(D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE)

Creación y destrucción de un objeto de evento de CPU de KMD

Los siguientes DDIs se usan para crear y destruir objetos de sincronización de eventos de CPU de KMD:

Señalización de un objeto de evento de CPU desde KMD

Para indicar un objeto de evento de CPU, KMD llama a DXGKCB_SIGNALEVENT en IRQL <= DISPATCH_LEVEL y con los valores de estructura de DXGKARGCB_SIGNALEVENT establecidos de la siguiente manera:

  • hDxgkProcess es igual a 0.

  • hEvent igual al identificador de objeto de evento de CPU dxgkrnl pasado a DXGKDDI_CREATECPUEVENT.

  • CpuEventObject debe ser 1.

  • Reservado debe ser 0.