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
UMD crea un objeto de sincronización de GPU con el tipo D3DDDI_CPU_NOTIFICATION . El objeto creado se hace visible para KMD estableciendo la marca SignalByKmd al llamar a D3DKMTCreateSynchronizationObject.
Dxgkrnl llama a DXGKDDI_CREATECPUEVENT para permitir que KMD cree su propio objeto.
UMD llama a D3DKMTEscape con el tipo de escape conocido D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE para notificar al KMD sobre el uso previsto del objeto de sincronización.
Dxgkrnl llama a DXGKDDI_ESCAPE para pasar los datos privados a KMD.
En algún momento, KMD llama a DXGKCB_SIGNALEVENT con la marca CpuEventObject para indicar el objeto de evento de CPU.
UMD llama a D3DKMTDestroySynchronizationObject para destruir el objeto de evento de CPU.
Dxgkrnl llama a DXGKDDI_DESTROYCPUEVENT para destruir el objeto de evento de CPU. DXGKCB_SIGNALEVENT no se debe llamar después de este punto.
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.