#include "vmxon.hpp" namespace vmxon { auto create_vmxon_region(hv::pvcpu_ctx vcpu_ctx) -> void { PHYSICAL_ADDRESS mem_range; mem_range.QuadPart = ~0ull; hv::vmx_basic_msr_t vmx_basic; vmx_basic.control = __readmsr(IA32_VMX_BASIC); vcpu_ctx->vmxon = reinterpret_cast( MmAllocateContiguousMemory(PAGE_SIZE, mem_range)); vcpu_ctx->vmxon_phys = MmGetPhysicalAddress(vcpu_ctx->vmxon).QuadPart; RtlSecureZeroMemory( vcpu_ctx->vmxon, PAGE_SIZE); vcpu_ctx->vmxon->header .bits .revision_identifier = vmx_basic.bits .vmcs_revision_identifier; } auto create_vmcs(hv::pvcpu_ctx vcpu_ctx) -> void { PHYSICAL_ADDRESS mem_range; mem_range.QuadPart = ~0ull; hv::vmx_basic_msr_t vmx_basic; vmx_basic.control = __readmsr(IA32_VMX_BASIC); vcpu_ctx->vmcs = reinterpret_cast( MmAllocateContiguousMemory(PAGE_SIZE, mem_range)); vcpu_ctx->vmcs_phys = MmGetPhysicalAddress(vcpu_ctx->vmcs).QuadPart; RtlSecureZeroMemory( vcpu_ctx->vmcs, PAGE_SIZE); vcpu_ctx->vmcs->header .bits .revision_identifier = vmx_basic.bits .vmcs_revision_identifier; } auto create_vcpus(hv::pvmx_ctx vmx_ctx) -> void { vmx_ctx->vcpu_num = KeQueryActiveProcessorCountEx( ALL_PROCESSOR_GROUPS); // allocate buffer for vcpu pointers... vmx_ctx->vcpus = reinterpret_cast( ExAllocatePool(NonPagedPool, sizeof(hv::pvcpu_ctx) * vmx_ctx->vcpu_num)); // allocate vcpu for each logical processor along with // vmxon region and vmcs memory for each logical processor... for (auto idx = 0u; idx < g_vmx_ctx->vcpu_num; ++idx) { vmx_ctx->vcpus[idx] = reinterpret_cast( ExAllocatePool(NonPagedPool, sizeof hv::vcpu_ctx)); // allocate host stack... vmx_ctx->vcpus[idx]->host_stack = reinterpret_cast( ExAllocatePool(NonPagedPool, PAGE_SIZE * HOST_STACK_PAGES)); // zero host stack... RtlZeroMemory(reinterpret_cast( vmx_ctx->vcpus[idx]->host_stack), PAGE_SIZE * HOST_STACK_PAGES); // setup VMCS and VMXON region... create_vmxon_region(vmx_ctx->vcpus[idx]); create_vmcs(vmx_ctx->vcpus[idx]); DBG_PRINT("setup vcpu for processor: %d\n", idx); DBG_PRINT(" - vmxon region (virtual): 0x%p\n", vmx_ctx->vcpus[idx]->vmxon); DBG_PRINT(" - vmxon region (physical): 0x%p\n", vmx_ctx->vcpus[idx]->vmxon_phys); DBG_PRINT(" - vmcs (virtual): 0x%p\n", vmx_ctx->vcpus[idx]->vmcs); DBG_PRINT(" - vmcs (physical): 0x%p\n", vmx_ctx->vcpus[idx]->vmcs_phys); DBG_PRINT(" - host stack: 0x%p\n", vmx_ctx->vcpus[idx]->host_stack); } } auto init_vmxon() -> void { hv::ia32_feature_control_msr_t feature_msr = { 0 }; hv::cr_fixed_t cr_fixed; hv::cr0_t cr0 = { 0 }; hv::cr4_t cr4 = { 0 }; // TODO: should check to see if this is locked or not... feature_msr.control = __readmsr(IA32_FEATURE_CONTROL); feature_msr.bits.vmxon_outside_smx = true; feature_msr.bits.lock = true; __writemsr(IA32_FEATURE_CONTROL, feature_msr.control); // not sure if did this in the wrong order, i think maybe cr4.vmx_enable bit needs // to be flipped before i fixed cr0 and cr4 registers? TODO: read up on dat sheet... cr_fixed.all = __readmsr(IA32_VMX_CR0_FIXED0); cr0.flags = __readcr0(); cr0.flags |= cr_fixed.split.low; cr_fixed.all = __readmsr(IA32_VMX_CR0_FIXED1); cr0.flags &= cr_fixed.split.low; __writecr0(cr0.flags); cr_fixed.all = __readmsr(IA32_VMX_CR4_FIXED0); cr4.flags = __readcr4(); cr4.flags |= cr_fixed.split.low; cr_fixed.all = __readmsr(IA32_VMX_CR4_FIXED1); cr4.flags &= cr_fixed.split.low; __writecr4(cr4.flags); // enable vmx instructions on this core... cr4.flags = __readcr4(); cr4.vmx_enable = true; __writecr4(cr4.flags); const auto vmxon_result = __vmx_on((unsigned long long*) &vmxon::g_vmx_ctx->vcpus[ KeGetCurrentProcessorNumber()]->vmxon_phys); DBG_PRINT("vmxon for processor: %d\n", KeGetCurrentProcessorNumber()); DBG_PRINT(" - vmxon result (0 == success): %d\n", vmxon_result); } }