41 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
51 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
55 _In_ ULONG_PTR guest_stack_pointer,
56 _In_ ULONG_PTR guest_instruction_pointer, _In_opt_
void *context);
64 _IRQL_requires_max_(PASSIVE_LEVEL)
static bool VmpSetupVmcs(
66 _In_ ULONG_PTR guest_stack_pointer,
67 _In_ ULONG_PTR guest_instruction_pointer, _In_ ULONG_PTR vmm_stack_pointer);
69 _IRQL_requires_max_(PASSIVE_LEVEL)
static void VmpLaunchVm();
71 _IRQL_requires_max_(PASSIVE_LEVEL)
static ULONG
74 _IRQL_requires_max_(PASSIVE_LEVEL)
static ULONG_PTR
79 _In_ USHORT segment_selector);
81 _IRQL_requires_max_(PASSIVE_LEVEL)
static ULONG_PTR
85 _IRQL_requires_max_(PASSIVE_LEVEL)
static ULONG
88 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
99 #if defined(ALLOC_PRAGMA) 100 #pragma alloc_text(PAGE, VmInitialization) 101 #pragma alloc_text(PAGE, VmTermination) 102 #pragma alloc_text(PAGE, VmpIsVmxAvailable) 103 #pragma alloc_text(PAGE, VmpSetLockBitCallback) 104 #pragma alloc_text(PAGE, VmpInitializeSharedData) 105 #pragma alloc_text(PAGE, VmpBuildMsrBitmap) 106 #pragma alloc_text(PAGE, VmpBuildIoBitmaps) 107 #pragma alloc_text(PAGE, VmpStartVm) 108 #pragma alloc_text(PAGE, VmpInitializeVm) 109 #pragma alloc_text(PAGE, VmpEnterVmxMode) 110 #pragma alloc_text(PAGE, VmpInitializeVmcs) 111 #pragma alloc_text(PAGE, VmpSetupVmcs) 112 #pragma alloc_text(PAGE, VmpLaunchVm) 113 #pragma alloc_text(PAGE, VmpGetSegmentAccessRight) 114 #pragma alloc_text(PAGE, VmpGetSegmentBase) 115 #pragma alloc_text(PAGE, VmpGetSegmentDescriptor) 116 #pragma alloc_text(PAGE, VmpGetSegmentBaseByDescriptor) 117 #pragma alloc_text(PAGE, VmpAdjustControlValue) 118 #pragma alloc_text(PAGE, VmpStopVm) 119 #pragma alloc_text(PAGE, VmpFreeProcessorData) 120 #pragma alloc_text(PAGE, VmpFreeSharedData) 121 #pragma alloc_text(PAGE, VmpIsHyperPlatformInstalled) 122 #pragma alloc_text(PAGE, VmHotplugCallback) 136 #if !defined(GetSegmentLimit) 138 return __segmentlimit(selector);
147 return STATUS_CANCELLED;
151 return STATUS_HV_FEATURE_UNAVAILABLE;
156 return STATUS_MEMORY_NOT_ALLOCATED;
164 if (!NT_SUCCESS(status)) {
177 int cpu_info[4] = {};
178 __cpuid(cpu_info, 1);
179 const CpuFeaturesEcx cpu_features = {
static_cast<ULONG_PTR
>(cpu_info[2])};
200 if (!NT_SUCCESS(status)) {
218 UNREFERENCED_PARAMETER(context);
224 return STATUS_SUCCESS;
231 return STATUS_DEVICE_CONFIGURATION_ERROR;
233 return STATUS_SUCCESS;
251 if (!shared_data->msr_bitmap) {
263 shared_data->io_bitmap_a = io_bitmaps;
264 shared_data->io_bitmap_b = io_bitmaps + PAGE_SIZE;
272 const auto msr_bitmap = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE,
277 RtlZeroMemory(msr_bitmap, PAGE_SIZE);
280 const auto bitmap_read_low =
reinterpret_cast<UCHAR *
>(msr_bitmap);
281 const auto bitmap_read_high = bitmap_read_low + 1024;
282 RtlFillMemory(bitmap_read_low, 1024, 0xff);
283 RtlFillMemory(bitmap_read_high, 1024, 0xff);
286 RTL_BITMAP bitmap_read_low_header = {};
287 RtlInitializeBitMap(&bitmap_read_low_header,
288 reinterpret_cast<PULONG>(bitmap_read_low), 1024 * 8);
289 RtlClearBits(&bitmap_read_low_header, 0xe7, 2);
292 for (
auto msr = 0ul; msr < 0x1000; ++msr) {
296 #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "Catch all."); 297 } __except (EXCEPTION_EXECUTE_HANDLER) {
298 RtlClearBits(&bitmap_read_low_header, msr, 1);
303 RTL_BITMAP bitmap_read_high_header = {};
304 RtlInitializeBitMap(&bitmap_read_high_header,
305 reinterpret_cast<PULONG>(bitmap_read_high),
307 RtlClearBits(&bitmap_read_high_header, 0x101, 2);
317 const auto io_bitmaps =
reinterpret_cast<UCHAR *
>(ExAllocatePoolWithTag(
323 const auto io_bitmap_a = io_bitmaps;
324 const auto io_bitmap_b = io_bitmaps + PAGE_SIZE;
325 RtlFillMemory(io_bitmap_a, PAGE_SIZE, 0);
326 RtlFillMemory(io_bitmap_b, PAGE_SIZE, 0);
329 RTL_BITMAP bitmap_a_header = {};
330 RtlInitializeBitMap(&bitmap_a_header, reinterpret_cast<PULONG>(io_bitmap_a),
331 PAGE_SIZE * CHAR_BIT);
334 RTL_BITMAP bitmap_b_header = {};
335 RtlInitializeBitMap(&bitmap_b_header, reinterpret_cast<PULONG>(io_bitmap_b),
336 PAGE_SIZE * CHAR_BIT);
342 _Use_decl_annotations_
static NTSTATUS
VmpStartVm(
void *context) {
346 KeGetCurrentProcessorNumberEx(
nullptr));
350 return STATUS_UNSUCCESSFUL;
353 return STATUS_SUCCESS;
359 ULONG_PTR guest_stack_pointer, ULONG_PTR guest_instruction_pointer,
369 const auto processor_data =
372 if (!processor_data) {
376 processor_data->shared_data = shared_data;
377 InterlockedIncrement(&processor_data->shared_data->reference_count);
381 if (!processor_data->ept_data) {
386 processor_data->vmm_stack_limit =
388 if (!processor_data->vmm_stack_limit) {
391 RtlZeroMemory(processor_data->vmm_stack_limit, KERNEL_STACK_SIZE);
393 processor_data->vmcs_region =
396 if (!processor_data->vmcs_region) {
401 processor_data->vmxon_region =
404 if (!processor_data->vmxon_region) {
422 const auto vmm_stack_region_base =
423 reinterpret_cast<ULONG_PTR
>(processor_data->vmm_stack_limit) +
425 const auto vmm_stack_data = vmm_stack_region_base -
sizeof(
void *);
426 const auto vmm_stack_base = vmm_stack_data -
sizeof(
void *);
428 processor_data->vmm_stack_limit);
430 vmm_stack_region_base);
434 processor_data, vmm_stack_data);
436 guest_stack_pointer);
438 guest_instruction_pointer);
439 *
reinterpret_cast<ULONG_PTR *
>(vmm_stack_base) = MAXULONG_PTR;
440 *
reinterpret_cast<ProcessorData **
>(vmm_stack_data) = processor_data;
447 goto ReturnFalseWithVmxOff;
450 guest_instruction_pointer, vmm_stack_base)) {
451 goto ReturnFalseWithVmxOff;
460 ReturnFalseWithVmxOff:;
481 Cr0 cr0 = {__readcr0()};
482 Cr0 cr0_original = cr0;
483 cr0.
all &= cr0_fixed1.
all;
484 cr0.
all |= cr0_fixed0.
all;
495 Cr4 cr4 = {__readcr4()};
496 Cr4 cr4_original = cr4;
497 cr4.
all &= cr4_fixed1.
all;
498 cr4.
all |= cr4_fixed0.
all;
512 if (__vmx_on(&vmxon_region_pa)) {
534 if (__vmx_vmclear(&vmcs_region_pa)) {
537 if (__vmx_vmptrld(&vmcs_region_pa)) {
547 const ProcessorData *processor_data, ULONG_PTR guest_stack_pointer,
548 ULONG_PTR guest_instruction_pointer, ULONG_PTR vmm_stack_pointer) {
559 .fields.vmx_capability_hint;
566 vm_entryctl_requested.
all)};
572 vm_exitctl_requested.
all)};
578 vm_pinctl_requested.
all)};
589 vm_procctl_requested.
all)};
613 const auto exception_bitmap =
624 Cr0 cr0_shadow = {__readcr0()};
627 Cr4 cr4_shadow = {__readcr4()};
774 const auto vmx_status =
static_cast<VmxStatus>(error);
787 auto vmx_status =
static_cast<VmxStatus>(__vmx_vmlaunch());
800 USHORT segment_selector) {
804 if (segment_selector) {
807 native_access_right >>= 8;
808 access_right.
all =
static_cast<ULONG
>(native_access_right);
815 return access_right.
all;
820 ULONG_PTR gdt_base, USHORT segment_selector) {
829 const auto local_segment_descriptor =
831 const auto ldt_base =
833 const auto segment_descriptor =
837 const auto segment_descriptor =
845 ULONG_PTR descriptor_table_base, USHORT segment_selector) {
859 const auto base_high = segment_descriptor->
fields.
base_high << (6 * 4);
860 const auto base_middle = segment_descriptor->
fields.
base_mid << (4 * 4);
862 ULONG_PTR base = (base_high | base_middle | base_low) & MAXULONG;
868 base |= (base_upper32 << 32);
875 Msr msr, ULONG requested_value) {
878 LARGE_INTEGER msr_value = {};
880 auto adjusted_value = requested_value;
883 adjusted_value &= msr_value.HighPart;
885 adjusted_value |= msr_value.LowPart;
886 return adjusted_value;
895 if (NT_SUCCESS(status)) {
904 _Use_decl_annotations_
static NTSTATUS
VmpStopVm(
void *context) {
905 UNREFERENCED_PARAMETER(context);
909 KeGetCurrentProcessorNumberEx(
nullptr));
914 if (!NT_SUCCESS(status)) {
919 Cr4 cr4 = {__readcr4()};
924 return STATUS_SUCCESS;
932 if (!processor_data) {
984 int cpu_info[4] = {};
985 __cpuid(cpu_info, 1);
986 const CpuFeaturesEcx cpu_features = {
static_cast<ULONG_PTR
>(cpu_info[2])};
992 return cpu_info[0] ==
'PpyH';
996 _Use_decl_annotations_ NTSTATUS
1001 GROUP_AFFINITY affinity = {};
1002 GROUP_AFFINITY previous_affinity = {};
1003 KeSetSystemGroupAffinityThread(&affinity, &previous_affinity);
1009 KeSetSystemGroupAffinityThread(&affinity, &previous_affinity);
1011 if (!NT_SUCCESS(status)) {
1015 return STATUS_UNSUCCESSFUL;
1019 affinity.Group = proc_num.Group;
1020 affinity.Mask = 1ull << proc_num.Number;
1021 KeSetSystemGroupAffinityThread(&affinity, &previous_affinity);
1025 KeRevertToUserGroupAffinityThread(&previous_affinity);
static ULONG VmpAdjustControlValue(_In_ Msr msr, _In_ ULONG requested_value)
struct SegmentSelector::@7 fields
struct EptData * ept_data
A pointer to EPT related data.
unsigned mov_dr_exiting
[23]
void * msr_bitmap
Bitmap to activate MSR I/O VM-exit.
static UCHAR * VmpBuildIoBitmaps()
static bool VmpEnterVmxMode(_Inout_ ProcessorData *processor_data)
USHORT __stdcall AsmReadGS()
Reads GS.
#define HYPERPLATFORM_LOG_INFO(format,...)
#define HYPERPLATFORM_LOG_DEBUG(format,...)
Logs a message as respective severity.
static void VmpFreeSharedData(_In_ ProcessorData *processor_data)
static void VmpInitializeVm(_In_ ULONG_PTR guest_stack_pointer, _In_ ULONG_PTR guest_instruction_pointer, _In_opt_ void *context)
VmxStatus UtilVmWrite(VmcsField field, ULONG_PTR field_value)
unsigned load_debug_controls
[2]
VmxStatus
Indicates a result of VMX-instructions.
unsigned pae
[5] Physical Address Extension
USHORT __stdcall AsmReadCS()
Reads CS.
NTSTATUS VmInitialization()
Virtualizes all processors.
USHORT __stdcall AsmReadTR()
Reads STR.
struct VmControlStructure * vmcs_region
VA of a VMCS region.
static void * VmpBuildMsrBitmap()
unsigned unusable
[16] Segment unusable
static const ULONG kHyperPlatformCommonPoolTag
A pool tag.
static ULONG_PTR VmpGetSegmentBaseByDescriptor(_In_ const SegmentDescriptor *segment_descriptor)
See: Virtual-Machine Control Structures & FORMAT OF THE VMCS REGION.
void VmTermination()
De-virtualize all processors.
constexpr bool IsX64()
Checks if a system is x64.
unsigned use_msr_bitmaps
[28]
#define HYPERPLATFORM_COMMON_DBG_BREAK()
Sets a break point that works only when a debugger is present.
unsigned vmxe
[13] Virtual Machine Extensions Enabled
ULONG32 not_used
[31] Always 0 (a.k.a. HypervisorPresent)
USHORT __stdcall AsmReadDS()
Reads DS.
static bool VmpIsVmxAvailable()
static NTSTATUS VmpStopVm(_In_opt_ void *context)
Operation failed with extended status available.
unsigned nw
[29] Not Write-Through
struct SegmentDescriptor::@8 fields
static ULONG_PTR VmpGetSegmentBase(_In_ ULONG_PTR gdt_base, _In_ USHORT segment_selector)
See: Guest Register State.
USHORT __stdcall AsmReadES()
Reads ES.
ULONG GetSegmentLimit(_In_ ULONG selector)
void __sgdt(_Out_ void *gdtr)
Writes to GDT.
#define HYPERPLATFORM_LOG_WARN(format,...)
void * UtilAllocateContiguousMemory(SIZE_T number_of_bytes)
struct Ia32FeatureControlMsr::@27 fields
See: Definitions of Primary Processor-Based VM-Execution Controls.
Declares interfaces to EPT functions.
unsigned pge
[7] Page Global Enable
See: Definitions of VM-Entry Controls.
bool __stdcall AsmInitializeVm(_In_ void(*vm_initialization_routine)(_In_ ULONG_PTR, _In_ ULONG_PTR, _In_opt_ void *), _In_opt_ void *context)
A wrapper for vm_initialization_routine.
struct Ia32VmxBasicMsr::@28 fields
VmxStatus UtilInveptGlobal()
Executes the INVEPT instruction and invalidates EPT entry cache.
unsigned host_address_space_size
[9]
SharedProcessorData * shared_data
Shared data.
struct VmxRegmentDescriptorAccessRight::@26 fields
void * io_bitmap_a
Bitmap to activate IO VM-exit (~ 0x7FFF)
void * vmm_stack_limit
A head of VA for VMM stack.
USHORT __stdcall AsmReadLDTR()
Reads SLDT.
struct VmxSecondaryProcessorBasedControls::@23 fields
struct VmxProcessorBasedControls::@22 fields
void * io_bitmap_b
Bitmap to activate IO VM-exit (~ 0xffff)
Declares interfaces to VMM functions.
NTSTATUS UtilVmCall(HypercallNumber hypercall_number, void *context)
unsigned long revision_identifier
USHORT __stdcall AsmReadSS()
Reads SS.
unsigned pse
[4] Page Size Extensions
void EptTermination(EptData *ept_data)
static void VmpFreeProcessorData(_In_opt_ ProcessorData *processor_data)
void UtilWriteMsr64(Msr msr, ULONG64 value)
unsigned smep
[20] Supervisor Mode Execution Protection Enable
unsigned descriptor_table_exiting
[2]
static NTSTATUS VmpSetLockBitCallback(_In_opt_ void *context)
Declares interfaces to assembly functions.
unsigned enable_rdtscp
[3]
See: Feature Information Returned in the ECX Register.
Msr
See: MODEL-SPECIFIC REGISTERS (MSRS)
static bool VmpSetupVmcs(_In_ const ProcessorData *processor_data, _In_ ULONG_PTR guest_stack_pointer, _In_ ULONG_PTR guest_instruction_pointer, _In_ ULONG_PTR vmm_stack_pointer)
Represents VMM related data shared across all processors.
struct VmControlStructure * vmxon_region
VA of a VMXON region.
bool EptIsEptAvailable()
Checks if the system supports EPT technology sufficient enough.
Declares interfaces to utility functions.
ULONG64 UtilPaFromVa(void *va)
unsigned enable_invpcid
[12]
ULONG_PTR UtilReadMsr(Msr msr)
See: Definitions of Pin-Based VM-Execution Controls.
unsigned enable_xsaves_xstors
[20]
See: Definitions of Secondary Processor-Based VM-Execution Controls.
unsigned short ti
Table Indicator.
unsigned cd
[30] Cache Disable
USHORT __stdcall AsmReadFS()
Reads FS.
void EptInitializeMtrrEntries()
Reads and stores all MTRRs to set a correct memory type for EPT.
void UtilLoadPdptes(ULONG_PTR cr3_value)
unsigned revision_identifier
[0:30]
volatile long reference_count
Number of processors sharing this data.
ULONG_PTR __stdcall AsmLoadAccessRightsByte(_In_ ULONG_PTR segment_selector)
Loads access rights byte.
static ULONG VmpGetSegmentAccessRight(_In_ USHORT segment_selector)
static bool VmpInitializeVmcs(_Inout_ ProcessorData *processor_data)
NTSTATUS VmHotplugCallback(const PROCESSOR_NUMBER &proc_num)
Virtualizes the specified processor.
static bool VmpIsHyperPlatformInstalled()
unsigned memory_type
[50:53]
VmxStatus UtilInvvpidAllContext()
Executes the INVVPID instruction (type 2)
unsigned use_io_bitmaps
[25]
ULONG_PTR UtilVmRead(VmcsField field)
bool UtilIsX86Pae()
Checks if the system is a PAE-enabled x86 system.
void __stdcall AsmVmmEntryPoint()
An entry point of VMM where gets called whenever VM-exit occurred.
static const ULONG32 kHyperVCpuidInterface
A majority of modern hypervisors expose their signatures through CPUID with this CPUID function code ...
unsigned cr3_load_exiting
[15]
unsigned reserved2
[17:31]
See: BASIC VMX INFORMATION.
void UtilFreeContiguousMemory(void *base_address)
static SegmentDescriptor * VmpGetSegmentDescriptor(_In_ ULONG_PTR descriptor_table_base, _In_ USHORT segment_selector)
struct CpuFeaturesEcx::@9 fields
static SharedProcessorData * VmpInitializeSharedData()
struct VmxVmExitControls::@24 fields
unsigned pg
[31] Paging Enabled
Declares and implements common things across the project.
unsigned activate_secondary_control
[31]
Declares interfaces to VMM initialization functions.
unsigned ia32e_mode_guest
[9]
ULONG64 UtilReadMsr64(Msr msr)
ULONG32 vmx
[5] Virtual Machine Technology
See: MEMORY-MANAGEMENT REGISTERS.
EptData * EptInitialization()
Builds EPT, allocates pre-allocated entires, initializes and returns EptData.
static const SIZE_T kVmxMaxVmcsSize
See: OVERVIEW.
#define HYPERPLATFORM_LOG_ERROR(format,...)
Declares interfaces to logging functions.
static NTSTATUS VmpStartVm(_In_opt_ void *context)
static void VmpLaunchVm()
See: Definitions of VM-Exit Controls.
ULONG64 EptGetEptPointer(EptData *ept_data)
struct VmxVmEntryControls::@25 fields
NTSTATUS UtilForEachProcessor(NTSTATUS(*callback_routine)(void *), void *context)
Represents VMM related data associated with each processor.
VmxStatus UtilVmWrite64(VmcsField field, ULONG64 field_value)