다음을 통해 공유


GPU 준가상화

이 문서에서는 WDDM의 GPU 매개 변수화에 대해 설명합니다. 이 기능은 Windows 10 버전 1803(WDDM 2.4)부터 사용할 수 있습니다.

GPU 가상화 정보

GPU 가상화는 Windows 클라이언트와 Windows Server 모두에서 중요한 기능입니다. 가상 머신에서 GPU 리소스를 효과적으로 사용해야 하는 많은 시나리오가 있습니다.

서버 시나리오(호스트 OS에서 사용자 애플리케이션을 실행하지 않는 경우)는 다음과 같습니다.

  • 데스크톱 가상화
  • 컴퓨팅(AI, ML 등)

클라이언트 시나리오(호스트 OS가 VM과 사용자 애플리케이션 간에 GPU를 공유하는 경우)는 다음과 같습니다.

  • 그래픽 애플리케이션 개발 및 테스트(VM에서 테스트가 실행되는 위치)
  • 보안을 위해 VM에서 애플리케이션 실행
  • GPU 가속을 사용하여 VM에서 Linux 실행

WDDM의 GPU 부분 가상화

PV(반가상화)는 기본 하드웨어와 유사한 VM(가상 머신)에 대한 인터페이스를 제공합니다. PV에서는 VMM(가상 머신 모니터) 위에서 비정형 게스트 OS를 실행할 수 없으므로 VM을 설치하기 전에 게스트 OS를 명시적으로 포팅합니다.

장점:

  • 여러 VM이 하드웨어 리소스를 공유합니다.
  • 드라이버 코드에서 변경해야 하는 사항은 거의 없습니다.

다음 그림에서는 WDDM의 매개 변수화된 디자인과 관련된 다양한 구성 요소를 보여 줍니다.

매개 변수화된 디자인과 관련된 구성 요소를 보여 주는 다이어그램입니다.

게스트 VM의 D3D 런타임은 변경되지 않습니다. 사용자 모드 런타임과 KMT 커널 썽크와의 인터페이스는 변하지 않습니다.

드라이버 구성 요소에는 다음과 같은 많은 변경이 필요하지 않습니다.

  • 게스트 VM의 UMD는 다음을 수행해야 합니다.

    • 호스트 KMD(커널 모드 드라이버)와의 통신은 VM 경계를 넘어 발생합니다.
    • 추가된 Dxgkrnl 서비스를 사용하여 레지스트리 설정에 액세스합니다.
  • 게스트에는 KMD가 없고 UMD만 있습니다. VRD(Virtual Render Device) KMD는 KMD를 대체합니다. VRD의 목적은 Dxgkrnl의 로드를 용이하게 하는 것입니다.

  • 게스트에는 비디오 메모리 관리자(VidMm) 또는 스케줄러(VidSch)가 없습니다.

  • VM의 Dxgkrnl unk 호출을 가져오고 VM 버스 채널을 통해 호스트 파티션에 마샬링합니다. 게스트 내에서 Dxgkrnl은 할당, 프로세스, 디바이스 및 기타 리소스를 위한 로컬 개체를 생성하여 호스트와의 트래픽을 줄입니다.

VRD(가상 렌더링 디바이스)

VM에 반가상화된 GPU가 없으면 VM의 디바이스 관리자에 "Microsoft Hyper-V Video" 어댑터가 표시됩니다. 이 디스플레이 전용 어댑터는 기본적으로 렌더링을 위해 BasicRender 어댑터와 페어링됩니다.

VM에 반가상화된 GPU를 추가하면 VM의 디바이스 관리자에 다음 두 개의 어댑터가 표시됩니다.

  • Microsoft Hyper-V 비디오 어댑터 또는 Microsoft 원격 디스플레이 어댑터
  • Microsoft Virtual Render Driver(실제 이름은 호스트의 GPU 어댑터 이름)

기본적으로 VRD는 Hyper-V 비디오 어댑터와 페어링되므로 모든 UI 렌더링은 VRD 어댑터와 함께 발생합니다.

렌더링 문제가 발생하는 경우 GpuVirtualizationFlags 레지스트리 설정을 사용하여 이 페어링을 사용하지 않도록 설정할 수 있습니다. 이 경우 애플리케이션에서 특별히 선택할 때 VRD(렌더링 전용 어댑터)가 사용됩니다. 예를 들어 일부 DirectX 샘플을 사용하면 렌더링 디바이스를 변경할 수 있습니다. Direct3D 런타임은 애플리케이션에서 사용하기로 결정할 때 VRD에 논리적 디스플레이 출력을 추가합니다.

VM에 여러 가상 GPU를 추가하는 경우 게스트에 여러 VRD 어댑터가 있을 수 있습니다. 그러나 그 중 하나만 Hyper-V Video 어댑터와 페어링할 수 있습니다. 어떤 것을 지정할 수 있는 방법은 없습니다. OS에서 선택합니다.

컨테이너 및 VM

GPU 가상화는 VM 및 컨테이너에 대해 지원됩니다. 컨테이너는 호스트 OS 이진 파일이 컨테이너 VM에 매핑되는 경량 VM입니다.

컨테이너에 대한 자세한 내용은 Windows 및 컨테이너참조하세요.

보안 VM

보안 VM에는 다음과 같은 제한 사항이 있습니다.

  • 드라이버 이스케이프 호출은 DriverKnownEscape 플래그와 함께 사용되는 알려진 이스케이프를 제외하고는 허용되지 않습니다.
  • IoMmu 격리가 활성화됩니다. 드라이버가 IoMmu 격리를 지원하지 않으면 VM 만들기가 실패합니다.

보안 모드를 사용하는 경우:

개발 중에 보안 모드를 강제 적용하거나 IoMmu 격리를 사용하지 않도록 설정하는 레지스트리 설정이 있습니다. 자세한 내용은 레지스트리 설정참조하세요.

VM/컨테이너 데스크톱의 원격

다음 두 가지 방법을 사용하여 VM(가상 머신)의 데스크톱 콘텐츠를 호스트로 원격으로 연결할 수 있습니다.

  • 디스플레이 어댑터 Hyper-V
  • 터미널 세션 원격

RDP(원격 데스크톱)를 사용하여 VM에 연결하는 경우 터미널 세션 원격이 사용됩니다.

Hyper-V 관리자는 VMConnect 애플리케이션을 사용하여 VM 데스크톱을 표시합니다. VMConnect는 다음 두 가지 모드에서 작동합니다.

  • 터미널 세션 원격을 사용하는 향상된 모드입니다.
  • Hyper-V 디스플레이 어댑터를 사용하는 기본 모드입니다.

VM 작업자 프로세스 및 VM 메모리

VM 또는 컨테이너를 시작할 때 운영 체제는 호스트에 다음 프로세스를 만듭니다.

  • VM 작업자 프로세스(vmwp.exe)
  • VM 메모리 프로세스(vmmem.exe)

Vmwp는 가상 디바이스 드라이버, 특히 반가상화된 그래픽 어댑터용 드라이버인 vrdumed.dll를 포함하고 있습니다.

vmmem 프로세스 가상 주소 공간은 게스트에서 vGPU의 IO 공간에 대한 백업 역할을 합니다. 게스트가 IO 공간에 액세스하면 결과 실제 주소는 두 번째 수준 변환에 대한 항목으로, vmmem 프로세스의 페이지 테이블을 사용합니다.

가상화된 환경에서 일반적으로 호스트의 사용자 프로세스 컨텍스트 내에서 실행되는 다양한 KMD DDI 호출은 가상 머신이 실행될 때 vmmem 프로세스의 컨텍스트 내에서 실행됩니다.

Dxgkrnl 이 문서에서 이러한 프로세스를 위한 단일 DXGPROCESS(및 해당 KMD 프로세스 개체)를 만드는데, 이를 VM worker process 라고 합니다. DXG VM 작업자 프로세스와 연결된 EPROCESS는 vmmem입니다.

VM 프로세스

게스트 VM에서 DXGPROCESS를 만들 때 Dxgkrnl 호스트에 해당 DXGPROCESS 개체를 만듭니다. 이 프로세스를 이 문서의 VM 프로세스라고 합니다. DXGPROCESS와 연결된 EPROCESS는 vmmem.

VM 또는 VM 할당 생성의 모든 렌더링 작업은 VM의 DXGPROCESS 컨텍스트에서 수행됩니다.

