VirtualBox

Changeset 56672 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 29, 2015 12:53:55 PM (9 years ago)
Author:
vboxsync
Message:

VMM/GIM: Workaround PGM issue with large pages in Hyper-V by directly rewriting guest memory than using the MMIO2 mapping.

Location:
trunk/src/VBox/VMM
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/GIMR0Hv.cpp

    r56287 r56672  
    9999        return VERR_GIM_PVTSC_NOT_ENABLED;
    100100
     101    /** @todo this is buggy when large pages are used due to a PGM limitation, see
     102     *        @bugref{7532}.
     103     *
     104     *        In any case, we do not ever update this page while the guest is
     105     *        running after setting it up (in ring-3, see gimR3HvEnableTscPage()) as
     106     *        the TSC offset is handled in the VMCS/VMCB (HM) or by trapping RDTSC
     107     *        (raw-mode). */
     108#if 0
    101109    PCGIMHV          pcHv     = &pVM->gim.s.u.Hv;
    102110    PCGIMMMIO2REGION pcRegion = &pcHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
     
    128136    Assert(pRefTsc->u32TscSequence != 0);
    129137    Assert(pRefTsc->u32TscSequence != UINT32_C(0xffffffff));
     138#endif
    130139    return VINF_SUCCESS;
    131140}
  • trunk/src/VBox/VMM/VMMR3/GIMHv.cpp

    r55439 r56672  
    131131    pRegion->iRegion    = GIM_HV_HYPERCALL_PAGE_REGION_IDX;
    132132    pRegion->fRCMapping = false;
    133     pRegion->cbRegion   = PAGE_SIZE;
     133    pRegion->cbRegion   = PAGE_SIZE;  /* Sanity checked in gimR3HvLoad(), gimR3HvEnableTscPage() & gimR3HvEnableHypercallPage() */
    134134    pRegion->GCPhysPage = NIL_RTGCPHYS;
    135135    RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V hypercall page");
     
    138138    pRegion->iRegion    = GIM_HV_REF_TSC_PAGE_REGION_IDX;
    139139    pRegion->fRCMapping = false;
    140     pRegion->cbRegion   = PAGE_SIZE;
     140    pRegion->cbRegion   = PAGE_SIZE;  /* Sanity checked in gimR3HvLoad(), gimR3HvEnableTscPage() & gimR3HvEnableHypercallPage() */
    141141    pRegion->GCPhysPage = NIL_RTGCPHYS;
    142142    RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V TSC page");
     
    479479    rc = SSMR3GetStrZ(pSSM, pRegion->szDescription, sizeof(pRegion->szDescription));
    480480    AssertRCReturn(rc, rc);
     481
     482    if (pRegion->cbRegion != PAGE_SIZE)
     483        return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Hypercall page region size %u invalid, expected %u"),
     484                                pRegion->cbRegion, PAGE_SIZE);
     485
    481486    if (MSR_GIM_HV_HYPERCALL_IS_ENABLED(pHv->u64HypercallMsr))
    482487    {
     
    505510    rc = SSMR3GetU32(pSSM, &uTscSequence);
    506511    AssertRCReturn(rc, rc);
     512
     513    if (pRegion->cbRegion != PAGE_SIZE)
     514        return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("TSC page region size %u invalid, expected %u"),
     515                                pRegion->cbRegion, PAGE_SIZE);
     516
    507517    if (MSR_GIM_HV_REF_TSC_IS_ENABLED(pHv->u64TscPageMsr))
    508518    {
     
    560570     */
    561571    Assert(!pRegion->fMapped);
     572
     573    /** @todo this is buggy when large pages are used due to a PGM limitation, see
     574     *        @bugref{7532}. Instead of the overlay style mapping, we just
     575     *               rewrite guest memory directly. */
     576#if 0
    562577    rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysTscPage);
    563578    if (RT_SUCCESS(rc))
     
    592607    else
    593608        LogRelFunc(("GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
    594 
    595609    return VERR_GIM_OPERATION_FAILED;
     610#else
     611    AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_2);
     612    PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)RTMemAllocZ(PAGE_SIZE);
     613    if (RT_UNLIKELY(!pRefTsc))
     614    {
     615        LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
     616        return VERR_NO_MEMORY;
     617    }
     618
     619    uint64_t const u64TscKHz = TMCpuTicksPerSecond(pVM) / UINT64_C(1000);
     620    uint32_t       u32TscSeq = 1;
     621    if (   fUseThisTscSeq
     622        && uTscSeq < UINT32_C(0xfffffffe))
     623        u32TscSeq = uTscSeq + 1;
     624    pRefTsc->u32TscSequence  = u32TscSeq;
     625    pRefTsc->u64TscScale     = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
     626    pRefTsc->i64TscOffset    = 0;
     627
     628    rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysTscPage, pRefTsc, sizeof(*pRefTsc));
     629    if (RT_SUCCESS(rc))
     630    {
     631        LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
     632                GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
     633
     634        pRegion->GCPhysPage = GCPhysTscPage;
     635        pRegion->fMapped = true;
     636        TMR3CpuTickParavirtEnable(pVM);
     637    }
     638    else
     639    {
     640        LogRelFunc(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc));
     641        rc = VERR_GIM_OPERATION_FAILED;
     642    }
     643    RTMemFree(pRefTsc);
     644    return rc;
     645#endif
    596646}
    597647
     
    609659    if (pRegion->fMapped)
    610660    {
     661#if 0
    611662        GIMR3Mmio2Unmap(pVM, pRegion);
    612663        Assert(!pRegion->fMapped);
     664#else
     665        pRegion->fMapped = false;
     666#endif
    613667        LogRel(("GIM: HyperV: Disabled TSC-page\n"));
    614668
     
    631685    if (pRegion->fMapped)
    632686    {
     687#if 0
    633688        GIMR3Mmio2Unmap(pVM, pRegion);
    634689        Assert(!pRegion->fMapped);
     690#else
     691        pRegion->fMapped = false;
     692#endif
    635693        for (VMCPUID i = 0; i < pVM->cCpus; i++)
    636694            VMMHypercallsDisable(&pVM->aCpus[i]);
     
    674732     */
    675733    Assert(!pRegion->fMapped);
     734
     735    /** @todo this is buggy when large pages are used due to a PGM limitation, see
     736     *        @bugref{7532}. Instead of the overlay style mapping, we just
     737     *               rewrite guest memory directly. */
     738#if 0
    676739    int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage);
    677740    if (RT_SUCCESS(rc))
     
    711774    LogRel(("GIM: HyperV: GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
    712775    return rc;
    713 }
    714 
     776#else
     777    AssertReturn(pRegion->cbRegion == PAGE_SIZE, VERR_GIM_IPE_3);
     778    void *pvHypercallPage = RTMemAllocZ(PAGE_SIZE);
     779    if (RT_UNLIKELY(!pvHypercallPage))
     780    {
     781        LogRelFunc(("Failed to alloc %u bytes\n", PAGE_SIZE));
     782        return VERR_NO_MEMORY;
     783    }
     784
     785    /*
     786     * Patch the hypercall-page.
     787     */
     788    size_t cbWritten = 0;
     789    int rc = VMMPatchHypercall(pVM, pvHypercallPage, PAGE_SIZE, &cbWritten);
     790    if (   RT_SUCCESS(rc)
     791        && cbWritten < PAGE_SIZE)
     792    {
     793        uint8_t *pbLast = (uint8_t *)pvHypercallPage + cbWritten;
     794        *pbLast = 0xc3;  /* RET */
     795
     796        rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysHypercallPage, pvHypercallPage, PAGE_SIZE);
     797        if (RT_SUCCESS(rc))
     798        {
     799            /*
     800             * Notify VMM that hypercalls are now enabled for all VCPUs.
     801             */
     802            for (VMCPUID i = 0; i < pVM->cCpus; i++)
     803                VMMHypercallsEnable(&pVM->aCpus[i]);
     804
     805            pRegion->GCPhysPage = GCPhysHypercallPage;
     806            pRegion->fMapped = true;
     807            LogRel(("GIM: HyperV: Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
     808        }
     809        else
     810            LogRel(("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed during hypercall page setup. rc=%Rrc\n", rc));
     811    }
     812    else
     813    {
     814        if (rc == VINF_SUCCESS)
     815            rc = VERR_GIM_OPERATION_FAILED;
     816        LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
     817    }
     818
     819    RTMemFree(pvHypercallPage);
     820    return rc;
     821#endif
     822}
     823
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette