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

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.