Поделиться через


Сигнализация события ЦП из драйвера в режиме ядра

Бывают случаи, когда драйвер режима ядра (KMD) должен сигнализировать о событии ЦП, чтобы уведомить драйвер пользовательского режима (UMD) о чем-то; Например:

  • Когда KMD обнаруживает, что один из его объектов находится в плохом состоянии и должен уведомить UMD.
  • Во время отладки GPU, где KMD необходимо сообщить UMD о том, что произошло какое-то событие. Для IHV с панелями управления для GPU сигнализация событий ЦП с помощью KMD позволяет KMD уведомлять приложение панели управления о внутренних событиях.

Как правило, UMD может создать событие ЦП и передать его дескриптор NT в KMD в escape-личных данных. Этот метод не работает в сценарии паравиртуализации GPU (GPU-PV), так как дескрипторы NT не могут использоваться в пределах виртуальных машин.

Начиная с Windows 11 версии 21H2 (WDDM 3.0), API WDDM был расширен, чтобы разрешить UMD создавать объект события ЦП, который может сигнализировать kmd. Эта функция работает как при выполнении UMD на узле, так и на виртуальной машине с использованием GPU-PV.

Поток функций

  • UMD создает событие ЦП.

  • UMD создает объект синхронизации GPU с типом D3DDDI_CPU_NOTIFICATION . Созданный объект становится видимым для KMD путем установки флага SignalByKmd при вызове D3DKMTCreateSynchronizationObject.

  • Dxgkrnl вызывает DXGKDDI_CREATECPUEVENT , чтобы разрешить KMD создавать собственный объект.

  • UMD вызывает D3DKMTEscape с D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE известным escape-типом, чтобы уведомить KMD о предполагаемом использовании объекта синхронизации.

  • Dxgkrnl вызывает DXGKDDI_ESCAPE для передачи частных данных в KMD.

  • В какой-то момент KMD вызывает DXGKCB_SIGNALEVENT с флагом CpuEventObject , чтобы сообщить об объекте события ЦП.

  • UMD вызывает D3DKMTDesynchronizationObject для уничтожения объекта события ЦП.

  • Dxgkrnl вызывает DXGKDDI_DESTROYCPUEVENT для уничтожения объекта события ЦП. DXGKCB_SIGNALEVENT не следует вызывать после этого момента.

Объект синхронизации не может быть вставлен в очередь контекста. Это может быть сигнализировать только KMD с помощью DXGKCB_SIGNALEVENT.

API пользовательского режима для обработки объектов синхронизации событий ЦП

Создание объекта события ЦП KMD

Объект события ЦП KMD создается как объект синхронизации GPU путем вызова D3D12DDICB_CREATESYNCHRONIZATIONOBJECT2 с помощью:

  • Введитезначение D3DDDI_CPU_NOTIFICATION.

  • Флаги , для которого задано значение SignalByKmd , чтобы указать, что объект будет сигнализировать с помощью KMD. Этот флаг можно задать только в том случае, если элемент TypeD3DDDI_SYNCHRONIZATIONOBJECTINFO2D3DDDI_CPU_NOTIFICATION.

Если установлен флаг SignalByKmd , будет вызван DXGKDDI_CREATECPUEVENT для создания объекта события ЦП KMD. Обратите внимание, что при создании объекта синхронизации необходимо указать дескриптор устройства.

Объект синхронизации нельзя использовать в API сигналов и ожидания (D3DKMTSignalSynchronizationObject, D3DKMTWaitForSynchronizatioObject). Об этом может сообщить только KMD, и UMD может ожидать соответствующего события ЦП.

Экранирование UMD для определения использования объекта синхронизации событий ЦП KMD

В D3DDDI_DRIVERESCAPETYPE добавлен известный escape-экран. D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE используется для уведомления KMD о предполагаемом использовании объекта события ЦП KMD. Известный escape-файл определяется параметром DXGKARG_ESCAPE::Flags.DriverKnownEscape = 1. Известные escape-уведомления отправляются на узел даже с защищенных виртуальных машин.

Следующий фрагмент кода является примером использования.

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 вызовет DXGKDDI_ESCAPE со следующим кодом:

  • hDevice — дескриптор устройства miniport, который использовался для создания объекта синхронизации.
  • pPrivateDriverData, указывающий на структуру D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE
  • Для PrivateDriverDataSize задано значение sizeof(D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE)

Создание и уничтожение объекта события ЦП KMD

Следующие DDIs используются для создания и уничтожения объектов синхронизации событий ЦП KMD:

Сигнализация объекта события ЦП из KMD

Чтобы сообщить об объекте события ЦП, KMD вызывает DXGKCB_SIGNALEVENT в IRQL <= DISPATCH_LEVEL и с заданными значениями структуры DXGKARGCB_SIGNALEVENT следующим образом:

  • hDxgkProcess равно 0.

  • hEvent равно дескриптору объекта события ЦП Dxgkrnl , переданного в DXGKDDI_CREATECPUEVENT.

  • CpuEventObject должен иметь значение 1.

  • Зарезервировано должно иметь значение 0.