디버깅 목적으로, DxgkrnlDxgkDdiCreateProcess에서 어느 프로세스가 VM 작업자 프로세스 또는 VM 프로세스인지 KMD에 알립니다. 이 정보를 사용하여 드라이버는 VM 프로세스를 VM 작업자 프로세스에 연결할 수 있습니다. 이 정보는 둘 이상의 VM이 실행되는 시나리오에서 디버깅하는 데 도움이 됩니다.

드라이버 요구 사항

GPU 패러버추얼라이제이션을 지원하는 KMD는 DXGK_VIDMMCAPS::ParavirtualizationSupported 기능을 설정해야 합니다.

UMD(사용자 모드 드라이버)는 프라이빗 드라이버 데이터(포인터, 핸들 등)에서 프로세스 컨텍스트 관련 데이터를 사용하면 안 됩니다. 대신 KMD는 다른 프로세스 컨텍스트에서 호스트의 프라이빗 데이터를 가져옵니다.

게스트의 UMD는 호스트의 KMD와 메모리를 공유할 수 없습니다. UMD 레지스트리 액세스에 설명된 함수를 사용하여 레지스트리에 액세스해야 합니다.

현재 매개 변수화 구현은 VM 버스를 사용하여 게스트와 호스트 간에 통신합니다. 최대 메시지 크기는 128KB입니다. 현재 Dxgkrnl은 메시지를 나누어 청크로 보내지 않습니다. 따라서 드라이버는 개체 생성을 통해 전달되는 개인 데이터의 크기를 제한해야 합니다. 예를 들어 Pfnd3dddiAllocatecb 사용하여 많은 할당을 만드는 경우 총 메시지 크기에는 헤더, 전역 프라이빗 데이터 및 할당당 개인 데이터의 크기와 할당 수를 곱한 크기가 포함됩니다. 이 정보는 모두 단일 메시지에 맞아야 합니다.

전체 화면 에뮬레이트 모드에서 애플리케이션 실행

간접 디스플레이 어댑터는 원격을 사용하도록 설정해야 합니다(기본적으로 사용하도록 설정됨). 사용하지 않도록 설정하려면 다음 단계를 수행합니다.

  • 그룹 정책 편집 시작
  • 컴퓨터 구성->관리 템플릿->Windows 구성 요소->원격 데스크톱 서비스->원격 데스크톱 세션 호스트->원격 세션 환경으로 이동합니다.
  • "원격 데스크톱 연결에 WDDM 그래픽 디스플레이 드라이버 사용" 항목을 엽니다.
  • 사용 안 함을 선택하고 확인을 선택하세요.
  • 재부팅

VM의 전체 화면 애플리케이션에 대한 DXGI 지원은 기본적으로 사용하도록 설정됩니다. 사용하지 않도록 설정하려면 StagingTool.exe /disable 19316777사용합니다.

전체 화면 애플리케이션은 에뮬레이트된 전체 화면 모드에서 실행되어야 합니다.

모든 DXGI 애플리케이션에 eFSE를 사용하도록 설정하고 교환 효과 전환을 위해 최소 WDDM 버전을 WDDM 2.0으로 설정합니다.

  • D3DEnableFeature.exe /enable DXGI_eFSE_Enablement_Policy
  • D3DEnableFeature.exe /setvariant DXGI_eFSE_Enablement_Policy 7

eFSE는 D3D9 애플리케이션에 대해 기본적으로 사용하도록 설정됩니다.

VM의 DriverStore

호스트의 드라이버 이진 파일은 드라이버 저장소 %windir%\system32\drivers\DriverStore\FileRepository<DriverDirectory>있습니다.

반가상화의 경우 VM에서 UMD의 이진 파일은 %windir%\system32\drivers\HostDriverStore\FileRepository<DriverDirectory>위치해야 합니다.

호스트 KMD는 드라이버 저장소에 대한 전체 경로가 있는 UMD DLL의 이름을 보고합니다. 예를 들어 c:\windows\system32\DriverStore\FileRepository\DriverSpecificDirectory\d3dumd.dll.

VM에서 UMD 이름을 요청하면 이름이 <VmSystemDrive>:\windows\system32\HostDriverStore\FileRepository\DriverSpecificDirectory\d3dumd.dll로 변환됩니다.

컨테이너용 호스트 DriverStore

컨테이너의 경우 Hyper-V 호스트의 전체 호스트 드라이버 저장소 디렉터리를 컨테이너의 <%windir%\HostDriverStore 매핑합니다.

전체 VM에 대한 호스트 DriverStore

가상 GPU 어댑터가 VM에서 시작될 때 드라이버 저장소 파일이 VM에 복사됩니다. 이 기능은 릴리스된 OS 버전에서 사용할 수 없습니다.

다음 레지스트리 키와 가능한 값은 복사 작업을 제어합니다. 키는 기본적으로 존재하지 않습니다.

DWORD RTL_REGISTRY_CONTROL\GraphicsDrivers\DriverStoreCopyMode
설명
0 드라이버 저장소 복사 사용 안 함
1 정상적인 작업(드라이버 저장소 파일의 복사를 사용하도록 설정하고 기존 파일을 덮어쓰지 않음).
2 드라이버 저장소의 복사를 사용하도록 설정하고 기존 파일을 덮어씁 수 있습니다.

UMD에서 레지스트리 액세스

KMD 레지스트리 키는 호스트에 있으며 VM에 반영되지 않습니다. 따라서 UMD는 이러한 드라이버 레지스트리 키를 직접 읽을 수 없습니다. pfnQueryAdapterInfoCb2 콜백이 D3D 런타임의 D3DDDI_ADAPTERCALLBACKS 구조에 추가됩니다. UMD는 다음과 같이 설정된 D3DDDICB_QUERYADAPTERINFO2 사용하여 pfnQueryAdapterInfoCb2 호출하여 특정 레지스트리 키를 읽을 수 있습니다.

  • D3DDDICB_QUERYADAPTERINFO2::QueryTypeD3DDDI_QUERYADAPTERTYPE_QUERYREGISTRY로 설정됩니다.
  • pPrivateDriverData 레지스트리 정보를 반환할 D3DDDI_QUERYREGISTRY_INFO 구조의 버퍼를 가리킵니다. UMD는 다음 멤버를 채웁니다.
  • PrivateDriverDataSize은(는) sizeof(D3DDDI_QUERYREGISTRY_INFO)에 동적 크기 출력 값의 버퍼 크기를 더한 값입니다.

UMD는 D3DKMTQueryAdapterInfo 직접 호출할 수도 있습니다. 호스트로 마샬링되어 특정 이름을 게스트 이름 공간으로 변환하는 방법을 제공하기 때문에, 이 호출은 게스트의 UMD에서 유용합니다.

D3DKMTQueryAdapterInfo은 특정 레지스트리 키를 읽기 위해 다음과 같이 설정된 D3DKMT_QUERYADAPTERINFO와 함께 호출됩니다.

  • 형식KMTQAITYPE_QUERYREGISTRY로 설정됩니다.
  • pPrivateDriverDataD3DKMT_ADAPTERREGISTRYINFO 구조를 가리킵니다.
  • PrivateDriverDataSize 동적 크기 출력 값의 버퍼 크기에 sizeof(D3DKMT_ADAPTERREGISTRYINFO)를 더한 값입니다.

예제 1: 서비스 키에서 값 읽기


