중첩된 가상화는 하드웨어 가상화 확장을 에뮬레이트하는 Hyper-V 하이퍼바이저를 나타냅니다. 이러한 에뮬레이트된 확장은 다른 가상화 소프트웨어(예: 중첩된 하이퍼바이저)에서 Hyper-V 플랫폼에서 실행하는 데 사용할 수 있습니다.
이 기능은 게스트 파티션에서만 사용할 수 있습니다. 가상 머신별로 사용하도록 설정해야 합니다. 중첩된 가상화는 Windows 루트 파티션에서 지원되지 않습니다.
다음 용어는 다양한 수준의 중첩된 가상화를 정의하는 데 사용됩니다.
| 용어 | Definition |
|---|---|
| L0 하이퍼바이저 | 물리적 하드웨어에서 실행되는 Hyper-V 하이퍼바이저입니다. |
| L1 루트 | Windows 루트 운영 체제입니다. |
| L1 게스트 | 중첩된 하이퍼바이저가 없는 Hyper-V 가상 머신입니다. |
| L1 하이퍼바이저 | Hyper-V 가상 머신 내에서 실행되는 중첩된 하이퍼바이저입니다. |
| L2 루트 | Hyper-V 가상 머신의 컨텍스트 내에서 실행되는 루트 Windows 운영 체제입니다. |
| L2 게스트 | Hyper-V 가상 머신의 컨텍스트 내에서 실행되는 중첩된 가상 머신입니다. |
운영 체제 미설치에 비해 하이퍼바이저는 VM에서 실행할 때 상당한 성능 회귀를 초래할 수 있습니다. L1 하이퍼바이저는 L0 하이퍼바이저에서 제공하는 인식 인터페이스를 사용하여 Hyper-V VM에서 실행되도록 최적화할 수 있습니다.
이 기능은 현재 x64에서만 지원됩니다.
인식 VMCS(Intel)
Intel 플랫폼에서 가상화 소프트웨어는 VMCS(가상 머신 제어 데이터 구조)를 사용하여 가상화와 관련된 프로세서 동작을 구성합니다. VMCS는 VMPTRLD 명령을 사용하여 활성화하고 VMREAD 및 VMWRITE 지침을 사용하여 수정해야 합니다. 이러한 지침은 에뮬레이트해야 하므로 중첩된 가상화에 상당한 병목 현상이 발생하는 경우가 많습니다.
하이퍼바이저는 게스트 실제 메모리의 데이터 구조를 사용하여 가상화 관련 프로세서 동작을 제어하는 데 사용할 수 있는 "인식 VMCS" 기능을 노출합니다. 이 데이터 구조는 일반 메모리 액세스 지침을 사용하여 수정할 수 있으므로 L1 하이퍼바이저가 VMREAD 또는 VMWRITE 또는 VMPTRLD 지침을 실행할 필요가 없습니다.
L1 하이퍼바이저는 가상 프로세서 지원 페이지의 해당 필드에 1을 작성하여 인식 VMCS를 사용하도록 선택할 수 있습니다. VP 지원 페이지의 다른 필드는 현재 활성 상태인 VMCS를 제어합니다. 각 인식 VMCS는 정확히 한 페이지(4KB)이며 처음에는 0이어야 합니다. 인식된 VMCS를 활성 또는 현재 상태로 만들기 위해 VMPTRLD 명령을 실행해서는 안 됩니다.
L1 하이퍼바이저가 인식된 VMCS를 사용하여 VM 항목을 수행한 후 VMCS는 프로세서에서 활성으로 간주됩니다. 인식된 VMCS는 단일 프로세서에서만 동시에 활성화할 수 있습니다. L1 하이퍼바이저는 VMCLEAR 명령을 실행하여 인식된 VMCS를 활성 상태에서 비활성 상태로 전환할 수 있습니다. 인식된 VMCS가 활성 상태인 동안의 모든 VMREAD 또는 VMWRITE 지침은 지원되지 않으며 예기치 않은 동작이 발생할 수 있습니다.
HV_VMX_ENLIGHTENED_VMCS 구조체는 인식된 VMCS의 레이아웃을 정의합니다. 가상이 아닌 모든 필드는 Intel 물리적 VMCS 인코딩에 매핑됩니다.
필드 정리
L0 하이퍼바이저는 인식된 VMCS의 일부를 캐시하도록 선택할 수 있습니다. 인식된 VMCS 정리 필드는 중첩된 VM 항목의 게스트 메모리에서 다시 로드되는 인식 VMCS의 부분을 제어합니다. L1 하이퍼바이저는 인식된 VMCS를 수정할 때마다 해당 VMCS 정리 필드를 지워야 합니다. 그렇지 않으면 L0 하이퍼바이저에서 부실 버전을 사용할 수 있습니다.
클린 필드 인식은 인식 VMCS의 합성 "클린 필드"필드를 통해 제어됩니다. 기본적으로 모든 비트는 L0 하이퍼바이저가 중첩된 각 VM 항목에 해당하는 VMCS 필드를 다시 로드하도록 설정됩니다.
기능 검색
인식된 VMCS 인터페이스에 대한 지원은 CPUID 리프 0x40000004 보고됩니다.
인식된 VMCS 구조는 향후 변경 사항을 고려하여 버전이 지정됩니다. 각 인식 VMCS 구조에는 L0 하이퍼바이저에서 보고하는 버전 필드가 포함됩니다.
현재 지원되는 유일한 VMCS 버전은 1입니다.
하이퍼바이저 구현 고려 사항
대부분의 VMCS 필드의 경우 아키텍처 기능 검색 메커니즘을 통해 결정된 대로 VMCS 필드가 VM에 대해 지원되는 경우 해당 인식 VMCS 필드가 VM에 대해 지원됩니다. 예외는 CPUID 리프 0x4000000A 보고됩니다.
아키텍처 기능 검색 메커니즘이 인식된 VMCS 필드가 정의되지 않은 VMCS 필드에 대한 지원을 나타내는 경우 L1 하이퍼바이저는 인식 VMCS를 사용하도록 선택하는 경우 이 기능을 사용하도록 설정해서는 안 됩니다.
Hyper-V L0 하이퍼바이저는 인식된 VMCS 필드 또는 예외가 정의되지 않은 VMCS 필드에 대한 지원을 나타내지 않습니다. 다른 L0 하이퍼바이저에 새로운 인식 VMCS 필드 또는 예외를 정의해야 하는 경우 Microsoft에 문의하세요.
AMD(Enlighened VMCB 필드)
AMD에는 하이퍼바이저 사용을 위해 VMCB에 예약된 공간과 연결된 클린 비트가 있습니다. 예약된 바이트는 VMCB의 컨트롤 섹션, 오프셋 0x3E0-3FF에 있습니다. 클린 비트는 비트 31입니다(하이퍼바이저가 VMCB의 "인식" 영역을 수정할 때마다 클린 비트가 무효화되어야 함).
Hyper-V 예약된 VMCB 영역을 활용하여 인식 사항을 구성합니다. HV_SVM_ENLIGHTENED_VMCB_FIELDS 구조체는 형식을 문서화합니다.
인식된 MSR 비트맵
L0 하이퍼바이저는 가상화 소프트웨어가 가로채기를 생성하는 MSR 액세스를 제어할 수 있도록 하는 Intel 및 AMD 플랫폼 모두에서 "MSR-Bitmap" 컨트롤을 에뮬레이트합니다.
L1 하이퍼바이저는 L0 하이퍼바이저와 공동 작업하여 MSR 액세스 효율성을 높일 수 있습니다. 인식된 VMCS/VMCB 필드의 해당 필드를 1로 설정하여 인식된 MSR 비트맵을 사용하도록 설정할 수 있습니다. 사용하도록 설정하면 L0 하이퍼바이저가 MSR 비트맵에서 변경 내용을 모니터링하지 않습니다. 대신 L1 하이퍼바이저는 MSR 비트맵 중 하나를 변경한 후 해당 정리 필드를 무효화해야 합니다.
인식된 MSR 비트맵에 대한 지원은 CPUID 리프 0x4000000A 보고됩니다.
실시간 마이그레이션과의 호환성
Hyper-V 한 호스트에서 다른 호스트로 자식 파티션을 실시간 마이그레이션할 수 있습니다. 실시간 마이그레이션은 일반적으로 자식 파티션에 투명합니다. 그러나 중첩된 가상화의 경우 L1 하이퍼바이저는 마이그레이션을 알고 있어야 할 수 있습니다.
실시간 마이그레이션 알림
L1 하이퍼바이저는 파티션이 마이그레이션될 때 알림을 요청할 수 있습니다. 이 기능은 CPUID에서 "AccessReenlightenmentControls" 권한으로 열거됩니다. L0 하이퍼바이저는 L1 하이퍼바이저에서 인터럽트 벡터 및 대상 프로세서를 구성하는 데 사용할 수 있는 가상 MSR(HV_X64_MSR_REENLIGHTENMENT_CONTROL)을 노출합니다. L0 하이퍼바이저는 각 마이그레이션 후에 지정된 벡터로 인터럽트를 삽입합니다.
#define HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106)
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 Vector :8;
UINT64 RsvdZ1 :8;
UINT64 Enabled :1;
UINT64 RsvdZ2 :15;
UINT64 TargetVp :32;
};
} HV_REENLIGHTENMENT_CONTROL;
지정된 벡터는 고정 APIC 인터럽트여야 합니다. TargetVp는 가상 프로세서 인덱스를 지정합니다.
TSC 에뮬레이션
게스트 파티션은 서로 다른 TSC 빈도를 가진 두 컴퓨터 간에 실시간 마이그레이션될 수 있습니다. 이러한 경우 참조 TSC 페이지의 TscScale 값을 다시 계산해야 할 수 있습니다.
L0 하이퍼바이저는 필요에 따라 L1 하이퍼바이저가 TscScale 값을 다시 계산할 수 있을 때까지 마이그레이션 후 모든 TSC 액세스를 에뮬레이트합니다. L1 하이퍼바이저는 HV_X64_MSR_TSC_EMULATION_CONTROL MSR에 기록하여 TSC 에뮬레이션을 옵트인할 수 있습니다. 옵트인하는 경우 L0 하이퍼바이저는 마이그레이션이 수행된 후 TSC 액세스를 에뮬레이트합니다.
L1 하이퍼바이저는 HV_X64_MSR_TSC_EMULATION_STATUS MSR을 사용하여 TSC 액세스가 현재 에뮬레이트되고 있는지 쿼리할 수 있습니다. 예를 들어 L1 하이퍼바이저는 실시간 마이그레이션 알림을 구독하고 마이그레이션 인터럽트 수신 후 TSC 상태를 쿼리할 수 있습니다. 이 MSR을 사용하여 TSC 에뮬레이션(TscScale 값을 업데이트한 후)을 끌 수도 있습니다.
#define HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)
#define HV_X64_MSR_TSC_EMULATION_STATUS (0x40000108)
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 Enabled :1;
UINT64 RsvdZ :63;
};
} HV_TSC_EMULATION_CONTROL;
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 InProgress : 1;
UINT64 RsvdP1 : 63;
};
} HV_TSC_EMULATION_STATUS;
Virtual TLB
하이퍼바이저에서 노출되는 가상 TLB는 L2 GPA에서 GPA로의 캐시 변환으로 확장될 수 있습니다. 논리 프로세서의 TLB와 마찬가지로 가상 TLB는 일관성이 없는 캐시이며 이 비 일관성은 게스트에게 표시됩니다. 하이퍼바이저는 TLB를 관리하는 작업을 노출합니다.
직접 가상 플러시
하이퍼바이저는 운영 체제가 가상 TLB를 보다 효율적으로 관리할 수 있도록 하는 하이퍼콜(HvCallFlushVirtualAddressSpace, HvCallFlushVirtualAddressSpaceEx, HvCallFlushVirtualAddressList 및 HvCallFlushVirtualAddressListEx)을 노출합니다. L1 하이퍼바이저는 게스트가 해당 하이퍼콜을 사용하도록 허용하고 해당 하이퍼바이저를 L0 하이퍼바이저에 처리할 책임을 위임하도록 선택할 수 있습니다. 이를 위해서는 파티션 지원 페이지(및 Intel 플랫폼의 가상 VMCS)를 사용해야 합니다.
사용 중인 경우 가상 TLB는 캐시된 모든 매핑을 만든 중첩된 컨텍스트(VMCS 또는 VMCB)의 식별자를 사용하여 태그를 지정합니다. L2 게스트의 직접 가상 플러시 하이퍼콜에 대한 응답으로 L0 하이퍼바이저는 중첩된 컨텍스트에서 만든 캐시된 모든 매핑을 무효화합니다.
- VmId는 호출자의 VmId와 동일합니다.
- VpId가 지정된 ProcessorMask에 포함되거나 HV_FLUSH_ALL_PROCESSORS 지정됩니다.
직접 가상 플러시에 대한 지원은 CPUID 리프 0x4000000A 보고됩니다.
구성 / 설정
가상 플러시 하이퍼콜의 직접 처리는 다음을 통해 사용하도록 설정됩니다.
- 가상 프로세서 지원 페이지의 NestedEnlightenmentsControl.Features.DirectHypercall 필드를 1로 설정합니다.
- 인식된 VMCS 또는 VMCB의 EnlightenmentsControl.NestedFlushVirtualHypercall 필드를 1로 설정합니다.
이를 사용하도록 설정하기 전에 L1 하이퍼바이저는 인식된 VMCS/VMCB의 다음 추가 필드를 구성해야 합니다.
- VpId: 인식된 VMCS/VMCB가 제어하는 가상 프로세서의 ID입니다.
- VmId: 인식된 VMCS/VMCB가 속한 가상 머신의 ID입니다.
- PartitionAssistPage: 파티션 지원 페이지의 게스트 실제 주소입니다.
또한 L1 하이퍼바이저는 CPUID를 통해 게스트에게 다음 기능을 노출해야 합니다.
- UseHypercallForLocalFlush
- UseHypercallForRemoteFlush
파티션 지원 페이지
파티션 지원 페이지는 L1 하이퍼바이저가 할당해야 하는 페이지 크기 정렬 페이지 크기 메모리 영역이며 직접 플러시 하이퍼콜을 사용하려면 0입니다. 해당 GPA는 인식된 VMCS/VMCB의 해당 필드에 기록되어야 합니다.
struct
{
UINT32 TlbLockCount;
} VM_PARTITION_ASSIST_PAGE;
가상 VM-Exit
호출자 파티션 지원 페이지의 TlbLockCount가 0이 아닌 경우 L0 하이퍼바이저는 직접 가상 플러시 하이퍼콜을 처리한 후 가상 종료 이유가 있는 VM-Exit L1 하이퍼바이저에 전달합니다.
Intel 플랫폼에서는 종료 이유가 HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH 있는 VM-Exit 제공됩니다. AMD 플랫폼에서는 종료 코드 HV_SVM_EXITCODE_ENL 가 포함된 VM-Exit 전달되고 ExitInfo1은 .로 HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH설정됩니다.
#define HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH 0x10000031
#define HV_SVM_EXITCODE_ENL 0xF0000000
#define HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH (1)
두 번째 수준 주소 변환
게스트 파티션에 중첩된 가상화를 사용하도록 설정하면 파티션에서 노출하는 MMU(메모리 관리 단위)에 두 번째 수준 주소 변환 지원이 포함됩니다. 두 번째 수준 주소 변환은 L1 하이퍼바이저에서 실제 메모리를 가상화하는 데 사용할 수 있는 기능입니다. 사용 중인 경우 GPA(게스트 물리적 주소)로 처리되는 특정 주소는 L2 GPA(게스트 물리적 주소)로 처리되고 페이징 구조 집합을 트래버스하여 GPA로 변환됩니다.
L1 하이퍼바이저는 두 번째 수준 주소 공간을 사용하는 방법과 위치를 결정할 수 있습니다. 각 두 번째 수준 주소 공간은 게스트 정의 64비트 ID 값으로 식별됩니다. Intel 플랫폼에서 이 값은 EPT 포인터와 동일합니다. AMD 플랫폼에서 값은 nCR3 VMCB 필드와 같습니다.
Compatibility
하이퍼바이저에서 노출하는 두 번째 수준 주소 변환 기능은 일반적으로 주소 변환에 대한 VMX 또는 SVM 지원과 호환됩니다. 그러나 다음과 같은 게스트 관찰 가능한 차이점이 있습니다.
- 내부적으로 하이퍼바이저는 L2 GPA를 SPA로 변환하는 섀도 페이지 테이블을 사용할 수 있습니다. 이러한 구현에서 이러한 섀도 페이지 테이블은 소프트웨어에 큰 TLL로 표시됩니다. 그러나 몇 가지 차이점을 관찰할 수 있습니다. 먼저 두 가상 프로세서 간에 섀도 페이지 테이블을 공유할 수 있지만 기존 TLL은 프로세서별 구조이며 독립적입니다. 이 공유는 한 가상 프로세서의 페이지 액세스가 나중에 다른 가상 프로세서에서 사용되는 섀도 페이지 테이블 항목을 채울 수 있기 때문에 표시될 수 있습니다.
- 일부 하이퍼바이저 구현에서는 게스트 페이지 테이블의 내부 쓰기 보호를 사용하여 내부 데이터 구조(예: 섀도 페이지 테이블)에서 MMU 매핑을 지연 플러시할 수 있습니다. 이러한 테이블에 대한 쓰기는 하이퍼바이저에서 투명하게 처리되므로 게스트가 아키텍처에서 볼 수 없습니다. 그러나 다른 파티션 또는 디바이스에서 기본 GPA 페이지에 수행된 쓰기는 적절한 TLB 플러시를 트리거하지 않을 수 있습니다.
- 일부 하이퍼바이저 구현에서는 두 번째 수준 페이지 오류가 캐시된 매핑을 무효화하지 않을 수 있습니다.
인식된 두 번째 수준 TLB 플러시
또한 하이퍼바이저는 게스트가 두 번째 수준 TLB를 보다 효율적으로 관리할 수 있도록 하는 향상된 기능 집합을 지원합니다. 이러한 향상된 작업은 레거시 TLB 관리 작업과 상호 교환하여 사용할 수 있습니다.
하이퍼바이저는 TLL을 무효화하기 위해 다음 하이퍼콜을 지원합니다.
| 하이퍼콜 | Description |
|---|---|
| HvCallFlushGuestPhysicalAddressSpace | 는 두 번째 수준 주소 공간 내에서 캐시된 L2 GPA를 GPA 매핑으로 무효화합니다. |
| HvCallFlushGuestPhysicalAddressList | 는 두 번째 수준 주소 공간의 일부 내에서 캐시된 GVA/L2 GPA를 GPA 매핑으로 무효화합니다. |
AMD 플랫폼에서 모든 TLB 항목은 ASID(주소 공간 식별자)로 아키텍처적으로 태그가 지정됩니다. ASID가 무효화되면 ASID와 연결된 모든 TLB 전체가 무효화됩니다. 중첩된 하이퍼바이저는 선택적으로 HV_SVM_ENLIGHTENED_VMCB_FIELDS EnlightenedNptTlb를 "1"로 설정하여 "인식된 TLB"를 옵트인할 수 있습니다. 중첩된 하이퍼바이저가 인식에 옵트인하는 경우 ASID 무효화는 첫 번째 수준 주소 변환(즉, 가상 주소 공간)에서 파생된 TLB 전체만 플러시합니다. NPT(중첩 페이지 테이블)에서 파생된 TLB 항목을 플러시하고 L0 하이퍼바이저가 섀도 페이지 테이블을 다시 작성하도록 하려면 HvCallFlushGuestPhysicalAddressSpace 또는 HvCallFlushGuestPhysicalAddressList 하이퍼콜을 사용해야 합니다.
중첩된 가상화 예외
Intel 플랫폼에서. L1 하이퍼바이저는 페이지 오류 예외 클래스에서 가상화 예외를 결합하도록 옵트인할 수 있습니다. L0 하이퍼바이저는 하이퍼바이저 중첩 가상화 기능 CPUID 리프에서 이 기능에 대한 지원을 보급합니다.
가상 프로세서 지원 페이지의 HV_NESTED_ENLIGHTENMENTS_CONTROL 데이터 구조에서 VirtualizationException을 "1"로 설정하여 이러한 인식 기능을 사용할 수 있습니다.
중첩된 가상화 MSR
중첩된 VP 인덱스 레지스터
L1 하이퍼바이저는 현재 프로세서의 기본 VP 인덱스를 보고하는 MSR을 노출합니다.
| MSR 주소 | 등록 이름 | Description |
|---|---|---|
| 0x40001002 | HV_X64_MSR_NESTED_VP_INDEX | 중첩된 루트 파티션에서 현재 프로세서의 기본 VP 인덱스가 보고됩니다. |
중첩된 SynIC MSR
중첩된 루트 파티션에서 다음 MSR은 기본 하이퍼바이저의 해당 SynIC 레지스터 에 대한 액세스를 허용합니다.
기본 프로세서의 인덱스 찾기를 호출자는 먼저 HV_X64_MSR_NESTED_VP_INDEX 사용해야 합니다.
| MSR 주소 | 등록 이름 | 기본 MSR |
|---|---|---|
| 0x40001080 | HV_X64_MSR_NESTED_SCONTROL | HV_X64_MSR_SCONTROL |
| 0x40001081 | HV_X64_MSR_NESTED_SVERSION | HV_X64_MSR_SVERSION |
| 0x40001082 | HV_X64_MSR_NESTED_SIEFP | HV_X64_MSR_SIEFP |
| 0x40001083 | HV_X64_MSR_NESTED_SIMP | HV_X64_MSR_SIMP |
| 0x40001084 | HV_X64_MSR_NESTED_EOM | HV_X64_MSR_EOM |
| 0x40001090 | HV_X64_MSR_NESTED_SINT0 | HV_X64_MSR_SINT0 |
| 0x40001091 | HV_X64_MSR_NESTED_SINT1 | HV_X64_MSR_SINT1 |
| 0x40001092 | HV_X64_MSR_NESTED_SINT2 | HV_X64_MSR_SINT2 |
| 0x40001093 | HV_X64_MSR_NESTED_SINT3 | HV_X64_MSR_SINT3 |
| 0x40001094 | HV_X64_MSR_NESTED_SINT4 | HV_X64_MSR_SINT4 |
| 0x40001095 | HV_X64_MSR_NESTED_SINT5 | HV_X64_MSR_SINT5 |
| 0x40001096 | HV_X64_MSR_NESTED_SINT6 | HV_X64_MSR_SINT6 |
| 0x40001097 | HV_X64_MSR_NESTED_SINT7 | HV_X64_MSR_SINT7 |
| 0x40001098 | HV_X64_MSR_NESTED_SINT8 | HV_X64_MSR_SINT8 |
| 0x40001099 | HV_X64_MSR_NESTED_SINT9 | HV_X64_MSR_SINT9 |
| 0x4000109A | HV_X64_MSR_NESTED_SINT10 | HV_X64_MSR_SINT10 |
| 0x4000109B | HV_X64_MSR_NESTED_SINT11 | HV_X64_MSR_SINT11 |
| 0x4000109C | HV_X64_MSR_NESTED_SINT12 | HV_X64_MSR_SINT12 |
| 0x4000109D | HV_X64_MSR_NESTED_SINT13 | HV_X64_MSR_SINT13 |
| 0x4000109E | HV_X64_MSR_NESTED_SINT14 | HV_X64_MSR_SINT14 |
| 0x4000109F | HV_X64_MSR_NESTED_SINT15 | HV_X64_MSR_SINT15 |