_Use_decl_annotations_ EXTERN_C static bool VminitpInitializeVMCS( PER_PROCESSOR_DATA *ProcessorData) { // Write a VMCS revision identifier IA32_VMX_BASIC_MSR vmxBasicMsr = {__readmsr(IA32_VMX_BASIC)}; ProcessorData->VmcsRegion->RevisionIdentifier = vmxBasicMsr.Fields.RevisionIdentifier; auto vmcsRegionPA = MmGetPhysicalAddress(ProcessorData->VmcsRegion); // It stores the value FFFFFFFF_FFFFFFFFH if there is no current VMCS if (__vmx_vmclear( reinterpret_cast<unsigned long long *>(&vmcsRegionPA.QuadPart))) { return false; } // Software makes a VMCS current by executing VMPTRLD with the address // of the VMCS; that address is loaded into the current-VMCS pointer. if (__vmx_vmptrld( reinterpret_cast<unsigned long long *>(&vmcsRegionPA.QuadPart))) { return false; } // The launch state of current VMCS is "clear" return true; }
NTSTATUS ControlAreaInitializeProcessor(LONG ProcessorNumber) { // // Allocate host stack region // 16 pages available for use // SIZE_T stackSize = 16 * PAGE_SIZE; PUCHAR stackBase = ExAllocatePoolWithTag(NonPagedPool, stackSize, 'KSTK'); if (!stackBase) return STATUS_NO_MEMORY; RtlSecureZeroMemory((PVOID)stackBase, stackSize); // // Set up CPU control structure // PVIRT_CPU cpu = (PVIRT_CPU)(stackBase + stackSize - 8 - sizeof(VIRT_CPU)); cpu->HostStackBase = stackBase; cpu->Self = cpu; CpuControlArea[ProcessorNumber] = cpu; // // Allocate all VMX regions // if (!NT_SUCCESS(AllocateVmxProcessorData(&cpu->VmxonVa, &cpu->VmxonPa, &cpu->VmxonSize))) return STATUS_NO_MEMORY; if (!NT_SUCCESS(AllocateVmxProcessorData(&cpu->VmcsVa, &cpu->VmcsPa, &cpu->VmcsSize))) return STATUS_NO_MEMORY; if (!NT_SUCCESS(AllocateVmxProcessorData(&cpu->MSRBitmapVa, &cpu->MSRBitmapPa, &cpu->MSRBitmapSize))) return STATUS_NO_MEMORY; // Bitmap needs to be zeroed RtlSecureZeroMemory(cpu->MSRBitmapVa, cpu->MSRBitmapSize); __try { if (__vmx_on(PA_PTR_INT64(cpu->VmxonPa)) > 0) return STATUS_UNSUCCESSFUL; if (__vmx_vmclear(PA_PTR_INT64(cpu->VmcsPa)) > 0) return STATUS_UNSUCCESSFUL; if (__vmx_vmptrld(PA_PTR_INT64(cpu->VmcsPa)) > 0) return STATUS_UNSUCCESSFUL; } __except (EXCEPTION_EXECUTE_HANDLER) { // Rare case (or if physical address is invalid) return GetExceptionCode(); } return STATUS_SUCCESS; }
static bool init_vmcs(struct vmcs *vmcs) { u64 vmx = __readmsr(MSR_IA32_VMX_BASIC); vmcs->revision_id = (u32)vmx; uintptr_t pa = __pa(vmcs); if (__vmx_vmclear(&pa)) return false; return __vmx_vmptrld(&pa) == 0; }
// See: VMM SETUP & TEAR DOWN _Use_decl_annotations_ static bool VmpInitializeVMCS( ProcessorData *processor_data) { // Write a VMCS revision identifier const Ia32VmxBasicMsr vmx_basic_msr = {UtilReadMsr64(Msr::kIa32VmxBasic)}; processor_data->vmcs_region->revision_identifier = vmx_basic_msr.fields.revision_identifier; auto vmcs_region_pa = UtilPaFromVa(processor_data->vmcs_region); if (__vmx_vmclear(&vmcs_region_pa)) { return false; } if (__vmx_vmptrld(&vmcs_region_pa)) { return false; } // The launch state of current VMCS is "clear" return true; }
/// <summary> /// Switch CPU to root mode /// </summary> /// <param name="Vcpu">Virtual CPU data</param> /// <returns>TRUE on success</returns> BOOLEAN VmxEnterRoot( IN PVCPU Vcpu ) { PKSPECIAL_REGISTERS Registers = &Vcpu->HostState.SpecialRegisters; PIA32_VMX_BASIC_MSR pBasic = (PIA32_VMX_BASIC_MSR)&Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_BASIC )]; // Ensure the the VMCS can fit into a single page if (pBasic->Fields.RegionSize > PAGE_SIZE) { DPRINT( "HyperBone: CPU %d: %s: VMCS region doesn't fit into one page\n", CPU_IDX, __FUNCTION__ ); return FALSE; } // Ensure that the VMCS is supported in writeback memory if (pBasic->Fields.MemoryType != VMX_MEM_TYPE_WRITEBACK) { DPRINT( "HyperBone: CPU %d: %s: Unsupported memory type\n", CPU_IDX, __FUNCTION__ ); return FALSE; } // Ensure that true MSRs can be used for capabilities if (pBasic->Fields.VmxCapabilityHint == 0) { DPRINT( "HyperBone: CPU %d: %s: No true MSR support\n", CPU_IDX, __FUNCTION__ ); return FALSE; } // Capture the revision ID for the VMXON and VMCS region Vcpu->VMXON->RevisionId = pBasic->Fields.RevisionIdentifier; Vcpu->VMCS->RevisionId = pBasic->Fields.RevisionIdentifier; // Update CR0 with the must-be-zero and must-be-one requirements Registers->Cr0 &= Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_CR0_FIXED1 )].LowPart; Registers->Cr0 |= Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_CR0_FIXED0 )].LowPart; // Do the same for CR4 Registers->Cr4 &= Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_CR4_FIXED1 )].LowPart; Registers->Cr4 |= Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_CR4_FIXED0 )].LowPart; // Update host CR0 and CR4 based on the requirements above __writecr0( Registers->Cr0 ); __writecr4( Registers->Cr4 ); // Enable VMX Root Mode PHYSICAL_ADDRESS phys = MmGetPhysicalAddress( Vcpu->VMXON ); int res = __vmx_on( (PULONG64)&phys ); if (res) { DPRINT( "HyperBone: CPU %d: %s: __vmx_on failed with status %d\n", CPU_IDX, __FUNCTION__, res ); return FALSE; } // Clear the state of the VMCS, setting it to Inactive phys = MmGetPhysicalAddress( Vcpu->VMCS ); if (__vmx_vmclear( (PULONG64)&phys )) { DPRINT( "HyperBone: CPU %d: %s: __vmx_vmclear failed\n", CPU_IDX, __FUNCTION__ ); return FALSE; } // Load the VMCS, setting its state to Active if (__vmx_vmptrld( (PULONG64)&phys )) { DPRINT( "HyperBone: CPU %d: %s: __vmx_vmptrld failed\n", CPU_IDX, __FUNCTION__ ); return FALSE; } // VMX Root Mode is enabled, with an active VMCS. return TRUE; }