WCHAR ValueName = L"EnableDebug";
    D3DDDI_QUERYREGISTRY_INFO Args = {};
    Args.QueryType = D3DDDI_QUERYREGISTRY_SERVICEKEY;
    Args.QueryFlags.TranslatePath = FALSE or TRUE;
    Args.ValueType = Supported registry value type;
    wcscpy_s(Args.ValueName, ARRAYSIZE(Args.ValueName), ValueName);

    D3DKMT_QUERYADAPTERINFO Args1 = {};
    Args1.hAdapter = hAdapter;
    Args1.Type = KMTQAITYPE_QUERYREGISTRY;
    Args1.pPrivateDriverData = &Args;
    Args1.PrivateDriverDataSize = sizeof(Args);
    NTSTATUS Status = D3DKMTQueryAdapterInfo(&Args1);
    if (NT_SUCCESS(Status) &&
        Args.Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
    {
       if (ValueType == REG_SZ || ValueType == REG_EXPAND_SZ) {

wprintf(L"Value: \"%s\"\n", Args.OutputString);
       } else
       if (ValueType == REG_MULTI_SZ) {
          wprintf(L"Value: ");
          for (UINT i = 0; i < Args.OutputValueSize; i++) {
             if (Args.OutputString[i] == 0) {
                wprintf(L" ");
             } else {
                wprintf(L"%c", Args.OutputString[i]);
             }
          }
          wprintf(L"\n");
       } else
       if (ValueType == REG_DWORD) {
          wprintf(L"Value: %d\n", Args.OutputDword);
       } else
       if (ValueType == REG_QWORD) {
          wprintf(L"Value: 0x%I64x\n", Args.OutputQword);
       } else
       if (ValueType == REG_BINARY) {
          wprintf(L"Num bytes: %d\n", Args.OutputValueSize);

for (UINT i = 0; i < Args.OutputValueSize; i++) {
             wprintf(L"%d ", Args.OutputBinary[i]);
          }
          wprintf(L"\n");
       }
    }

예제 2: 드라이버 저장소 경로 읽기

    D3DDDI_QUERYREGISTRY_INFO Args = {};
    Args.QueryType = D3DDDI_QUERYREGISTRY_DRIVERSTOREPATH;

    D3DKMT_QUERYADAPTERINFO Args1 = {};
    Args1.hAdapter = hAdapter;
    Args1.Type = KMTQAITYPE_QUERYREGISTRY;
    Args1.pPrivateDriverData = &Args;
    Args1.PrivateDriverDataSize = sizeof(Args);
    NTSTATUS Status = D3DKMTQueryAdapterInfo(&Args1);
    if (NT_SUCCESS(Status) &&
        Args.Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
    {
        Args.OutputString holds the output NULL terminated string.
        Args.OutputValueSize holds the number of characters in the string
    }

VM에서 %windir%\system32%windir%\syswow64로 파일을 복사하기

경우에 따라 드라이버 사용자 모드 DLL이 %windir%\system32 있어야 하고 \syswow64 디렉터리에%windir%.

OS는 드라이버가 호스트의 드라이버 저장소에서 \system32 또는 %windir%\syswow64%windir%위해 복사해야 하는 파일을 지정할 수 있는 방법을 제공합니다.

설치 INF에서 드라이버는 그래픽 어댑터 레지스트리 키의 다음 하위 키에 여러 값을 정의할 수 있습니다.

  1. copyToVmOverwrite
  2. CopyToVmWhenNewer
  3. CopyToVmOverwriteWow64
  4. CopyToVmWhenNewerWow64

CopyToVmOverwriteCopyToVmWhenNewer 하위 키는 파일을 %windir%\system32 디렉터리에 복사하는 데 사용됩니다.

CopyToVmOverwriteWow64CopyToVmWhenNewerWow64 하위 키는 파일을 %windir%\syswow64 디렉터리에 복사하는 데 사용됩니다.

CopyToVmOverwriteCopyToVmOverwriteWow64 아래의 파일들은 항상 대상의 파일들을 덮어씁니다.

CopyToVmWhenNewerCopyToVmWhenNewerWow64 아래의 파일은 파일 변경 날짜가 최신인 경우에만 대상의 파일을 덮어쓸 있습니다. "최신" 조건은 다음 두 가지 정보를 비교합니다.

  • 파일 버전
  • 마지막 쓰기 시간

대상 파일이 .dll 또는 .exe 접미사로 끝나면 FileVersion은 가장 큰 버전이 "최신"으로 간주되는 가장 중요한 비교 값으로 사용됩니다. 대상 파일이 .dll 또는 .exe 접미사로 끝나지 않거나 두 FileVersion이 같으면, 따라서 LastWriteTime은 더 늦은 날짜/시간이 "최신"으로 간주되는 가장 덜 중요한 비교 값으로 사용됩니다.

하위 키 아래의 각 값 형식은 REG_MULTI_SZ 또는 REG_SZ 합니다. 값 형식이 REG_MULTI_SZ 경우 값에 최대 두 개의 문자열이 있어야 합니다. 이 요구 사항은 각 값이 단일 문자열 또는 두 번째 문자열이 비어 있을 수 있는 문자열 쌍을 정의한다는 것을 의미합니다.

쌍에서 첫 번째 이름은 드라이버 저장소의 파일 경로입니다. 경로는 드라이버 저장소의 루트를 기준으로 하며 하위 디렉터리를 포함할 수 있습니다.

쌍의 두 번째 이름은 %windir%\system32 또는 %windir%\syswow64 디렉터리에 표시되어야 하는 파일의 이름입니다. 두 번째 이름은 경로를 포함하지 않고 파일 이름이어야 합니다. 두 번째 이름이 비어 있으면 파일 이름은 드라이버 저장소(하위 디렉터리 제외)와 동일합니다.

이 방법을 사용하면 드라이버가 호스트 드라이버 저장소 및 게스트에서 서로 다른 이름을 가질 수 있습니다.

예제 1

다음 예제에서는 OS에서 <DriverStorePath>\CopyToVm\softgpu1.dll%windir%\system32\softgpu2.dll로 복사하도록 하는 방법을 보여줍니다.

INF [DDInstall] section
HKR,"softgpukmd\CopyToVmOverwrite",SoftGpuFiles,%REG_MULTI_SZ%,"CopyToVm\softgpu1.dll”, “softgpu2.dll”
The directive creates the registry key in the software (adapter) key:
"HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwrite”, SoftGpuFiles = REG_MULTI_SZ, “CopyToVm\softgpu1.dll”, “softgpu2.dll"

예제 2

다음 예제는 OS에서 <DriverStorePath>\softgpu1.dll%windir%\system32\softgpu.dll로, <DriverStorePath>\softgpu2.dll%windir%\system32\softgpu2.dll로 복사하는 방법을 보여줍니다.

INF [DDInstall] section:
HKR,"CopyToVmOverwrite",SoftGpuFiles1,%REG_MULTI_SZ%,"softgpu1.dll”,”softgpu.dll"
HKR,"CopyToVmOverwrite",SoftGpuFiles2,%REG_SZ%, “softgpu2.dll"
The directive creates the registry key in the software (adapter) key:
“HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwrite”,  SoftGpuFiles1 = REG_MULTI_SZ, “softgpu1.dll”, “softgpu.dll"

“HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwrite”,  SoftGpuFiles2 = REG_SZ, “softgpu2.dll””

예제 3

다음 예제에서는 OS가 <DriverStorePath>\Subdir1\Subdir2\softgpu2wow64.dll%windir%\syswow64\softgpu.dll으로 복사하고 <DriverStorePath>\softgpu.dll%windir%\syswow64\softgpu2wow64.dll으로 복사하는 방법을 보여줍니다.

INF [DDInstall] section:
HKR,"CopyToVmOverwriteWow64",SoftGpuFiles,%REG_MULTI_SZ%,“Subdir1\Subdir2\softgpu2wow64.dll”,”softgpu.dll”.
The directive creates the registry key in the software (adapter) key:
“HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\<number>\CopyToVmOverwriteWow64”,  SoftGpuFiles = REG_MULTI_SZ, “Subdir1\Subdir2\softgpu2wow64.dll”,”softgpu.dll

DxgkDdiCreateProcess에 대한 변경 내용

KMD의 DxgkDdiCreateProcess 함수는 VM 작업자 프로세스 및 VM 프로세스를 지원하도록 업데이트해야 합니다. 다음 필드가 DXGKARG_CREATEPROCESS 구조에 추가됩니다.

  • hKmdVmWorkerProcess
  • processNameLength
  • pProcessName

VM 작업자 프로세스 및 VM 프로세스를 지원하기 위해 다음 플래그가 DXGK_CREATEPROCESSFLAGS 추가됩니다.

  • 가상머신프로세스
  • VirtualMachineWorkerProcess

DxgkDdiSetVirtualMachineData

DxgkDdiSetVirtualMachineData는 가상 머신 정보를 KMD에 전달하기 위해 Dxgkrnl에 추가되었습니다.

호스트에 대한 비동기 VM 버스 메시지

게스트 OS의 Dxgkrnl 호스트에 대한 일부 메시지는 비동기적입니다. 이 접근 방식은 게스트 시스템에서 빈번한 Dxgkrnl API 호출 성능을 향상시킵니다. 호스트에 대한 각 동기 VM 버스 메시지의 오버헤드는 높을 수 있습니다.

비동기 메시지는 다음과 같습니다.

GPU-PV LDA 지원

LDA(연결된 디스플레이 어댑터)는 GPU-PV에서 지원됩니다. 일관된 구현을 보장하고 이전 Windows 릴리스에 대한 LDA 지원의 향후 백 포팅을 지원하려면 KMD는 DxgkCbIsFeatureEnabled(DXGK_FEATURE_LDA_GPUPV)호출하여 GPU-PV LDA 지원을 확인해야 합니다. 함수가 성공하고 enabled 반환하는 경우 지원이 활성화됩니다. KMD가 이 콜백을 호출하지 않으면 Dxgkrnl KMD가 GPU-PV에서 LDA를 지원하지 않는다고 가정합니다.

OS에서 이 기능을 지원하는 경우 드라이버가 사용자 모드에서 LDA를 사용하도록 설정해야 합니다. 드라이버가 사용자 모드에서 LDA를 사용하도록 설정하는 경우 다음과 같이 해야 합니다.

실행 시간 LDA 상태
D3D12 이전의 런타임 DXGK_FEATURE_LDA_GPUPV 지원되고 게스트 OS가 Windows 11, 버전 22H2(WDDM 3.1) 이상인 경우 사용하도록 설정합니다.
비 DirectX 런타임(Windows) DXGK_FEATURE_LDA_GPUPV 지원되고 게스트 OS가 Windows 11, 버전 22H2(WDDM 3.1) 이상인 경우 사용하도록 설정합니다. OS 버전을 확인하는 대신 UMD는 D3DKMTQueryAdapterInfo(KMTQAITYPE_PHYSICALADAPTERCOUNT)를 호출하고 1보다 큰 실제 어댑터 수를 반환할 때 LDA를 사용하도록 설정할 수 있습니다.
D3D12 런타임(Windows) 활성화하세요. D3D12 런타임대한 LDA 상태 설정을 참조하세요.
Linux(d3d12 및 비 DX 런타임) DXGK_FEATURE_LDA_GPUPV 지원되는 경우 사용하도록 설정합니다.

인터페이스 버전이 DXGKDDI_INTERFACE_VERSION_WDDM3_0보다 낮은 드라이버는 DXGK_FEATURE_LDA_GPUPV을 확인하지 않습니다. 이러한 드라이버는 여전히 Linux 런타임에 대해 LDA를 사용하도록 설정할 수 있습니다.

D3D12 런타임에 대한 LDA 상태 설정

D3D12 런타임에 대해 LDA를 사용하거나 사용하지 않도록 설정하는 경우 UMD는 올바른 계층 및 노드 맵 정보를 런타임에 반환해야 합니다. 코드 흐름은 다음과 같습니다.

  • D3D12는 UMD에서 D3D12_CROSS_NODE_SHARING_TIER 한도를 가져옵니다.

  • D3D12는 D3DKMTQueryAdapterInfo(KMTQAITYPE_PHYSICALADAPTERCOUNT)호출하여 Dxgkrnl 실제 어댑터 수를 가져옵니다.

  • D3D12는 pfnQueryNodeMap(PhysicalAdapterCount, &map) 호출하여 논리 노드 인덱스를 실제 노드에 매핑합니다. 이 경우 노드는 실제 어댑터를 의미합니다. UMD는 맵 또는 D3D12DDI_NODE_MAP_HIDE_NODE에서 실제 어댑터 인덱스를 설정하여 노드를 비활성화해야 합니다.

  • pfnQueryNodeMap 결과에 따라 D3D12는 숨겨진 노드를 계산하지 않음으로써 효과적인 실제 어댑터 수를 계산합니다.

  • 계층의 상태와 유효 물리적 어댑터 수가 일치하지 않으면 D3D12는 디바이스 생성에 실패합니다. 불일치는 다음과 같은 경우에 발생합니다.

    • 계층이 D3D12DDI_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED이고 어댑터 수가 1보다 크다.
    • 계층은 D3D12DDI_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED이 아니며 어댑터 수는 1입니다.

LDA를 사용하지 않도록 설정하려면 UMD가 D3D12DDI_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED 계층을 반환하고 노드 맵에서 하나의 물리적 어댑터만 사용하도록 설정해야 합니다.

D3DKMTQueryAdapterInfo(KMTQAITYPE_PHYSICALADAPTERCOUNT)

실제 어댑터 수에 대한 KMTQAITYPE_PHYSICALADAPTERCOUNT 쿼리는 항상 게스트에 올바른 실제 어댑터 수를 반환합니다.

  • Windows 11 이전 버전 22H2 게스트에서는 1을 반환합니다. 이 값은 게스트 코드에서 하드 코딩됩니다. LDA 지원이 이전 OS 릴리스로 이식되는 경우 나중에 변경될 수 있습니다.
  • Windows 11 버전 22H2 이상 시스템에서는 다음을 반환합니다.
    • DXGK_FEATURE_LDA_GPUPV 사용하도록 설정된 실제 어댑터의 실제 수입니다.
    • 그렇지 않으면 1입니다.

파라가상화가 설정됩니다.

BIOS(VT-d 또는 이와 유사한)에서 가상화 지원을 사용하도록 설정합니다. GPU-PV 설정은 VMMS 가상 머신 및 컨테이너에 대해 다릅니다.

PowerShell(관리자 권한으로 실행)에서 서버에서 스크립트 실행을 사용하도록 설정합니다.

set-executionpolicy unrestricted

VMMS 가상 머신 설정

호스트 및 VM 설정

VM의 OS 빌드는 호스트의 OS 빌드보다 오래되거나 최신일 수 있습니다.

  1. 서버 역할 또는 클라이언트의 Hyper-V 기능에서 Hyper-V 기능을 사용하도록 설정합니다. 서버에서 이 기능을 사용하도록 설정하는 경우 네트워크 어댑터를 외부 스위치로 사용하는 옵션을 선택합니다.

  2. (선택 사항) 테스트 서명 사용(bcdedit -set TESTSIGNING ON)

  3. 재부팅.

  4. 파라 가상화를 지원하는 GPU 드라이버를 설치합니다.

  5. (선택 사항) 일부 드라이버는 ParavirtualizationSupported 상한을 설정하지 않습니다. 이 경우 드라이버를 설치하기 전에 다음 레지스트리를 추가하거나 플래그가 설정된 후 기기를 비활성화하거나 활성화합니다.

    DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\GpuVirtualizationFlags = 1   
    
  6. 운영 체제(OS)가 준가상화된 GPU를 인식하는지 확인하려면 다음 PowerShell 명령을 실행합니다.

    Get-VMPartitionableGpu
    
    # Example output from running the command
    Name                    : \\?\PCI#VEN_10DE&DEV_1C02&SUBSYS_11C210DE&REV_A1#4&275d7527&0&0010#{064092b3-625e-43bf-9eb5-d
                              c845897dd59}\GPUPARAV
    ValidPartitionCounts    : {32}
    PartitionCount          : 32
    TotalVRAM               : 1,000,000,000
    AvailableVRAM           : 1,000,000,000
    MinPartitionVRAM        : 0
    MaxPartitionVRAM        : 1,000,000,000
    OptimalPartitionVRAM    : 1,000,000,000
    TotalEncode             : 18,446,744,073,709,551,615
    AvailableEncode         : 18,446,744,073,709,551,615
    MinPartitionEncode      : 0
    MaxPartitionEncode      : 18,446,744,073,709,551,615
    
    OptimalPartitionEncode  : 18446744073709551615
    TotalDecode             : 1000000000
    AvailableDecode         : 1000000000
    MinPartitionDecode      : 0
    MaxPartitionDecode      : 1000000000
    OptimalPartitionDecode  : 1000000000
    TotalCompute            : 1000000000
    AvailableCompute        : 1000000000
    MinPartitionCompute     : 0
    MaxPartitionCompute     : 1000000000
    OptimalPartitionCompute : 1000000000
    CimSession              : CimSession: .
    ComputerName            : MYCOMPUTER-TEST2
    IsDeleted               : False
    
  7. PowerShell에서 다음 명령을 실행하여 GPU를 사용하여 VM을 만듭니다. TEST라는 VM이 만들어집니다.

    $vm = “TEST“
    New-VM -VMName $vm -Generation 2
    Set-VM -GuestControlledCacheTypes $true -VMName $vm
    
  8. VM에 대한 IO 공간을 설정합니다. GPU-PV은 CPU에서 볼 수 있는 할당을 처리하기 위해 IO 공간을 사용합니다. 8GB 이상의 IO 공간이 필요합니다.

    Set-VM -LowMemoryMappedIoSpace 1GB -VMName $vm
    Set-VM -HighMemoryMappedIoSpace 16GB -VMName $vm
    
  9. [선택 사항] 기본적으로 높은 메모리 IO 공간의 기본 주소는 (64GB - 512MB)로 설정됩니다. 36비트 실제 메모리 주소가 있는 Haswell 칩셋에서 IO 공간 영역의 끝 주소는 64GB 미만이어야 하므로 시작 주소를 적절하게 설정해야 합니다. SetHighMmioBase.ps1이라는 다음 스크립트는 다음 매개 변수를 사용하여 실행할 때 시작 주소를 47GB로 설정합니다.

    SetHightMmioBase.ps1 “TEST” 48128
    
    # SetHighMmioBase.ps1
    
    param( [string]$VmName, $BaseInMB)
    
    function Get-WMIVM
    {
        [CmdletBinding()]
        param(
            [parameter(Mandatory=$true)]
            [ValidateNotNullOrEmpty()]
            [string]$VmName = ""
            )
    
        gwmi -namespace root\virtualization\v2 -query "select * from Msvm_ComputerSystem where ElementName = '$VmName'"
    }
    function Get-WMIVmSettingData
    {
        [CmdletBinding()]
        param(
            [parameter(Mandatory=$true)]
            [ValidateNotNullOrEmpty()]
            [string]$VmName = ""
            )
        $vm = Get-WMIVM $VmName
    
        return $vm.GetRelated ("Msvm_VirtualSystemSettingData","Msvm_SettingsDefineState",$null,$null, "SettingData", "ManagedElement", $false, $null)
    }
    
    Write-Host "Setting HighMmioGapBase to $BaseInMB for VmName $VmName"
    $vssd = Get-WMIVmSettingData $VmName
    $vmms = Get-WmiObject -Namespace "root\virtualization\v2" -Class Msvm_VirtualSystemManagementService
    $vssd.HighMmioGapBase = $BaseInMB
    $settingsText = $vssd.PSBase.GetText("CimDtd20")
    $ret=$vmms.ModifySystemSettings($settingsText).ReturnValue
    if ($ret -eq 0)
    {
       Write-Host "Successfully set" $vssd.HighMmioGapBase
    } else
    {
       Write-Host "Error $ret"
    }
    
  10. VM에 가상 GPU를 추가하고 검사점을 사용하지 않도록 설정합니다.

    Add-VMGpuPartitionAdapter -VMName $vm
    Set-VM -CheckpointType Disabled -VMName $vm
    
  11. VM에 반가상화된 GPU가 있는지 확인하려면 다음 명령을 실행합니다.

    Get-VMGpuPartitionAdapter -VMName $vm in PowerShell. The output should show the adapter.
    
    
    # Example output from running the command
    
    MinPartitionVRAM        :
    MaxPartitionVRAM        :
    OptimalPartitionVRAM    :
    MinPartitionEncode      :
    MaxPartitionEncode      :
    OptimalPartitionEncode  :
    MinPartitionDecode      :
    MaxPartitionDecode      :
    OptimalPartitionDecode  :
    MinPartitionCompute     :
    MaxPartitionCompute     :
    OptimalPartitionCompute :
    Name                    : GPU Partition Settings
    Id                      : Microsoft:9ABB95E2-D12D-43C3-B840-6F4A9CFB217B\929890BC-BB33-4687-BC1A-F72A4F1B3B3F
    VMId                    : 9abb95e2-d12d-43c3-b840-6f4a9cfb217b
    VMName                  : TEST
    VMSnapshotId            : 00000000-0000-0000-0000-000000000000
    VMSnapshotName          :
    
    CimSession              : CimSession: .
    ComputerName            : MYCOMPUTER-TEST2
    IsDeleted               : False
    VMCheckpointId          : 00000000-0000-0000-0000-000000000000
    VMCheckpointName        :
    
  12. VM에서 사용하는 동일한 클라이언트 빌드의 VHDX를 호스트 디렉터리에 복사합니다. 예를 들어 d:\VM\os.vhdx.

  13. Hyper-V 관리자를 열고 VM 매개 변수를 수정합니다(VM을 선택하고 설정을 선택).

    • 보안 - 보안 부팅활성화 선택을 취소합니다.
    • 메모리 - 확인 후동적 메모리를 활성화합니다. 메모리 양을 1,024MB 이상으로 설정합니다.
    • 프로세서 - 가상 프로세서 수 2 또는 4로 설정합니다.
    • 네트워크 어댑터 - 드롭아웃 상자에서 VM과 함께 사용할 네트워크 어댑터를 선택합니다. 네트워크 디버깅을 사용하는 경우 Microsoft 디버깅 NET 어댑터를 선택해야 합니다.
    • SCSI 컨트롤러 - 하드 드라이브 - 추가 - 가상 하드 디스크 - 찾아보기 - d:\VM\os.vhdx 선택
  14. OS는 어댑터가 게스트에서 초기화될 때 호스트 드라이버 저장소에서 게스트의 HostDriverStore 디렉터리로 파일을 복사합니다.

    • VM의 VHDX를 탑재합니다. 예를 들어 디스크 f:에 연결합니다.
    • 탑재된 VM에서 f:\%windir%\system32\HostDriverStore\FileRepository디렉터리를 만듭니다.
    • 호스트의 %windir%\system32\DriverStore VM으로 드라이버 파일을 복제합니다. VM에는 f:\%windir%\system32\HostDriverStore\FileRepository\YourDriverDirectory\*가 있어야 합니다.
  15. 드라이버가 %windir%\system32 또는 %windir%\syswow64파일에 액세스해야 하는 경우 파일을 VM에 수동으로 복사합니다.

  16. 드라이버가 Microsoft 서명되지 않은 경우 VM에서 테스트 서명을 사용하도록 설정합니다. CMD 관리 창에서 다음 명령을 실행합니다.

    bcdedit /store <VM drive>:\EFI\Microsoft\Boot\BCD -set {bootmgr} testsigning on
    

    VM의 VHDX를 분리합니다.

  17. VM을 시작합니다.

  18. Hyper-V 관리자 연결 옵션을 사용하여 VM에 연결합니다.

VM 내부

VM의 디바이스 관리자에 Virtual Render 디바이스가 있는지 확인합니다. VM 내의 모든 렌더링은 가상 GPU를 통과합니다.

VM을 설정하는 PowerShell 스크립트

다음 PowerShell 스크립트는 VM을 처음부터 설정하는 방법의 예입니다. 요구 사항에 맞게 수정합니다.


Param(
   [string]$VMName,
   [string]$VHDPath,
   [string]$SwitchName,
   [switch]$CreateVm,
   [switch]$InitDebug,
   [switch]$CopyRegistry,
   [switch]$CopyDriverStore,
   [switch]$CreateSwitch,
   [switch]$AddGpu,
   [switch]$All
)

if($All)
{
   $CreateVm = $True
   $CreateInitDebug = $True
   $CopyRegistry = $True
   $CopyDriverStore = $True
   $CreateSwitch = $True
   $AddGpu = $True
   $InitDebug = $True
}

   $vm = $VMName

#
# Validate parameters
#
if ($CreateSwitch -or $CreateVM)
{
    if ($SwitchName -eq "")
    {
        write "SwitchName is not set"
        exit
    }
}

if ($AddGpu -or $CreateVM)
{
    if ($VMName -eq "")
    {
        write "VMName is not set"
        exit
    }
}

if ($InitDebug -or $CreateVM -or $CopyDriverStore -or $CopyRegistry)
{
    if ($VHDPath -eq "")
    {
        write "VHDPath is not set"
        exit
    }
}

enable-windowsoptionalfeature -FeatureName Microsoft-Hyper-V-All -online

#
# Create a network switch for the VM
#
if ($CreateSwitch)
{
    New-VMSwitch $SwitchName -NetAdapterName "Ethernet (Kernel Debugger)"
}

#
# Create a VM and assign VHD to it
#
if ($CreateVm)
{
   New-VM -VMName $vm -Generation 2
   Set-VM -GuestControlledCacheTypes $true -VMName $vm


Set-VM -LowMemoryMappedIoSpace 1Gb -VMName $vm
   Set-VM -HighMemoryMappedIoSpace 32GB -VMName $vm
   Set-VMProcessor -VMname $vm -count 4
   Set-VMMemory -VMName $vm -DynamicMemoryEnabled $true -MinimumBytes 1024MB -MaximumBytes 4096MB -StartupBytes 1024MB -Buffer 20
   Add-VMHardDiskDrive -VMName $vm -Path $VHDPath
   Connect-VMNetworkAdapter -VMName $vm -Name "Network Adapter" -SwitchName $SwitchName
   Set-VMFirmware -VMName $vm -EnableSecureBoot off
   Set-VMFirmware -VMName $vm -FirstBootDevice (Get-VMHardDiskDrive -VMName $vm)
}

#
# Enable debugger and testsiging
#
if ($InitDebug)

```powershell
{
   Mount-vhd $VHDPath
   Add-PartitionAccessPath  -DiskNumber (Get-DiskImage -ImagePath $VHDPath | Get-Disk).Number -PartitionNumber 1 -AssignDriveLetter
   $efidrive = (Get-DiskImage -ImagePath $VHDPath | Get-Disk | Get-Partition -PartitionNumber 1).DriveLetter
   bcdedit /store ${efidrive}:\EFI\Microsoft\Boot\BCD -set '{bootmgr}' testsigning on
   bcdedit /store ${efidrive}:\EFI\Microsoft\Boot\BCD -set '{default}' debug on
   bcdedit /store ${efidrive}:\EFI\Microsoft\Boot\BCD /dbgsettings net port:50052 key:a.b.c.d hostip:10.131.18.133
   Dismount-VHD $VHDPath
}

#

# Now boot the VM without vGPU to verify that it's initialized correctly
# If everything is OK, turn off the VM
#
if ($CreateVm)
{
   Write-Output "Boot the VM and turn it OFF after it's initialized"
   pause
}

#
# Add virtual GPU
#
if($AddGpu)
{
   Add-VMGpuPartitionAdapter -VMName $vm
   Get-VMGpuPartitionAdapter -VMName $vm
}

#
# Copy the driver store to the VM
#
if ($CopyDriverStore)
{
   Write "Copying driver store"
   Mount-vhd $VHDPath
   $drive = (Get-DiskImage -ImagePath $VHDPath | Get-Disk | Get-Partition -PartitionNumber 3).DriveLetter
   xcopy /s $Env:windir\system32\driverstore\* ${drive}:\windows\system32\hostdriverstore\


Dismount-VHD $VHDPath
}

#
# Export driver registry settings
#
if ($CopyRegistry)
{
   Write "Copying registry"
   Mount-vhd $VHDPath
   $drive = (Get-DiskImage -ImagePath $VHDPath | Get-Disk | Get-Partition -PartitionNumber 3).DriveLetter
   reg load HKLM\VMSettings ${drive}:\Windows\System32\config\SYSTEM
   reg copy "HKLM\System\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000" "HKLM\VmSettings\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000" /s /f
   reg unload "HKLM\VmSettings"
   Dismount-VHD $VHDPath
}

VM 디버깅

일반 클라이언트 컴퓨터에서 네트워크 디버깅과 동일한 방식으로 VM 디버거를 구성합니다.

VM이 시작되지 않거나 검은색 화면이 표시되는 경우:

  • 다음 명령을 사용하여 VM을 끄고 가상 GPU를 제거합니다.

    $vm = “TEST“
    remove-VMGpuPartitionAdapter  -VMName $vm -AdapterId “<Id from Get-VMGpuPartitionAdapter>”
    

    예를 들어:

    remove-VMGpuPartitionAdapter  -VMName $vm -AdapterId “Microsoft:9ABB95E2-D12D-43C3-B840-6F4A9CFB217B\929890BC-BB33-4687-BC1A-F72A4F1B3B3F”
    
  • VM을 시작합니다. 성공적으로 시작되면 드라이버 파일이 VM의 HostDriverStore에 올바르게 복사되었는지 확인합니다.

  • Add-VMGpuPartitionAdapter 명령을 사용하여 VM에 vGPU를 추가합니다.

  • VM을 다시 시작합니다.

자세한 내용은 문제 해결 참조하세요.

컨테이너 설정

컨테이너(HCS(호스트 컴퓨팅 시스템 ) VM이라고도 함)와 전체 VM 간의 차이점은 OS 이진 파일과 드라이버 저장소 파일이 컨테이너에 매핑된다는 점입니다. 따라서 windows\system32 디렉터리에 필요한 경우가 아니면 드라이버 파일을 컨테이너에 복사할 필요가 없습니다.

보안 컨테이너의 경우:

  • 드라이버 이스케이프를 사용할 수 없습니다.
  • 드라이버는 보안 컨테이너 내에서 사용하도록 설정하려면 IOMMU 격리를 지원해야 합니다.

호스트에서 드라이버를 업데이트하고 호스트 GPU를 시작하거나 중지하면 변경 내용이 컨테이너에 반영됩니다.

Windows 샌드박스

이 컨테이너 유형은 위험한 애플리케이션을 시도하는 데 사용됩니다. 전체 데스크톱 이미지가 호스트에 원격으로 표시됩니다. 간접 디스플레이 드라이버는 원격 연결에 사용됩니다. 그래픽 VAIL은 사용되지 않으므로 데스크톱 이미지를 호스트로 가져오는 속도가 느립니다.

가상 GPU는 Windows 샌드박스에서 기본적으로 사용하지 않도록 설정됩니다. 이를 사용하도록 설정하려면 WSB 구성 파일(예: config.wsb )을 만들고 가상 GPU 옵션을 설정합니다. 구성 파일을 클릭하여 샌드박스를 시작합니다.

구성 파일 예제:

<Configuration>
    <VGpu>Enable</VGpu>
</Configuration>

기본적으로 컨테이너의 vGPU에는 드라이버 이스케이프를 사용할 수 없습니다. 드라이버 이스케이프를 사용하도록 설정하는 구성 옵션이 있습니다. 다음 WSB 파일 예제에서는 샌드박스에서 vGPU와 드라이버 이스케이프를 모두 사용하도록 설정합니다.

<Configuration>
    <VGpu>EnableVendorExtensions</VGpu>
</Configuration>

Windows 샌드박스는 GPU 어댑터 "핫 플러그"를 지원합니다.

VAIL(Virtual Application Integrated Locally) 컨테이너

이 컨테이너 유형을 사용하여 WCOS(Windows Core 운영 체제) 기반 호스트 내에서 Win32 애플리케이션을 실행합니다. 컨테이너에 있는 각 애플리케이션의 이미지가 호스트에 원격으로 표시됩니다. 그래픽 VAIL은 각 애플리케이션 스왑 체인을 원격으로 설정할 수 있습니다. 드라이버 이스케이프를 사용할 수 있습니다.

일반적인 컨테이너 요구 사항

머신 요구 사항은 다음과 같습니다.

  • Vtx와 Vtd는 모두 BIOS(또는 해당 항목: AMD-V, AMD-IOMMU)에서 사용하도록 설정해야 합니다.
  • 최소 8GB의 RAM.
  • 5GB 이상의 시스템 디스크 공간.

Windows 샌드박스에 대한 커널 디버거 설정

CMDIAG 사용

cmservice(Container Manager 서비스)는 Hyper-V 격리된 컨테이너를 제어합니다. CMDIAG.EXE Hyper-V 및 컨테이너 기능을 설치할 때 사용할 수 있는 애플리케이션입니다. 컨테이너에 대한 커널 모드 디버깅을 사용하도록 설정하고 테스트 서명 등을 사용하도록 설정합니다.

Container Manager는 직렬 및 NET 디버깅을 지원합니다.

cmdiag.exe Debug 실행하여 옵션을 확인합니다.

CMDIAG 컨테이너 기본 이미지의 디버거 설정을 수정합니다. 커널 디버거를 사용할 때 실행되는 컨테이너의 인스턴스는 하나만 있어야 합니다.

디버거 설정을 변경하기 전에 HVSICS 서비스를 중지합니다.


# Example 1:

C:\Windows\system32>sc stop hvsics
SERVICE_NAME: HVSICS
        TYPE               : 30  WIN32
        STATE              : 3  STOP_PENDING
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x1
        WAIT_HINT          : 0xbb8

C:\Windows\system32>cmdiag debug -on -Serial  -Force
Debugging successfully enabled. Connection string: -k com:pipe,port=\\.\pipe\debugpipe,reconnect -v

# Example 2:

C:\Windows\system32>cmdiag debug -on -net -port 51000 -key a.b.c.d -hostip 10.131.18.34

다른 컴퓨터에서 디버거 실행

직렬 디버거를 사용하는 경우 다른 컴퓨터에서 실행할 수 있습니다. kdsrv.exe 사용하여 다른 컴퓨터에서 디버거를 실행합니다. 자세한 내용은 KD 연결 서버참조하세요.

커널 디버깅 중에 시간 초과를 비활성화하려면 다음 레지스트리 키를 설정합니다.

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\UtilityVm" /v BridgeTransactionTimeout /t REG_DWORD /d 0xffffffff /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\UtilityVm" /v BridgeServerConnectTimeout /t REG_DWORD /d 0xffffffff /f
reg add "HKLM\SOFTWARE\Microsoft\HVSI" /f /v DisableResetContainer /t REG_DWORD /d 1
reg add "HKLM\SOFTWARE\Microsoft\HVSI" /f /v AppLaunchTimeoutInSeconds /t REG_DWORD /d 0x7fffffff
reg add "HKLM\Software\Microsoft\Terminal Server Client" /f /v ConnectionHealthMonitoringSupported /t REG_DWORD /d 0

reg add "HKLM\Software\Microsoft\Terminal Server Client" /f /v DisableUDPTransport /t REG_DWORD /d 1
reg add "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client" /f /v ConnectionHealthMonitoringSupported /t REG_DWORD /d 0
reg add "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client" /f /v DisableUDPTransport /t REG_DWORD /d 1

VAIL 컨테이너에 대한 커널 디버거 설정

  • 텔넷을 사용하여 호스트에 연결합니다. 호스트 OS의 네트워크 설정에서 호스트의 IP 주소를 가져올 수 있습니다.
  • cmdiag.exe 사용하여 디버거를 구성합니다.

하이퍼바이저 디버거 설정

bcdedit /hypervisorsettings NET port:50000 key:a.b.c.d hostip:1.1.1.1
bcdedit /set {hypervisorsettings} hypervisorbusparams 0.0.0 (if needed)
bcdedit /set hypervisordebug on
reboot host

문제 해결

이 섹션에서는 GPU-PV 문제를 해결하는 방법에 대한 정보를 제공합니다.

Get-VMHostPartitionableGpu

Get-VMHostPartitionableGpu 호출하여 가상화된 GPU가 있는지 확인합니다. 출력이 비어 있으면 어딘가에 오류가 발생합니다(드라이버가 가상화 한도를 설정하지 않았으므로 가상화가 활성화되지 않음)

Get-VMHostPartitionableGpu

# Example output from running the command

Name                    : \\?\PCI#VEN_10DE&DEV_1188&SUBSYS_095B10DE&REV_A1#6&cfd27c8&0&00400008#{064092b3-625e-43bf-9eb5-dc845897dd59}\PARAV
ValidPartitionCounts    : {32, 4}
PartitionCount          : 32
TotalVRAM               : 2,000,000
AvailableVRAM           : 1,800,000
MinPartitionVRAM        : 100,000
MaxPartitionVRAM        : 1,000,000
OptimalPartitionVRAM    : 1,000,000
TotalEncode             : 20
AvailableEncode         : 20
MinPartitionEncode      : 1
MaxPartitionEncode      : 5
OptimalPartitionEncode  : 4
TotalDecode             : 40
AvailableDecode         : 30
MinPartitionDecode      : 2


MaxPartitionDecode      : 20
OptimalPartitionDecode  : 15
TotalCompute            : 100
AvailableCompute        : 100
MinPartitionCompute     : 1
MaxPartitionCompute     : 50
OptimalPartitionCompute : 30
CimSession              : CimSession: .
ComputerName            : WIN-T3H0LVHJJ59
IsDeleted               : False

ETW 이벤트 사용

Dxgkrnl ETW 이벤트에 대한 관리자 및 운영 채널이 있습니다. 이벤트는 Windows 이벤트 뷰어: 애플리케이션 및 서비스 로그 - Microsoft - Windows - Dxgkrnl에 표시됩니다.

이벤트 뷰어에는 GPU-PV(Hyper-V-Compute, Hyper-V-Worker, Hyper-V-VID 등)를 사용하여 VM을 만드는 데 참여하는 다른 구성 요소의 이벤트가 있습니다.

Add-VMGpuPartitionAdapter 사용

Add-VMGpuPartitionAdapter사용하는 경우 필요하지 않은 경우 기능(예: 디코딩)을 지정하지 마세요. 이 기능에는 0을 사용하지 마세요.

Remove-VMGpuPartitionAdapter 사용

VM을 시작하지 못하거나 렌더링 문제가 있는 경우 Remove-VMGpuPartitionAdapter사용하여 VM에서 가상 GPU를 제거합니다.

remove-VMGpuPartitionAdapter  -VMName $vm -AdapterId "Microsoft:9ABB95E2-D12D-43C3-B840-6F4A9CFB217B\929890BC-BB33-4687-BC1A-F72A4F1B3B3F"

부팅하는 동안 VM 시작 방지

set-vm -AutomaticStartAction Nothing -VmName TEST

이벤트 뷰어 이벤트

이벤트 뷰어 채널에 이벤트를 추가하여 vGPU 시작 문제를 식별합니다. "Application and Services Logs\Microsoft\Windows\Dxgkrnl"에서 이벤트를 찾을 수 있습니다. 이벤트 채널은 관리 및 운영이라는 두 가지입니다.

이벤트는 다음과 같은 경우에 발생합니다.

  • vGPU가 만들어집니다.
  • vGPU가 제거됨
  • 게스트가 가상 어댑터를 엽니다.

이벤트 파일은 다음과 같습니다.

  • c:\Windows\System32\winevt\Logs\Microsoft-Windows-DxgKrnl-Admin.evtx
  • c:\Windows\System32\winevt\Logs\Microsoft-Windows-DxgKrnl-Operational.evtx

vGPU가 만들어졌는지와 오류가 있는지 확인합니다.

레지스트리 설정

Gpu 가상화 플래그

GpuVirtualizationFlags 레지스트리 키는 파라바이러스화된 GPU의 동작을 설정하는 데 사용됩니다. 키는 다음 위치에 있습니다.

DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\GpuVirtualizationFlags

다음 비트가 정의됩니다.

비트 묘사
0x1 모든 하드웨어 어댑터에 대해 ParavirtualizationSupported 캡을 강제로 적용합니다. 호스트에서 이 비트를 사용합니다.
0x2 BasicRender에 대해 ParavirtualizationSupported 캡을 강제로 적용합니다. 호스트에서 이 비트를 사용합니다.
0x4 모든 가상 머신이 안전한 것으로 처리되는 보안 가상 머신 모드를 강제 적용합니다. 이 모드에서는 사용자 모드 드라이버에 제한이 있습니다. 예를 들어 드라이버는 이스케이프 호출을 사용할 수 없으므로 실패합니다. 호스트에서 이 비트를 사용합니다.
0x8 반가상화된 어댑터를 디스플레이 전용 어댑터와 페어링할 수 있습니다. 게스트 VM에서 이 비트를 사용합니다. 페어링은 기본적으로 사용하도록 설정됩니다.

GuestIoSpace 크기(Mb 단위)

GuestIoSpaceSizeInMb 레지스트리 키는 가상 GPU에 대한 게스트 IO 공간의 크기를 메가바이트 단위로 설정하는 데 사용됩니다. 기본값은 1,000MB(1GB)입니다. 키는 다음 위치에 있습니다.

DWORD HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Paravirtualization\GuestIoSpaceSizeInMb

게스트 IO 공간은 현재 CPU에서 볼 수 있는 할당을 구현하고 있습니다. 호스트의 CPU 표시 할당 백업 저장소는 메모리에 고정되고 게스트 IO 공간에 매핑됩니다. 게스트에서 할당 사용자 모드 가상 주소는 IO 공간 영역으로 회전됩니다. 일부 Haswell 시스템에서 CPU에는 36비트 물리적 주소가 있습니다. 이러한 시스템의 Hyper-V IO 공간 크기가 제한됩니다.

보안 가상 머신에 대해 IOMMU 격리 사용 안 함

드라이버가 IoMmu 격리를 지원하지 않는 경우 개발 중에 다음 레지스트리 설정을 사용하여 IoMmu 격리를 사용하지 않도록 설정합니다.

`DWORD HKLM\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\IoMmuFlags = 8`

가상 함수 수 제한

기본적으로 GPU 매개 변수화를 지원하는 어댑터에 의해 노출되는 가상 함수의 수는 32개입니다. 이 숫자는 각 VM에 하나의 어댑터가 있다고 가정하여 32개의 가상 머신에 어댑터를 추가할 수 있음을 의미합니다.

다음 레지스트리 설정을 사용하여 노출된 가상 함수의 수를 제한할 수 있습니다.

DWORD HKLM\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\NumVirtualFunctions

예를 들어 NumVirtualFunctions 1로 설정하면 어댑터를 한 번만 GPU에 추가할 수 있습니다. 이 설정은 컴퓨터에 GPU-PV 지원하는 여러 GPU 어댑터가 있고 각 어댑터를 VM에 할당하려는 경우에 유용합니다. Add-VMGpuPartitionAdapter 추가할 어댑터를 지정할 수 없습니다. 따라서 두 어댑터가 VM에 추가되면 둘 다 호스트에서 동일한 GPU-PV 어댑터를 가져올 수 있습니다.

WDDM 2.4 DDI 업데이트

다음 DDI 업데이트는 WDDM 2.4에서 GPU 매개 변수화를 지원하기 위해 수행됩니다.

DXGK_VIDMMCAPS 한도 추가됨

ParavirtualizationSupported 기능이 DXGK_VIDMMCAPS 구조체에 추가되었습니다. 호스트 KMD는 이 섹션에 설명된 모든 DD를 구현하는 경우 이 한도를 설정합니다.

DDI를 통해 전달된 드라이버 프라이빗 데이터

UMD는 다양한 DD를 사용하여 해당 KMD와 개인 정보를 교환합니다. 게스트 VM에서 UMD가 실행되면 해당 KMD DDI 호출이 호스트 파티션에서 발생합니다. 따라서 UMD는 다음과 같습니다.

  1. 프라이빗 데이터에 포인터를 전달할 수 없습니다.
  2. 프라이빗 데이터의 핸들을 전달할 수 없습니다.
  3. 이 변경 내용이 다른 실행 중인 VM에 영향을 줄 수 있으므로 KMD에 GPU 상태를 전역으로 변경하도록 지시해서는 안 됩니다.

DxgkDdiCreateProcess에 대한 VirtualMachineProcess 플래그가 추가됨

OS는 실행 중인 각 VM에 대한 VM 작업자 프로세스를 만듭니다. Dxgkrnl 해당 DXGPROCESS를 만들고 VirtualMachineWorkerProcess 플래그가 설정된 상태로 DxgkDdiCreateProcess를 호출합니다. 이 프로세스 컨텍스트에는 렌더링 또는 드라이버 리소스 생성이 없습니다. 따라서 드라이버는 특정 리소스 할당을 건너뛸 수 있습니다.

OS는 GPU를 사용하는 게스트 VM의 모든 프로세스에 대해 호스트에 DXGPROCESS를 만듭니다. DxgkrnlDxgkDdiCreateProcessVirtualMachineProcess 플래그를 설정하여 호출합니다. 각 VM DXG 프로세스는 VM 작업자 프로세스와 동일한 EPROCESS에 속합니다.

DxgkDdiQueryAdapterInfo 업데이트

DXGKARG_QUERYADAPTERINFO 구조체는 매개 변수화 지원을 위해 다음 필드를 포함하도록 업데이트됩니다.

  • Flags 멤버가 추가되어 Dxgkrnl 다음을 나타낼 수 있습니다.

    • 호출이 VM에서 온다는 것을 나타내도록 VirtualMachineData 설정합니다.
    • SecureVirtualMachine 설정하여 VM이 보안 모드에서 실행되었음을 나타냅니다.
  • hKmdProcessHandle 추가되어 드라이버가 게스트 VM에서 시작된 쿼리를 처리할 때 호스트 쪽에서 올바른 프로세스 컨텍스트를 식별하고 사용할 수 있습니다.

DxgkDdiEscape 업데이트

hKmdProcessHandle 멤버는 드라이버가 게스트 VM에서 발생하는 이스케이프를 처리할 때 호스트 쪽에서 올바른 프로세스 컨텍스트를 식별하고 사용할 수 있도록 DXGKARG_ESCAPE 구조체에 추가됩니다.

VirtualMachineData 플래그는 DxgkDdiEscape 가상 머신에서 호출되었음을 나타내기 위해 D3DDDI_ESCAPEFLAGS 구조체에 추가됩니다.

GPU 할당에 대한 물리적 액세스

현재 드라이버는 할당에 대한 물리적 액세스를 구현하지 않습니다. 드라이버는 GpuMmu을 지원해야 합니다.

WDDM 2.5 DDI 업데이트

WDDM 2.5의 경우 매개 변수화 지원에도 다음과 같은 DDI 변경이 필요합니다.

호스트 KMD에 의한 게스트 이벤트 신호

KMD가 UMD에서 만든 이벤트를 신호로 표시해야 하는 경우 가상화 없이 존재하는 시나리오가 있습니다. 매개 변수화를 사용할 때 이러한 시나리오를 처리하려면 호스트의 KMD가 게스트에서 만든 이벤트를 신호로 표시해야 합니다. 이 목적을 위해 DxgkCbSignalEvent 콜백이 추가됩니다. KMD는 이 콜백을 사용하여 호스트 프로세스의 이벤트를 신호로 보낼 수도 있습니다.

VM에서 UMD 제공 핸들 지원

특정 드라이버 콜백은 다음과 같이 UMD가 전달하는 Dxgkrnl 할당 또는 리소스 핸들을 허용합니다.

호스트에 대한 호출은 DxgkDdiXxx 함수를 호출한 동일한 스레드의 컨텍스트에 있어야 합니다.

예를 들어 가상화가 없으면 KMD가 DxgkDdiEscape호출하는 D3DKMTEscape호출하는 사용자 모드 스레드의 컨텍스트에서 DxgkCbAcquireHandleData 호출한다고 가정합니다.

UMD가 가상 머신에서 실행되는 경우 게스트 할당 핸들만 알고 있으며 KMD가 호스트에서 실행되기 때문에 이러한 핸들을 KMD에 전달할 수 없습니다. 게스트에서 D3DKMTEscape를 호출하는 UMD와 호스트에서 해당 DxgkDdiEscape 호출을 받는 KMD. KMD는 이 스레드의 컨텍스트에서 DxgkCbAcquireHandleData 호출해야 합니다.

게스트 할당/리소스 핸들을 해당 호스트 핸들로 변환할 수 있도록 D3DDDI_ESCAPEFLAGS::D riverKnownEscape 드라이버 이스케이프 플래그가 추가됩니다.

DriverKnownEscape 플래그가 설정된 D3DKMTEscape 호출하는 경우:

  • D3DKMT_ESCAPE::TypeD3DKMT_ESCAPE_DRIVERPRIVATE로 설정합니다.

  • D3DKMT_ESCAPE::p PrivateDriverData 다음 섹션에 정의된 알려진 드라이버 이스케이프 구조를 가리키도록 설정합니다. 각 구조체는 D3DDDI_DRIVERESCAPETYPE 값으로 시작합니다.

가상화를 사용하지 않으면 변환된 핸들이 입력 핸들과 동일합니다.

정의된 알려진 드라이버 이스케이프는 다음과 같습니다.

다음 코드 조각은 DriverKnownEscape 플래그를 사용하는 방법을 보여줍니다.

D3DDDI_DRIVERESCAPE_TRANSLATEALLOCATIONEHANDLE Command = {};
    Command.EscapeType = D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE;
    Command.hAllocation = hAlloc;
    D3DKMT_ESCAPE Args = {};
    Args.hAdapter = hAdapter;
    Args.Flags.DriverKnownEscape = TRUE;
    Args.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
    Args.pPrivateDriverData = &Command;
    Args.PrivateDriverDataSize = sizeof(Command);
    Status = D3DKMTEscape(&Args);

WDDM 2.6 DDI 업데이트

WDDM 2.6(Windows 10 버전 1903)부터 매개 변수화 지원을 위해 다음과 같은 업데이트가 수행되었습니다.

  • 드라이버는 가상 머신에서 DXGK_ALLOCATIONINFOFLAGS::ACCESSEDPHYSICALLY 플래그를 사용할 수 있습니다. WDDM 2.6 이전에는 드라이버가 가상 머신에서 이 플래그를 사용할 수 없었고 이 플래그를 사용하여 할당을 만들지 못했습니다.

  • UMD는 가상 머신에서 Pfnd3dkmtUpdateallocationproperty 사용할 수 있습니다. WDDM 2.6 이전에는 이 호출이 실패합니다.