/** * Initializes remaining bits of the Minimal provider. * This is called after initializing HM and almost all other VMM components. * * @returns VBox status code. * @param pVM Pointer to the VM. */ VMMR3_INT_DECL(int) gimR3MinimalInitCompleted(PVM pVM) { /* * Expose a generic hypervisor-agnostic leaf (originally defined VMware). * The leaves range from 0x40000010 to 0x400000FF. * * This is done in the init. completed routine as we need PDM to be * initialized (otherwise PDMApicGetTimerFreq() would fail). */ CPUMCPUIDLEAF HyperLeaf; int rc = CPUMR3CpuIdGetLeaf(pVM, &HyperLeaf, 0x40000000, 0 /* uSubLeaf */); if (RT_SUCCESS(rc)) { HyperLeaf.uEax = UINT32_C(0x40000010); /* Maximum leaf we implement. */ rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); /* * Insert missing zero leaves (you never know what missing leaves are * going to return when read). */ for (uint32_t uLeaf = UINT32_C(0x40000001); uLeaf < UINT32_C(0x40000010); uLeaf++) { rc = CPUMR3CpuIdGetLeaf(pVM, &HyperLeaf, uLeaf, 0 /* uSubLeaf */); if (RT_FAILURE(rc)) { RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = uLeaf; rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); } } /* * Add the timing information hypervisor leaf. * MacOS X uses this to determine the TSC, bus frequency. See @bugref{7270}. * * EAX - TSC frequency in KHz. * EBX - APIC frequency in KHz. * ECX, EDX - Reserved. */ uint64_t uApicFreq; rc = PDMApicGetTimerFreq(pVM, &uApicFreq); AssertLogRelRCReturn(rc, rc); RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = UINT32_C(0x40000010); HyperLeaf.uEax = TMCpuTicksPerSecond(pVM) / UINT64_C(1000); HyperLeaf.uEbx = (uApicFreq + 500) / UINT64_C(1000); rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); } else LogRel(("GIM: Minimal: failed to get hypervisor leaf 0x40000000.\n")); return VINF_SUCCESS; }
/** * Initializes remaining bits of the Hyper-V provider. * * This is called after initializing HM and almost all other VMM components. * * @returns VBox status code. * @param pVM Pointer to the VM. */ VMMR3_INT_DECL(int) gimR3HvInitCompleted(PVM pVM) { PGIMHV pHv = &pVM->gim.s.u.Hv; /* * Determine interface capabilities based on the version. */ if (!pVM->gim.s.u32Version) { /* Hypervisor capabilities; features used by the hypervisor. */ pHv->uHyperCaps = HMIsNestedPagingActive(pVM) ? GIM_HV_HOST_FEAT_NESTED_PAGING : 0; pHv->uHyperCaps |= HMAreMsrBitmapsAvailable(pVM) ? GIM_HV_HOST_FEAT_MSR_BITMAP : 0; } CPUMCPUIDLEAF HyperLeaf; RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = UINT32_C(0x40000006); HyperLeaf.uEax = pHv->uHyperCaps; HyperLeaf.uEbx = 0; HyperLeaf.uEcx = 0; HyperLeaf.uEdx = 0; int rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); return rc; }
/** * Initializes remaining bits of the KVM provider. * * This is called after initializing HM and almost all other VMM components. * * @returns VBox status code. * @param pVM Pointer to the VM. */ VMMR3_INT_DECL(int) gimR3KvmInitCompleted(PVM pVM) { PGIMKVM pKvm = &pVM->gim.s.u.Kvm; pKvm->cTscTicksPerSecond = TMCpuTicksPerSecond(pVM); if (TMR3CpuTickIsFixedRateMonotonic(pVM, true /* fWithParavirtEnabled */)) { /** @todo We might want to consider just enabling this bit *always*. As far * as I can see in the Linux guest, the "TSC_STABLE" bit is only * translated as a "monotonic" bit which even in Async systems we * -should- be reporting a strictly monotonic TSC to the guest. */ pKvm->uBaseFeat |= GIM_KVM_BASE_FEAT_TSC_STABLE; CPUMCPUIDLEAF HyperLeaf; RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = UINT32_C(0x40000001); HyperLeaf.uEax = pKvm->uBaseFeat; HyperLeaf.uEbx = 0; HyperLeaf.uEcx = 0; HyperLeaf.uEdx = 0; int rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); } return VINF_SUCCESS; }
/** * Initializes the Hyper-V GIM provider. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param uVersion The interface version this VM should use. */ VMMR3_INT_DECL(int) gimR3HvInit(PVM pVM) { AssertReturn(pVM, VERR_INVALID_PARAMETER); AssertReturn(pVM->gim.s.enmProviderId == GIMPROVIDERID_HYPERV, VERR_INTERNAL_ERROR_5); int rc; PGIMHV pHv = &pVM->gim.s.u.Hv; /* * Determine interface capabilities based on the version. */ if (!pVM->gim.s.u32Version) { /* Basic features. */ pHv->uBaseFeat = 0 //| GIM_HV_BASE_FEAT_VP_RUNTIME_MSR | GIM_HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR //| GIM_HV_BASE_FEAT_BASIC_SYNTH_IC //| GIM_HV_BASE_FEAT_SYNTH_TIMER_MSRS | GIM_HV_BASE_FEAT_APIC_ACCESS_MSRS | GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR | GIM_HV_BASE_FEAT_VIRT_SYS_RESET_MSR //| GIM_HV_BASE_FEAT_STAT_PAGES_MSR | GIM_HV_BASE_FEAT_PART_REF_TSC_MSR //| GIM_HV_BASE_FEAT_GUEST_IDLE_STATE_MSR | GIM_HV_BASE_FEAT_TIMER_FREQ_MSRS //| GIM_HV_BASE_FEAT_DEBUG_MSRS ; /* Miscellaneous features. */ pHv->uMiscFeat = GIM_HV_MISC_FEAT_TIMER_FREQ; /* Hypervisor recommendations to the guest. */ pHv->uHyperHints = GIM_HV_HINT_MSR_FOR_SYS_RESET | GIM_HV_HINT_RELAX_TIME_CHECKS; } /* * Populate the required fields in MMIO2 region records for registering. */ AssertCompile(GIM_HV_PAGE_SIZE == PAGE_SIZE); PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX]; pRegion->iRegion = GIM_HV_HYPERCALL_PAGE_REGION_IDX; pRegion->fRCMapping = false; pRegion->cbRegion = PAGE_SIZE; pRegion->GCPhysPage = NIL_RTGCPHYS; RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V hypercall page"); pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX]; pRegion->iRegion = GIM_HV_REF_TSC_PAGE_REGION_IDX; pRegion->fRCMapping = false; pRegion->cbRegion = PAGE_SIZE; pRegion->GCPhysPage = NIL_RTGCPHYS; RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V TSC page"); /* * Make sure the CPU ID bit are in accordance to the Hyper-V * requirement and other paranoia checks. * See "Requirements for implementing the Microsoft hypervisor interface" spec. */ Assert(!(pHv->uPartFlags & ( GIM_HV_PART_FLAGS_CREATE_PART | GIM_HV_PART_FLAGS_ACCESS_MEMORY_POOL | GIM_HV_PART_FLAGS_ACCESS_PART_ID | GIM_HV_PART_FLAGS_ADJUST_MSG_BUFFERS | GIM_HV_PART_FLAGS_CREATE_PORT | GIM_HV_PART_FLAGS_ACCESS_STATS | GIM_HV_PART_FLAGS_CPU_MGMT | GIM_HV_PART_FLAGS_CPU_PROFILER))); Assert((pHv->uBaseFeat & (GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR)) == (GIM_HV_BASE_FEAT_HYPERCALL_MSRS | GIM_HV_BASE_FEAT_VP_ID_MSR)); for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++) { PCGIMMMIO2REGION pcCur = &pHv->aMmio2Regions[i]; Assert(!pcCur->fRCMapping); Assert(!pcCur->fMapped); Assert(pcCur->GCPhysPage == NIL_RTGCPHYS); } /* * Expose HVP (Hypervisor Present) bit to the guest. */ CPUMSetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_HVP); /* * Modify the standard hypervisor leaves for Hyper-V. */ CPUMCPUIDLEAF HyperLeaf; RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = UINT32_C(0x40000000); HyperLeaf.uEax = UINT32_C(0x40000006); /* Minimum value for Hyper-V is 0x40000005. */ HyperLeaf.uEbx = 0x7263694D; /* 'Micr' */ HyperLeaf.uEcx = 0x666F736F; /* 'osof' */ HyperLeaf.uEdx = 0x76482074; /* 't Hv' */ rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); HyperLeaf.uLeaf = UINT32_C(0x40000001); HyperLeaf.uEax = 0x31237648; /* 'Hv#1' */ HyperLeaf.uEbx = 0; /* Reserved */ HyperLeaf.uEcx = 0; /* Reserved */ HyperLeaf.uEdx = 0; /* Reserved */ rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); /* * Add Hyper-V specific leaves. */ HyperLeaf.uLeaf = UINT32_C(0x40000002); /* MBZ until MSR_GIM_HV_GUEST_OS_ID is set by the guest. */ HyperLeaf.uEax = 0; HyperLeaf.uEbx = 0; HyperLeaf.uEcx = 0; HyperLeaf.uEdx = 0; rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); HyperLeaf.uLeaf = UINT32_C(0x40000003); HyperLeaf.uEax = pHv->uBaseFeat; HyperLeaf.uEbx = pHv->uPartFlags; HyperLeaf.uEcx = pHv->uPowMgmtFeat; HyperLeaf.uEdx = pHv->uMiscFeat; rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); HyperLeaf.uLeaf = UINT32_C(0x40000004); HyperLeaf.uEax = pHv->uHyperHints; HyperLeaf.uEbx = 0xffffffff; HyperLeaf.uEcx = 0; HyperLeaf.uEdx = 0; rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); /* * Insert all MSR ranges of Hyper-V. */ for (unsigned i = 0; i < RT_ELEMENTS(g_aMsrRanges_HyperV); i++) { rc = CPUMR3MsrRangesInsert(pVM, &g_aMsrRanges_HyperV[i]); AssertLogRelRCReturn(rc, rc); } return VINF_SUCCESS; }
/** * MSR write handler for Hyper-V. * * @returns Strict VBox status code like CPUMSetGuestMsr(). * @retval VINF_CPUM_R3_MSR_WRITE * @retval VERR_CPUM_RAISE_GP_0 * * @param pVCpu Pointer to the VMCPU. * @param idMsr The MSR being written. * @param pRange The range this MSR belongs to. * @param uRawValue The raw value with the ignored bits not masked. */ VMM_INT_DECL(VBOXSTRICTRC) gimHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue) { NOREF(pRange); PVM pVM = pVCpu->CTX_SUFF(pVM); PGIMHV pHv = &pVM->gim.s.u.Hv; switch (idMsr) { case MSR_GIM_HV_TPR: PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x80, uRawValue); return VINF_SUCCESS; case MSR_GIM_HV_EOI: PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x0B, uRawValue); return VINF_SUCCESS; case MSR_GIM_HV_ICR: PDMApicWriteMSR(pVM, pVCpu->idCpu, 0x30, uRawValue); return VINF_SUCCESS; case MSR_GIM_HV_GUEST_OS_ID: { #ifndef IN_RING3 return VINF_CPUM_R3_MSR_WRITE; #else /* Disable the hypercall-page if 0 is written to this MSR. */ if (!uRawValue) { gimR3HvDisableHypercallPage(pVM); pHv->u64HypercallMsr &= ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT; } else { LogRel(("GIM: HyperV: Guest OS reported ID %#RX64\n", uRawValue)); LogRel(("GIM: HyperV: Open-source=%RTbool Vendor=%#x OS=%#x (%s) Major=%u Minor=%u ServicePack=%u Build=%u\n", MSR_GIM_HV_GUEST_OS_ID_IS_OPENSOURCE(uRawValue), MSR_GIM_HV_GUEST_OS_ID_VENDOR(uRawValue), MSR_GIM_HV_GUEST_OS_ID_OS_VARIANT(uRawValue), gimHvGetGuestOsIdVariantName(uRawValue), MSR_GIM_HV_GUEST_OS_ID_MAJOR_VERSION(uRawValue), MSR_GIM_HV_GUEST_OS_ID_MINOR_VERSION(uRawValue), MSR_GIM_HV_GUEST_OS_ID_SERVICE_VERSION(uRawValue), MSR_GIM_HV_GUEST_OS_ID_BUILD(uRawValue))); /* Update the CPUID leaf, see Hyper-V spec. "Microsoft Hypervisor CPUID Leaves". */ CPUMCPUIDLEAF HyperLeaf; RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = UINT32_C(0x40000002); HyperLeaf.uEax = MSR_GIM_HV_GUEST_OS_ID_BUILD(uRawValue); HyperLeaf.uEbx = MSR_GIM_HV_GUEST_OS_ID_MINOR_VERSION(uRawValue) | (MSR_GIM_HV_GUEST_OS_ID_MAJOR_VERSION(uRawValue) << 16); HyperLeaf.uEcx = MSR_GIM_HV_GUEST_OS_ID_SERVICE_VERSION(uRawValue); HyperLeaf.uEdx = MSR_GIM_HV_GUEST_OS_ID_SERVICE_VERSION(uRawValue) | (MSR_GIM_HV_GUEST_OS_ID_BUILD(uRawValue) << 24); int rc2 = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertRC(rc2); } pHv->u64GuestOsIdMsr = uRawValue; return VINF_SUCCESS; #endif /* IN_RING3 */ } case MSR_GIM_HV_HYPERCALL: { #ifndef IN_RING3 return VINF_CPUM_R3_MSR_WRITE; #else /* IN_RING3 */ /* * For now ignore writes to the hypercall MSR (i.e. keeps it disabled). * This is required to boot FreeBSD 10.1 (with Hyper-V enabled ofc), * see @bugref{7270#c116}. */ return VINF_SUCCESS; # if 0 /* First, update all but the hypercall enable bit. */ pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT); /* Hypercalls can only be enabled when the guest has set the Guest-OS Id Msr. */ bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_HYPERCALL_ENABLE_BIT); if ( fEnable && !pHv->u64GuestOsIdMsr) { return VINF_SUCCESS; } /* Is the guest disabling the hypercall-page? Allow it regardless of the Guest-OS Id Msr. */ if (!fEnable) { gimR3HvDisableHypercallPage(pVM); pHv->u64HypercallMsr = uRawValue; return VINF_SUCCESS; } /* Enable the hypercall-page. */ RTGCPHYS GCPhysHypercallPage = MSR_GIM_HV_HYPERCALL_GUEST_PFN(uRawValue) << PAGE_SHIFT; int rc = gimR3HvEnableHypercallPage(pVM, GCPhysHypercallPage); if (RT_SUCCESS(rc)) { pHv->u64HypercallMsr = uRawValue; return VINF_SUCCESS; } return VERR_CPUM_RAISE_GP_0; # endif #endif /* IN_RING3 */ } case MSR_GIM_HV_REF_TSC: { #ifndef IN_RING3 return VINF_CPUM_R3_MSR_WRITE; #else /* IN_RING3 */ /* First, update all but the TSC-page enable bit. */ pHv->u64TscPageMsr = (uRawValue & ~MSR_GIM_HV_REF_TSC_ENABLE_BIT); /* Is the guest disabling the TSC-page? */ bool fEnable = RT_BOOL(uRawValue & MSR_GIM_HV_REF_TSC_ENABLE_BIT); if (!fEnable) { gimR3HvDisableTscPage(pVM); pHv->u64TscPageMsr = uRawValue; return VINF_SUCCESS; } /* Enable the TSC-page. */ RTGCPHYS GCPhysTscPage = MSR_GIM_HV_REF_TSC_GUEST_PFN(uRawValue) << PAGE_SHIFT; int rc = gimR3HvEnableTscPage(pVM, GCPhysTscPage, false /* fUseThisTscSequence */, 0 /* uTscSequence */); if (RT_SUCCESS(rc)) { pHv->u64TscPageMsr = uRawValue; return VINF_SUCCESS; } return VERR_CPUM_RAISE_GP_0; #endif /* IN_RING3 */ } case MSR_GIM_HV_RESET: { #ifndef IN_RING3 return VINF_CPUM_R3_MSR_WRITE; #else if (MSR_GIM_HV_RESET_IS_SET(uRawValue)) { LogRel(("GIM: HyperV: Reset initiated through MSR\n")); int rc = PDMDevHlpVMReset(pVM->gim.s.pDevInsR3); AssertRC(rc); } /* else: Ignore writes to other bits. */ return VINF_SUCCESS; #endif /* IN_RING3 */ } case MSR_GIM_HV_CRASH_CTL: { #ifndef IN_RING3 return VINF_CPUM_R3_MSR_WRITE; #else if (uRawValue & MSR_GIM_HV_CRASH_CTL_NOTIFY_BIT) { LogRel(("GIM: HyperV: Guest indicates a fatal condition! P0=%#RX64 P1=%#RX64 P2=%#RX64 P3=%#RX64 P4=%#RX64\n", pHv->uCrashP0, pHv->uCrashP1, pHv->uCrashP2, pHv->uCrashP3, pHv->uCrashP4)); } return VINF_SUCCESS; #endif } case MSR_GIM_HV_CRASH_P0: pHv->uCrashP0 = uRawValue; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P1: pHv->uCrashP1 = uRawValue; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P2: pHv->uCrashP2 = uRawValue; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P3: pHv->uCrashP3 = uRawValue; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P4: pHv->uCrashP4 = uRawValue; return VINF_SUCCESS; case MSR_GIM_HV_TIME_REF_COUNT: /* Read-only MSRs. */ case MSR_GIM_HV_VP_INDEX: case MSR_GIM_HV_TSC_FREQ: case MSR_GIM_HV_APIC_FREQ: LogFunc(("WrMsr on read-only MSR %#RX32 -> #GP(0)\n", idMsr)); return VERR_CPUM_RAISE_GP_0; default: { #ifdef IN_RING3 static uint32_t s_cTimes = 0; if (s_cTimes++ < 20) LogRel(("GIM: HyperV: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr, uRawValue & UINT64_C(0xffffffff00000000), uRawValue & UINT64_C(0xffffffff))); #endif LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue)); break; } } return VERR_CPUM_RAISE_GP_0; }
/** * Initializes the KVM GIM provider. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param uVersion The interface version this VM should use. */ VMMR3_INT_DECL(int) gimR3KvmInit(PVM pVM) { AssertReturn(pVM, VERR_INVALID_PARAMETER); AssertReturn(pVM->gim.s.enmProviderId == GIMPROVIDERID_KVM, VERR_INTERNAL_ERROR_5); int rc; PGIMKVM pKvm = &pVM->gim.s.u.Kvm; /* * Determine interface capabilities based on the version. */ if (!pVM->gim.s.u32Version) { /* Basic features. */ pKvm->uBaseFeat = 0 | GIM_KVM_BASE_FEAT_CLOCK_OLD //| GIM_KVM_BASE_FEAT_NOP_IO_DELAY //| GIM_KVM_BASE_FEAT_MMU_OP | GIM_KVM_BASE_FEAT_CLOCK //| GIM_KVM_BASE_FEAT_ASYNC_PF //| GIM_KVM_BASE_FEAT_STEAL_TIME //| GIM_KVM_BASE_FEAT_PV_EOI | GIM_KVM_BASE_FEAT_PV_UNHALT ; /* Rest of the features are determined in gimR3KvmInitCompleted(). */ } /* * Expose HVP (Hypervisor Present) bit to the guest. */ CPUMSetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_HVP); /* * Modify the standard hypervisor leaves for KVM. */ CPUMCPUIDLEAF HyperLeaf; RT_ZERO(HyperLeaf); HyperLeaf.uLeaf = UINT32_C(0x40000000); HyperLeaf.uEax = UINT32_C(0x40000001); /* Minimum value for KVM is 0x40000001. */ HyperLeaf.uEbx = 0x4B4D564B; /* 'KVMK' */ HyperLeaf.uEcx = 0x564B4D56; /* 'VMKV' */ HyperLeaf.uEdx = 0x0000004D; /* 'M000' */ rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); /* * Add KVM specific leaves. */ HyperLeaf.uLeaf = UINT32_C(0x40000001); HyperLeaf.uEax = pKvm->uBaseFeat; HyperLeaf.uEbx = 0; /* Reserved */ HyperLeaf.uEcx = 0; /* Reserved */ HyperLeaf.uEdx = 0; /* Reserved */ rc = CPUMR3CpuIdInsert(pVM, &HyperLeaf); AssertLogRelRCReturn(rc, rc); /* * Insert all MSR ranges of KVM. */ for (unsigned i = 0; i < RT_ELEMENTS(g_aMsrRanges_Kvm); i++) { rc = CPUMR3MsrRangesInsert(pVM, &g_aMsrRanges_Kvm[i]); AssertLogRelRCReturn(rc, rc); } /* * Setup hypercall and #UD handling. */ for (VMCPUID i = 0; i < pVM->cCpus; i++) VMMHypercallsEnable(&pVM->aCpus[i]); if (ASMIsAmdCpu()) { pKvm->fTrapXcptUD = true; pKvm->uOpCodeNative = OP_VMMCALL; } else { Assert(ASMIsIntelCpu() || ASMIsViaCentaurCpu()); pKvm->fTrapXcptUD = false; pKvm->uOpCodeNative = OP_VMCALL; } /* We always need to trap VMCALL/VMMCALL hypercall using #UDs for raw-mode VMs. */ if (!HMIsEnabled(pVM)) pKvm->fTrapXcptUD = true; return VINF_SUCCESS; }