Segnalazione di un evento cpu da un driver in modalità kernel

Ci sono casi in cui il driver in modalità kernel (KMD) deve segnalare un evento della CPU per notificare al driver in modalità utente (UMD) qualcosa; Per esempio:

  • Quando kmd rileva che uno dei relativi oggetti è in uno stato non valido e deve inviare una notifica a UMD.
  • Durante il debug della GPU in cui kmD deve comunicare con UMD che si è verificato un evento. Per IHV con pannelli di controllo per GPU, la segnalazione degli eventi della CPU da parte del KMD consente al KMD di notificare all'app Pannelli di controllo gli eventi interni.

In genere, UMD può creare un evento CPU e passare il relativo handle NT a KMD in un escape dei dati privati. Questo metodo non funziona nello scenario di paravirtualizzazione GPU (GPU-PV) perché gli handle NT non possono essere usati attraverso i limiti delle macchine virtuali.

A partire da Windows 11 versione 21H2 (WDDM 3.0), l'API WDDM è stata estesa per consentire a UMD di creare un oggetto evento CPU che può essere segnalato dal KMD. Questa funzionalità funziona sia quando la messaggistica unificata è in esecuzione nell'host o in una macchina virtuale che usa GPU-PV.

Flusso di funzionalità

L'oggetto di sincronizzazione non può essere inserito in una coda di contesto. Può essere segnalato solo dal KMD usando DXGKCB_SIGNALEVENT.

API in modalità utente per gestire gli oggetti di sincronizzazione degli eventi della CPU

Creazione dell'oggetto evento CPU KMD

L'oggetto evento CPU KMD viene creato come oggetto di sincronizzazione GPU chiamando D3D12DDICB_CREATESYNCHRONIZATIONOBJECT2 con:

  • Tipo impostato su D3DDDI_CPU_NOTIFICATION.

  • Flag impostati su SignalByKmd per specificare che l'oggetto verrà segnalato dal KMD. Questo flag può essere impostato solo quando il membro Type diD3DDDI_SYNCHRONIZATIONOBJECTINFO2 è D3DDDI_CPU_NOTIFICATION.

Quando viene impostato il flag SignalByKmd , DXGKDDI_CREATECPUEVENT verrà chiamato per creare l'oggetto evento CPU KMD. Si noti che l'handle del dispositivo deve essere specificato durante la creazione dell'oggetto di sincronizzazione.

L'oggetto di sincronizzazione non può essere usato nelle API signal and wait (D3DKMTSignalSynchronizationObject, D3DKMTWaitForSynchronizatioObject). Può essere segnalato solo dal KMD e UMD può attendere l'evento CPU corrispondente.

Escape UMD per definire l'utilizzo per un oggetto di sincronizzazione eventi CPU KMD

È stato aggiunto un escape noto a D3DDDI_DRIVERESCAPETYPE. D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE viene usato per notificare al KMD l'utilizzo previsto di un oggetto evento CPU KMD. Un carattere di escape noto viene definito impostando DXGKARG_ESCAPE::Flags.DriverKnownEscape = 1. I escape noti vengono inviati all'host anche da macchine virtuali sicure.

Il frammento di codice seguente è un esempio di utilizzo.

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 chiamerà DXGKDDI_ESCAPE con quanto segue:

  • hDevice impostato sull'handle del dispositivo miniport usato per creare l'oggetto di sincronizzazione
  • pPrivateDriverData che punta a una struttura D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE
  • PrivateDriverDataSize impostato su sizeof(D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE)

Creazione e eliminazione di un oggetto evento CPU KMD

Le DDI seguenti vengono usate per creare ed eliminare oggetti di sincronizzazione eventi CPU KMD:

Segnalazione di un oggetto evento CPU da KMD

Per segnalare un oggetto evento CPU, kmd chiama DXGKCB_SIGNALEVENT in IRQL <= DISPATCH_LEVEL e con i valori della struttura DXGKARGCB_SIGNALEVENT impostati come indicato di seguito:

  • hDxgkProcess è uguale a 0.

  • hEvent uguale all'handle dell'oggetto evento CPU Dxgkrnl passato a DXGKDDI_CREATECPUEVENT.

  • CpuEventObject deve essere 1.

  • Riservato deve essere 0.