Compartilhar via


Sinalizando um evento de CPU de um driver no modo kernel

Há casos em que o KMD (driver do modo kernel) precisa sinalizar um evento de CPU para notificar o DRIVER do modo de usuário (UMD) sobre algo; por exemplo:

  • Quando o KMD detecta que um de seus objetos está em um estado inválido e precisa notificar a UMD.
  • Durante a depuração de GPU em que o KMD precisa se comunicar com a UMD de que algum evento aconteceu. Para IHVs com Painéis de Controle para GPU, a sinalização de eventos de CPU por KMD permite que o KMD notifique o aplicativo Painéis de Controle sobre eventos internos.

Normalmente, a UMD pode criar um evento de CPU e passar seu identificador NT para KMD em um escape de dados privados. Esse método não funciona no cenário de paravirtualização de GPU (GPU-PV), pois os identificadores NT não podem ser usados entre os limites da máquina virtual.

A partir Windows 11 versão 21H2 (WDDM 3.0), a API do WDDM foi estendida para permitir que a UMD criasse um objeto de evento de CPU que pode ser sinalizado pelo KMD. Esse recurso funciona quando o UMD está em execução no host ou em uma máquina virtual usando GPU-PV.

Fluxo de recursos

O objeto de sincronização não pode ser inserido em uma fila de contexto. Ele só pode ser sinalizado pelo KMD usando DXGKCB_SIGNALEVENT.

APIs do modo de usuário para lidar com objetos de sincronização de eventos da CPU

Criação do objeto de evento de CPU KMD

O objeto de evento da CPU KMD é criado como um objeto de sincronização de GPU chamando D3D12DDICB_CREATESYNCHRONIZATIONOBJECT2 com:

Quando o sinalizador SignalByKmd for definido, DXGKDDI_CREATECPUEVENT será chamado para criar o objeto de evento da CPU KMD. Observe que o identificador do dispositivo deve ser especificado ao criar o objeto de sincronização.

O objeto de sincronização não pode ser usado em APIs de sinal e espera (D3DKMTSignalSynchronizationObject, D3DKMTWaitForSynchronizatioObject). Ele só pode ser sinalizado pelo KMD e o UMD pode aguardar o evento de CPU correspondente.

Escape umd para definir o uso de um objeto de sincronização de eventos de CPU KMD

Uma fuga conhecida foi adicionada a D3DDDI_DRIVERESCAPETYPE. D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE é usado para notificar o KMD sobre o uso pretendido de um objeto de evento de CPU KMD. Um escape conhecido é definido pela configuração DXGKARG_ESCAPE::Flags.DriverKnownEscape = 1. Escapes conhecidos são enviados para o host mesmo de máquinas virtuais seguras.

O snippet a seguir é um exemplo 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 chamará DXGKDDI_ESCAPE com o seguinte:

  • hDevice definido como o identificador de dispositivo de miniport que foi usado para criar o objeto de sincronização
  • pPrivateDriverData apontando para uma estrutura de D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE
  • PrivateDriverDataSize definido como sizeof(D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE)

Criando e destruindo um objeto de evento de CPU KMD

Os seguintes DDIs são usados para criar e destruir objetos de sincronização de eventos de CPU KMD:

Sinalizando um objeto de evento de CPU do KMD

Para sinalizar um objeto de evento de CPU, o KMD chama DXGKCB_SIGNALEVENT em IRQL <= DISPATCH_LEVEL e com os valores de estrutura DXGKARGCB_SIGNALEVENT definidos da seguinte maneira:

  • hDxgkProcess é igual a 0.

  • hEvent igual ao identificador de objeto de evento da CPU Dxgkrnl passado para DXGKDDI_CREATECPUEVENT.

  • CpuEventObject deve ser 1.

  • Reservado deve ser 0.