/** * 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; }
/** * MSR read handler for Hyper-V. * * @returns Strict VBox status code like CPUMQueryGuestMsr(). * @retval VINF_CPUM_R3_MSR_READ * @retval VERR_CPUM_RAISE_GP_0 * * @param pVCpu Pointer to the VMCPU. * @param idMsr The MSR being read. * @param pRange The range this MSR belongs to. * @param puValue Where to store the MSR value read. */ VMM_INT_DECL(VBOXSTRICTRC) gimHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue) { NOREF(pRange); PVM pVM = pVCpu->CTX_SUFF(pVM); PGIMHV pHv = &pVM->gim.s.u.Hv; switch (idMsr) { case MSR_GIM_HV_TIME_REF_COUNT: { /* Hyper-V reports the time in 100 ns units (10 MHz). */ uint64_t u64Tsc = TMCpuTickGet(pVCpu); uint64_t u64TscHz = pHv->cTscTicksPerSecond; uint64_t u64Tsc100Ns = u64TscHz / UINT64_C(10000000); /* 100 ns */ *puValue = (u64Tsc / u64Tsc100Ns); return VINF_SUCCESS; } case MSR_GIM_HV_VP_INDEX: *puValue = pVCpu->idCpu; return VINF_SUCCESS; case MSR_GIM_HV_TPR: PDMApicReadMSR(pVM, pVCpu->idCpu, 0x80, puValue); return VINF_SUCCESS; case MSR_GIM_HV_EOI: PDMApicReadMSR(pVM, pVCpu->idCpu, 0x0B, puValue); return VINF_SUCCESS; case MSR_GIM_HV_ICR: PDMApicReadMSR(pVM, pVCpu->idCpu, 0x30, puValue); return VINF_SUCCESS; case MSR_GIM_HV_GUEST_OS_ID: *puValue = pHv->u64GuestOsIdMsr; return VINF_SUCCESS; case MSR_GIM_HV_HYPERCALL: *puValue = pHv->u64HypercallMsr; return VINF_SUCCESS; case MSR_GIM_HV_REF_TSC: *puValue = pHv->u64TscPageMsr; return VINF_SUCCESS; case MSR_GIM_HV_TSC_FREQ: *puValue = TMCpuTicksPerSecond(pVM); return VINF_SUCCESS; case MSR_GIM_HV_APIC_FREQ: { int rc = PDMApicGetTimerFreq(pVM, puValue); if (RT_FAILURE(rc)) return VERR_CPUM_RAISE_GP_0; return VINF_SUCCESS; } case MSR_GIM_HV_RESET: *puValue = 0; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_CTL: *puValue = pHv->uCrashCtl; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P0: *puValue = pHv->uCrashP0; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P1: *puValue = pHv->uCrashP1; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P2: *puValue = pHv->uCrashP2; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P3: *puValue = pHv->uCrashP3; return VINF_SUCCESS; case MSR_GIM_HV_CRASH_P4: *puValue = pHv->uCrashP4; return VINF_SUCCESS; default: { #ifdef IN_RING3 static uint32_t s_cTimes = 0; if (s_cTimes++ < 20) LogRel(("GIM: HyperV: Unknown/invalid RdMsr (%#x) -> #GP(0)\n", idMsr)); #endif LogFunc(("Unknown/invalid RdMsr (%#RX32) -> #GP(0)\n", idMsr)); break; } } return VERR_CPUM_RAISE_GP_0; }