/** * Hyper-V state-load operation, final pass. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param pSSM Pointer to the SSM handle. * @param uSSMVersion The GIM saved-state version. */ VMMR3_INT_DECL(int) gimR3HvLoad(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion) { PGIMHV pHv = &pVM->gim.s.u.Hv; /* * Load the Hyper-V SSM version first. */ uint32_t uHvSavedStatVersion; int rc = SSMR3GetU32(pSSM, &uHvSavedStatVersion); AssertRCReturn(rc, rc); if (uHvSavedStatVersion != GIM_HV_SAVED_STATE_VERSION) return SSMR3SetLoadError(pSSM, VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION, RT_SRC_POS, N_("Unsupported Hyper-V saved-state version %u (expected %u)."), uHvSavedStatVersion, GIM_HV_SAVED_STATE_VERSION); /* * Load per-VM MSRs. */ SSMR3GetU64(pSSM, &pHv->u64GuestOsIdMsr); SSMR3GetU64(pSSM, &pHv->u64HypercallMsr); SSMR3GetU64(pSSM, &pHv->u64TscPageMsr); /* * Load Hyper-V features / capabilities. */ SSMR3GetU32(pSSM, &pHv->uBaseFeat); SSMR3GetU32(pSSM, &pHv->uPartFlags); SSMR3GetU32(pSSM, &pHv->uPowMgmtFeat); SSMR3GetU32(pSSM, &pHv->uMiscFeat); SSMR3GetU32(pSSM, &pHv->uHyperHints); SSMR3GetU32(pSSM, &pHv->uHyperCaps); /* * Load and enable the Hypercall region. */ PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX]; SSMR3GetU8(pSSM, &pRegion->iRegion); SSMR3GetBool(pSSM, &pRegion->fRCMapping); SSMR3GetU32(pSSM, &pRegion->cbRegion); SSMR3GetGCPhys(pSSM, &pRegion->GCPhysPage); rc = SSMR3GetStrZ(pSSM, pRegion->szDescription, sizeof(pRegion->szDescription)); AssertRCReturn(rc, rc); if (MSR_GIM_HV_HYPERCALL_IS_ENABLED(pHv->u64HypercallMsr)) { Assert(pRegion->GCPhysPage != NIL_RTGCPHYS); if (RT_LIKELY(pRegion->fRegistered)) { rc = gimR3HvEnableHypercallPage(pVM, pRegion->GCPhysPage); if (RT_FAILURE(rc)) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to enable the hypercall page. GCPhys=%#RGp rc=%Rrc"), pRegion->GCPhysPage, rc); } else return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Hypercall MMIO2 region not registered. Missing GIM device?!")); } /* * Load and enable the reference TSC region. */ uint32_t uTscSequence; pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX]; SSMR3GetU8(pSSM, &pRegion->iRegion); SSMR3GetBool(pSSM, &pRegion->fRCMapping); SSMR3GetU32(pSSM, &pRegion->cbRegion); SSMR3GetGCPhys(pSSM, &pRegion->GCPhysPage); SSMR3GetStrZ(pSSM, pRegion->szDescription, sizeof(pRegion->szDescription)); rc = SSMR3GetU32(pSSM, &uTscSequence); AssertRCReturn(rc, rc); if (MSR_GIM_HV_REF_TSC_IS_ENABLED(pHv->u64TscPageMsr)) { Assert(pRegion->GCPhysPage != NIL_RTGCPHYS); if (pRegion->fRegistered) { rc = gimR3HvEnableTscPage(pVM, pRegion->GCPhysPage, true /* fUseThisTscSeq */, uTscSequence); if (RT_FAILURE(rc)) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to enable the TSC page. GCPhys=%#RGp rc=%Rrc"), pRegion->GCPhysPage, rc); } else return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("TSC-page MMIO2 region not registered. Missing GIM device?!")); } return rc; }
/** * 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))); } 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; }