Signalisieren eines CPU-Ereignisses von einem Kernelmodustreiber
Es gibt Fälle, in denen der Kernelmodustreiber (KMD) ein CPU-Ereignis signalisieren muss, um den Benutzermodustreiber (UMD) über etwas zu benachrichtigen. Zum Beispiel:
- Wenn KMD erkennt, dass sich eines seiner Objekte in einem fehlerhaften Zustand befindet und UMD benachrichtigen muss.
- Während des GPU-Debuggings muss KMD mit UMD kommunizieren, dass ein Ereignis aufgetreten ist. Für IHVs mit Systemsteuerungen für GPU ermöglicht das Signalisieren von CPU-Ereignissen nach KMD, dass KMD die Systemsteuerungs-App über interne Ereignisse benachrichtigt.
In der Regel kann UMD ein CPU-Ereignis erstellen und sein NT-Handle in einer privaten Escapedaten an KMD übergeben. Diese Methode funktioniert nicht im GPU-Paravirtualisierungsszenario (GPU-PV), da NT-Handles nicht über VM-Grenzen hinweg verwendet werden können.
Ab Windows 11 Version 21H2 (WDDM 3.0) wurde die WDDM-API erweitert, damit UMD ein CPU-Ereignisobjekt erstellen kann, das von KMD signalisiert werden kann. Dieses Feature funktioniert sowohl, wenn UMD auf dem Host oder auf einem virtuellen Computer mit GPU-PV ausgeführt wird.
Ablauf des Features
UMD erstellt ein GPU-Synchronisierungsobjekt mit dem D3DDDI_CPU_NOTIFICATION Typ. Das erstellte Objekt wird für KMD sichtbar gemacht, indem beim Aufrufen von D3DKMTCreateSynchronizationObject das SignalByKmd-Flag festgelegt wird.
Dxgkrnl ruft DXGKDDI_CREATECPUEVENT auf, damit KMD ein eigenes Objekt erstellen kann.
UMD ruft D3DKMTEscape mit dem D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE bekannten Escapetyp auf, um KMD über die beabsichtigte Verwendung des Synchronisierungsobjekts zu benachrichtigen.
Dxgkrnl ruft DXGKDDI_ESCAPE auf, um die privaten Daten an KMD zu übergeben.
Irgendwann ruft KMD DXGKCB_SIGNALEVENT mit dem CpuEventObject-Flag auf, um das CPU-Ereignisobjekt zu signalisieren.
UMD ruft D3DKMTDestroySynchronizationObject auf, um das CPU-Ereignisobjekt zu zerstören.
Dxgkrnl ruft DXGKDDI_DESTROYCPUEVENT auf, um das CPU-Ereignisobjekt zu zerstören. DXGKCB_SIGNALEVENT sollte nach diesem Punkt nicht mehr aufgerufen werden.
Das Synchronisierungsobjekt kann nicht in eine Kontextwarteschlange eingefügt werden. Sie kann nur von KMD mit DXGKCB_SIGNALEVENT signalisiert werden.
Benutzermodus-APIs zum Verarbeiten von CPU-Ereignissynchronisierungsobjekten
Erstellen des KMD-CPU-Ereignisobjekts
Das KMD-CPU-Ereignisobjekt wird als GPU-Synchronisierungsobjekt erstellt, indem D3D12DDICB_CREATESYNCHRONIZATIONOBJECT2 mit folgendem Befehl aufgerufen wird:
Typ , der auf D3DDDI_CPU_NOTIFICATION festgelegt ist.
Flags , die auf SignalByKmd festgelegt sind, um anzugeben, dass das Objekt von KMD signalisiert wird. Dieses Flag kann nur festgelegt werden, wenn das Type-Element vonD3DDDI_SYNCHRONIZATIONOBJECTINFO2D3DDDI_CPU_NOTIFICATION ist.
Wenn das SignalByKmd-Flag festgelegt ist, wird DXGKDDI_CREATECPUEVENT aufgerufen, um das KMD-CPU-Ereignisobjekt zu erstellen. Beachten Sie, dass das Gerätehandle beim Erstellen des Synchronisierungsobjekts angegeben werden muss.
Das Synchronisierungsobjekt kann nicht in Signal- und Warte-APIs (D3DKMTSignalSynchronizationObject, D3DKMTWaitForSynchronizatioObject) verwendet werden. Es kann nur von KMD signalisiert werden, und UMD kann auf das entsprechende CPU-Ereignis warten.
UMD-Escape zum Definieren der Verwendung für ein KMD-CPU-Ereignissynchronisierungsobjekt
D3DDDI_DRIVERESCAPETYPE wurde ein bekanntes Escapezeichen hinzugefügt. D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE wird verwendet, um KMD über die beabsichtigte Verwendung eines KMD-CPU-Ereignisobjekts zu informieren. Ein bekanntes Escapezeichen wird definiert, indem DXGKARG_ESCAPE::Flags.DriverKnownEscape = 1 festgelegt wird. Bekannte Escapes werden selbst von sicheren virtuellen Computern an den Host gesendet.
Der folgende Codeausschnitt ist ein Verwendungsbeispiel.
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 ruft DXGKDDI_ESCAPE wie folgt auf:
- hDevice auf das Miniport-Gerätehandle festgelegt, das zum Erstellen des Synchronisierungsobjekts verwendet wurde
- pPrivateDriverData , das auf eine D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE-Struktur verweist
- PrivateDriverDataSize auf festgelegt
sizeof(D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE)
Erstellen und Zerstören eines KMD-CPU-Ereignisobjekts
Die folgenden DDIs werden verwendet, um KMD-CPU-Ereignissynchronisierungsobjekte zu erstellen und zu zerstören:
Signalisieren eines CPU-Ereignisobjekts aus KMD
Um ein CPU-Ereignisobjekt zu signalisieren, ruft KMD DXGKCB_SIGNALEVENT unter IRQL <= DISPATCH_LEVEL auf, wobei die DXGKARGCB_SIGNALEVENT-Strukturwerte wie folgt festgelegt sind:
hDxgkProcess ist gleich 0.
hEvent entspricht dem dxgkrnl CPU-Ereignisobjekthandle, das an DXGKDDI_CREATECPUEVENT übergeben wird.
CpuEventObject muss 1 sein.
Reserviert muss 0 sein.