커널 모드 드라이버에서 CPU 이벤트 신호
KMD(커널 모드 드라이버)가 CPU 이벤트에 신호를 전송하여 UMD(사용자 모드 드라이버)에게 무언가에 대해 알려야 하는 경우가 있습니다. 예를 들어:
- KMD가 해당 개체 중 하나가 잘못된 상태임을 감지하고 UMD에 알려야 하는 경우
- GPU 디버깅 중에 KMD가 일부 이벤트가 발생했음을 UMD와 통신해야 합니다. GPU용 제어판이 있는 IHV의 경우 KMD에서 CPU 이벤트를 신호로 전송하면 KMD가 제어판 앱에 내부 이벤트에 대해 알릴 수 있습니다.
일반적으로 UMD는 CPU 이벤트를 만들고 이스케이프 프라이빗 데이터의 KMD에 NT 핸들을 전달할 수 있습니다. NT 핸들은 가상 머신 경계를 넘어 사용할 수 없으므로 GPU-PV(GPU 반가상화) 시나리오에서는 이 메서드가 작동하지 않습니다.
Windows 11 버전 21H2(WDDM 3.0)부터 WDDM API는 UMD가 KMD에서 신호를 받을 수 있는 CPU 이벤트 개체를 만들 수 있도록 확장되었습니다. 이 기능은 UMD가 호스트 또는 GPU-PV를 사용하여 가상 머신에서 실행 중일 때 모두 작동합니다.
기능 흐름
UMD 는 CPU 이벤트를 만듭니다.
UMD는 D3DDDI_CPU_NOTIFICATION 형식의 GPU 동기화 개체를 만듭니다. 만든 개체는 D3DKMTCreateSynchronizationObject를 호출할 때 SignalByKmd 플래그를 설정하여 KMD에 표시됩니다.
Dxgkrnl 은 DXGKDDI_CREATECPUEVENT 호출하여 KMD가 자체 개체를 만들 수 있도록 합니다.
UMD는 D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE 알려진 이스케이프 형식으로 D3DKMTEscape를 호출하여 KMD에 동기화 개체의 의도된 사용법을 알립니다.
Dxgkrnl은DXGKDDI_ESCAPE 호출하여 프라이빗 데이터를 KMD에 전달합니다.
특정 시점에서 KMD는 cpuEventObject 플래그를 사용하여 DXGKCB_SIGNALEVENT 호출하여 CPU 이벤트 개체에 신호를 보냅니다.
UMD는 D3DKMTDestroySynchronizationObject 를 호출하여 CPU 이벤트 개체를 삭제합니다.
Dxgkrnl 은 DXGKDDI_DESTROYCPUEVENT 호출하여 CPU 이벤트 개체를 삭제합니다. 이 시점 이후에는 DXGKCB_SIGNALEVENT 호출하면 안 됩니다.
동기화 개체는 컨텍스트 큐에 삽입할 수 없습니다. DXGKCB_SIGNALEVENT 사용하여 KMD에서만 신호를 받을 수 있습니다.
CPU 이벤트 동기화 개체를 처리하는 사용자 모드 API
KMD CPU 이벤트 개체 만들기
KMD CPU 이벤트 개체는 다음을 사용하여 D3D12DDICB_CREATESYNCHRONIZATIONOBJECT2 호출하여 GPU 동기화 개체로 만들어집니다.
D3DDDI_CPU_NOTIFICATION 형식으로 설정됩니다.
개체 가 KMD로 신호를 받도록 지정하기 위해 SignalByKmd 로 설정된 플래그입니다. 이 플래그는 D3DDDI_SYNCHRONIZATIONOBJECTINFO2 Type 멤버가D3DDDI_CPU_NOTIFICATION 경우에만 설정할 수 있습니다.
SignalByKmd 플래그가 설정되면 DXGKDDI_CREATECPUEVENT 호출되어 KMD CPU 이벤트 개체를 만듭니다. 동기화 개체를 만들 때 디바이스 핸들을 지정해야 합니다.
동기화 개체는 신호 및 대기 API에서 사용할 수 없습니다(D3DKMTSignalSynchronizationObject, D3DKMTWaitForSynchronizatioObject). KMD에서만 신호를 받을 수 있으며 UMD는 해당 CPU 이벤트를 기다릴 수 있습니다.
KMD CPU 이벤트 동기화 개체에 대한 사용량을 정의하는 UMD 이스케이프
알려진 이스케이프가 D3DDDI_DRIVERESCAPETYPE 추가되었습니다. D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE KMD CPU 이벤트 개체의 의도된 사용량을 KMD에 알리는 데 사용됩니다. 알려진 이스케이프는 DXGKARG_ESCAPE::Flags.DriverKnownEscape = 1을 설정하여 정의됩니다. 알려진 이스케이프는 보안 가상 머신에서도 호스트로 전송됩니다.
다음 코드 조각은 사용 예제입니다.
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 는 동기화 개체를 만드는 데 사용된 미니포트 디바이스 핸들로 설정됩니다.
- D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE 구조를 가리키는 pPrivateDriverData
- PrivateDriverDataSize 가 로 설정됨
sizeof(D3DDDI_DRIVERESCAPE_CPUEVENTUSAGE)
KMD CPU 이벤트 개체 만들기 및 삭제
다음 DDI는 KMD CPU 이벤트 동기화 개체를 만들고 삭제하는 데 사용됩니다.
KMD에서 CPU 이벤트 개체 신호
CPU 이벤트 개체에 신호를 표시하기 위해 KMD는 IRQL<= DISPATCH_LEVEL 및 DXGKARGCB_SIGNALEVENT 구조체 값이 다음과 같이 설정된 DXGKCB_SIGNALEVENT 호출합니다.
hDxgkProcess는 0과 같습니다.
hEvent는 DXGKDDI_CREATECPUEVENT 전달된 Dxgkrnl CPU 이벤트 개체 핸들과 같습니다.
CpuEventObject 는 1이어야 합니다.
예약은 0이어야 합니다.