VirtualBox

Changeset 51643 in vbox for trunk/src/VBox/VMM/VMMR3


Ignore:
Timestamp:
Jun 18, 2014 11:06:06 AM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
94404
Message:

VMM/GIM: More bits for Hyper-V implementation.

Location:
trunk/src/VBox/VMM/VMMR3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/GIM.cpp

    r51560 r51643  
    9090     */
    9191    int rc;
    92 #if 0
    93     rc = SSMR3RegisterInternal(pVM, "GIM", 0, GIM_SSM_VERSION, sizeof(GIM),
    94                                     NULL, NULL, NULL,
    95                                     NULL, gimR3Save, NULL,
    96                                     NULL, gimR3Load, NULL);
     92    rc = SSMR3RegisterInternal(pVM, "GIM", 0 /* uInstance */, GIM_SSM_VERSION, sizeof(GIM),
     93                                    NULL /* pfnLivePrep */, NULL /* pfnLiveExec */, NULL /* pfnLiveVote*/,
     94                                    NULL /* pfnSavePrep */, gimR3Save,              NULL /* pfnSaveDone */,
     95                                    NULL /* pfnLoadPrep */, gimR3Load,              NULL /* pfnLoadDone */);
    9796    if (RT_FAILURE(rc))
    9897        return rc;
    99 #endif
    10098
    10199    /*
     
    226224
    227225/**
    228  * Execute state save operation.
     226 * Executes state-save operation.
    229227 *
    230228 * @returns VBox status code.
     
    234232DECLCALLBACK(int) gimR3Save(PVM pVM, PSSMHANDLE pSSM)
    235233{
    236     /** @todo save state. */
    237     return VINF_SUCCESS;
     234    AssertReturn(pVM,  VERR_INVALID_PARAMETER);
     235    AssertReturn(pSSM, VERR_SSM_INVALID_STATE);
     236
     237    /** @todo Save per-CPU data. */
     238    int rc;
     239#if 0
     240    for (VMCPUID i = 0; i < pVM->cCpus; i++)
     241    {
     242        rc = SSMR3PutXYZ(pSSM, pVM->aCpus[i].gim.s.XYZ);
     243    }
     244#endif
     245
     246    /*
     247     * Save per-VM data.
     248     */
     249    rc = SSMR3PutBool(pSSM, pVM->gim.s.fEnabled);
     250    AssertRCReturn(rc, rc);
     251    rc = SSMR3PutU32(pSSM, pVM->gim.s.enmProviderId);
     252    AssertRCReturn(rc, rc);
     253    rc = SSMR3PutU32(pSSM, pVM->gim.s.u32Version);
     254    AssertRCReturn(rc, rc);
     255
     256    /*
     257     * Save provider-specific data.
     258     */
     259    if (pVM->gim.s.fEnabled)
     260    {
     261        switch (pVM->gim.s.enmProviderId)
     262        {
     263            case GIMPROVIDERID_HYPERV:
     264                rc = GIMR3HvSave(pVM, pSSM);
     265                AssertRCReturn(rc, rc);
     266                break;
     267
     268            default:
     269                break;
     270        }
     271    }
     272
     273    return rc;
    238274}
    239275
     
    250286DECLCALLBACK(int) gimR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
    251287{
    252     /** @todo load state. */
    253     return VINF_SUCCESS;
     288    if (uPass != SSM_PASS_FINAL)
     289        return VINF_SUCCESS;
     290
     291    /** @todo Load per-CPU data. */
     292    int rc;
     293#if 0
     294    for (VMCPUID i = 0; i < pVM->cCpus; i++)
     295    {
     296        rc = SSMR3PutXYZ(pSSM, pVM->aCpus[i].gim.s.XYZ);
     297    }
     298#endif
     299
     300    /*
     301     * Load per-VM data.
     302     */
     303    rc = SSMR3GetBool(pSSM, &pVM->gim.s.fEnabled);
     304    AssertRCReturn(rc, rc);
     305    rc = SSMR3GetU32(pSSM, (uint32_t *)&pVM->gim.s.enmProviderId);
     306    AssertRCReturn(rc, rc);
     307    rc = SSMR3GetU32(pSSM, &pVM->gim.s.u32Version);
     308    AssertRCReturn(rc, rc);
     309
     310    /*
     311     * Load provider-specific data.
     312     */
     313    if (pVM->gim.s.fEnabled)
     314    {
     315        switch (pVM->gim.s.enmProviderId)
     316        {
     317            case GIMPROVIDERID_HYPERV:
     318                rc = GIMR3HvLoad(pVM, pSSM, uVersion);
     319                AssertRCReturn(rc, rc);
     320                break;
     321
     322            default:
     323                break;
     324        }
     325    }
     326
     327    return rc;
    254328}
    255329
     
    266340VMMR3_INT_DECL(int) GIMR3Term(PVM pVM)
    267341{
     342    if (!pVM->gim.s.fEnabled)
     343        return VINF_SUCCESS;
     344
     345    switch (pVM->gim.s.enmProviderId)
     346    {
     347        case GIMPROVIDERID_HYPERV:
     348            return GIMR3HvTerm(pVM);
     349
     350        default:
     351            break;
     352    }
    268353    return VINF_SUCCESS;
    269354}
     
    350435 * @param   pRegion     Pointer to the GIM MMIO2 region.
    351436 */
    352 VMM_INT_DECL(int) GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion)
     437VMMR3_INT_DECL(int) GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion)
    353438{
    354439    AssertPtr(pVM);
     
    359444    if (pRegion->fMapped)
    360445    {
    361         PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
    362         int rc = PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, pRegion->GCPhysPage);
     446        int rc = PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
     447        AssertRC(rc);
     448
     449        rc = PDMDevHlpMMIO2Unmap(pDevIns, pRegion->iRegion, pRegion->GCPhysPage);
    363450        if (RT_SUCCESS(rc))
    364451        {
     
    372459
    373460/**
    374  * Write access handler for a mapped MMIO2 region that presently ignores writes.
     461 * Write access handler for a mapped MMIO2 region. At present, this handler
     462 * simply ignores writes.
     463 *
     464 * In the future we might want to let the GIM provider decide what the handler
     465 * should do (like throwing #GP faults).
    375466 *
    376467 * @returns VBox status code.
     
    383474 * @param pvUser            User argument (NULL, not used).
    384475 */
    385 static DECLCALLBACK(int) gimR3Mmio2PageWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
    386                                                     PGMACCESSTYPE enmAccessType, void *pvUser)
     476static DECLCALLBACK(int) gimR3Mmio2WriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
     477                                                PGMACCESSTYPE enmAccessType, void *pvUser)
    387478{
    388479    /*
     
    402493 * @param   pRegion         Pointer to the GIM MMIO2 region.
    403494 * @param   GCPhysRegion    Where in the guest address space to map the region.
    404  * @param   pszDesc         Description of the region being mapped.
    405  */
    406 VMM_INT_DECL(int) GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCPhysRegion, const char *pszDesc)
     495 */
     496VMMR3_INT_DECL(int) GIMR3Mmio2Map(PVM pVM, PGIMMMIO2REGION pRegion, RTGCPHYS GCPhysRegion)
    407497{
    408498    PPDMDEVINS pDevIns = pVM->gim.s.pDevInsR3;
     
    412502    if (GCPhysRegion & PAGE_OFFSET_MASK)
    413503    {
    414         LogFunc(("%s: %#RGp not paging aligned\n", pszDesc, GCPhysRegion));
     504        LogFunc(("%s: %#RGp not paging aligned\n", pRegion->szDescription, GCPhysRegion));
    415505        return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
    416506    }
     
    421511    if (!PGMPhysIsGCPhysNormal(pVM, GCPhysRegion))
    422512    {
    423         LogFunc(("%s: %#RGp is not normal memory\n", pszDesc, GCPhysRegion));
     513        LogFunc(("%s: %#RGp is not normal memory\n", pRegion->szDescription, GCPhysRegion));
    424514        return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
    425515    }
    426516
    427     if (pRegion->fMapped)
    428     {
    429         LogFunc(("%s: A mapping for %#RGp already exists.\n", pszDesc, GCPhysRegion));
    430         return VERR_PGM_MAPPING_CONFLICT;
    431     }
    432 
    433     /*
    434      * Map the MMIO2 region over the guest-physical address.
     517    if (!pRegion->fRegistered)
     518    {
     519        LogFunc(("%s: Region has not been registered.\n"));
     520        return VERR_GIM_IPE_1;
     521    }
     522
     523    /*
     524     * Map the MMIO2 region over the specified guest-physical address.
    435525     */
    436526    int rc = PDMDevHlpMMIO2Map(pDevIns, pRegion->iRegion, GCPhysRegion);
     
    443533                                          PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
    444534                                          GCPhysRegion, GCPhysRegion + (pRegion->cbRegion - 1),
    445                                           gimR3Mmio2PageWriteHandler,  NULL /* pvUserR3 */,
     535                                          gimR3Mmio2WriteHandler,  NULL /* pvUserR3 */,
    446536                                          NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NIL_RTR0PTR /* pvUserR0 */,
    447537                                          NULL /* pszModRC */, NULL /* pszHandlerRC */, NIL_RTRCPTR /* pvUserRC */,
    448                                           pszDesc);
     538                                          pRegion->szDescription);
    449539        if (RT_SUCCESS(rc))
    450540        {
    451541            pRegion->fMapped    = true;
    452542            pRegion->GCPhysPage = GCPhysRegion;
    453             return VINF_SUCCESS;
     543            return rc;
    454544        }
    455545
     
    460550}
    461551
     552#if 0
     553/**
     554 * Registers the physical handler for the registered and mapped MMIO2 region.
     555 *
     556 * @returns VBox status code.
     557 * @param   pVM         Pointer to the VM.
     558 * @param   pRegion     Pointer to the GIM MMIO2 region.
     559 */
     560VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalRegister(PVM pVM, PGIMMMIO2REGION pRegion)
     561{
     562    AssertPtr(pRegion);
     563    AssertReturn(pRegion->fRegistered, VERR_GIM_IPE_2);
     564    AssertReturn(pRegion->fMapped, VERR_GIM_IPE_3);
     565
     566    return PGMR3HandlerPhysicalRegister(pVM,
     567                                        PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
     568                                        pRegion->GCPhysPage, pRegion->GCPhysPage + (pRegion->cbRegion - 1),
     569                                        gimR3Mmio2WriteHandler,  NULL /* pvUserR3 */,
     570                                        NULL /* pszModR0 */, NULL /* pszHandlerR0 */, NIL_RTR0PTR /* pvUserR0 */,
     571                                        NULL /* pszModRC */, NULL /* pszHandlerRC */, NIL_RTRCPTR /* pvUserRC */,
     572                                        pRegion->szDescription);
     573}
     574
     575
     576/**
     577 * Deregisters the physical handler for the MMIO2 region.
     578 *
     579 * @returns VBox status code.
     580 * @param   pVM         Pointer to the VM.
     581 * @param   pRegion     Pointer to the GIM MMIO2 region.
     582 */
     583VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalDeregister(PVM pVM, PGIMMMIO2REGION pRegion)
     584{
     585    return PGMHandlerPhysicalDeregister(pVM, pRegion->GCPhysPage);
     586}
     587#endif
     588
  • trunk/src/VBox/VMM/VMMR3/GIMHv.cpp

    r51560 r51643  
    2626#include <iprt/string.h>
    2727#include <iprt/mem.h>
     28#include <iprt/spinlock.h>
    2829
    2930#include <VBox/vmm/cpum.h>
     31#include <VBox/vmm/ssm.h>
    3032#include <VBox/vmm/vm.h>
    3133#include <VBox/vmm/hm.h>
     
    111113    PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
    112114    pRegion->iRegion    = GIM_HV_HYPERCALL_PAGE_REGION_IDX;
     115    pRegion->fRCMapping = false;
    113116    pRegion->cbRegion   = PAGE_SIZE;
    114117    pRegion->GCPhysPage = NIL_RTGCPHYS;
    115     RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hypercall Page");
    116     Assert(!pRegion->fRCMapping);
    117     Assert(!pRegion->fMapped);
     118    RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V hypercall page");
    118119
    119120    pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
    120121    pRegion->iRegion    = GIM_HV_REF_TSC_PAGE_REGION_IDX;
     122    pRegion->fRCMapping = false;
    121123    pRegion->cbRegion   = PAGE_SIZE;
    122124    pRegion->GCPhysPage = NIL_RTGCPHYS;
    123     RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "TSC Page");
     125    RTStrCopy(pRegion->szDescription, sizeof(pRegion->szDescription), "Hyper-V TSC page");
    124126
    125127    /*
     
    219221
    220222
     223VMMR3_INT_DECL(int) GIMR3HvTerm(PVM pVM)
     224{
     225    GIMR3HvReset(pVM);
     226    return VINF_SUCCESS;
     227}
     228
     229
    221230VMMR3_INT_DECL(void) GIMR3HvRelocate(PVM pVM, RTGCINTPTR offDelta)
    222231{
     
    239248     * Unmap MMIO2 pages that the guest may have setup.
    240249     */
     250    LogRelFunc(("Resetting Hyper-V MMIO2 regions and MSRs...\n"));
    241251    PGIMHV pHv = &pVM->gim.s.u.Hv;
    242252    for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++)
     
    272282}
    273283
     284
     285/**
     286 * Hyper-V state-save operation.
     287 *
     288 * @returns VBox status code.
     289 * @param   pVM     Pointer to the VM.
     290 * @param   pSSM    Pointer to the SSM handle.
     291 */
     292VMMR3_INT_DECL(int) GIMR3HvSave(PVM pVM, PSSMHANDLE pSSM)
     293{
     294    PCGIMHV pcHv = &pVM->gim.s.u.Hv;
     295
     296    /** @todo Save per-VCPU data. */
     297
     298    /*
     299     * Save per-VM MSRs.
     300     */
     301    int rc = SSMR3PutU64(pSSM, pcHv->u64GuestOsIdMsr);          AssertRCReturn(rc, rc);
     302    rc = SSMR3PutU64(pSSM, pcHv->u64HypercallMsr);              AssertRCReturn(rc, rc);
     303    rc = SSMR3PutU64(pSSM, pcHv->u64TscPageMsr);                AssertRCReturn(rc, rc);
     304
     305    /*
     306     * Save Hyper-V features / capabilities.
     307     */
     308    rc = SSMR3PutU32(pSSM, pcHv->uBaseFeat);                    AssertRCReturn(rc, rc);
     309    rc = SSMR3PutU32(pSSM, pcHv->uPartFlags);                   AssertRCReturn(rc, rc);
     310    rc = SSMR3PutU32(pSSM, pcHv->uPowMgmtFeat);                 AssertRCReturn(rc, rc);
     311    rc = SSMR3PutU32(pSSM, pcHv->uMiscFeat);                    AssertRCReturn(rc, rc);
     312    rc = SSMR3PutU32(pSSM, pcHv->uHyperHints);                  AssertRCReturn(rc, rc);
     313
     314    /*
     315     * Save per-VM MMIO2 regions.
     316     */
     317    rc = SSMR3PutU32(pSSM, RT_ELEMENTS(pcHv->aMmio2Regions));
     318    for (unsigned i = 0; i < RT_ELEMENTS(pcHv->aMmio2Regions); i++)
     319    {
     320        /* Save the fields necessary to remap the regions upon load.*/
     321        PCGIMMMIO2REGION pcRegion = &pcHv->aMmio2Regions[i];
     322        rc = SSMR3PutU8(pSSM,     pcRegion->iRegion);           AssertRCReturn(rc, rc);
     323        rc = SSMR3PutBool(pSSM,   pcRegion->fRCMapping);        AssertRCReturn(rc, rc);
     324        rc = SSMR3PutU32(pSSM,    pcRegion->cbRegion);          AssertRCReturn(rc, rc);
     325        rc = SSMR3PutGCPhys(pSSM, pcRegion->GCPhysPage);        AssertRCReturn(rc, rc);
     326        rc = SSMR3PutStrZ(pSSM,   pcRegion->szDescription);     AssertRCReturn(rc, rc);
     327    }
     328
     329    return VINF_SUCCESS;
     330}
     331
     332
     333/**
     334 * Hyper-V state-load operation, final pass.
     335 *
     336 * @returns VBox status code.
     337 * @param   pVM             Pointer to the VM.
     338 * @param   pSSM            Pointer to the SSM handle.
     339 * @param   uSSMVersion     The saved-state version.
     340 */
     341VMMR3_INT_DECL(int) GIMR3HvLoad(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion)
     342{
     343    PGIMHV pHv = &pVM->gim.s.u.Hv;
     344
     345    /** @todo Load per-VCPU data. */
     346
     347    /*
     348     * Load per-VM MSRs.
     349     */
     350    int rc = SSMR3GetU64(pSSM, &pHv->u64GuestOsIdMsr);          AssertRCReturn(rc, rc);
     351    rc = SSMR3GetU64(pSSM, &pHv->u64HypercallMsr);              AssertRCReturn(rc, rc);
     352    rc = SSMR3GetU64(pSSM, &pHv->u64TscPageMsr);                AssertRCReturn(rc, rc);
     353
     354    /*
     355     * Save Hyper-V features / capabilities.
     356     */
     357    rc = SSMR3GetU32(pSSM, &pHv->uBaseFeat);                    AssertRCReturn(rc, rc);
     358    rc = SSMR3GetU32(pSSM, &pHv->uPartFlags);                   AssertRCReturn(rc, rc);
     359    rc = SSMR3GetU32(pSSM, &pHv->uPowMgmtFeat);                 AssertRCReturn(rc, rc);
     360    rc = SSMR3GetU32(pSSM, &pHv->uMiscFeat);                    AssertRCReturn(rc, rc);
     361    rc = SSMR3GetU32(pSSM, &pHv->uHyperHints);                  AssertRCReturn(rc, rc);
     362
     363    /*
     364     * Load per-VM MMIO2 regions.
     365     */
     366    uint32_t cRegions;
     367    rc = SSMR3GetU32(pSSM, &cRegions);
     368    if (cRegions != RT_ELEMENTS(pHv->aMmio2Regions))
     369    {
     370        LogRelFunc(("MMIO2 region array size mismatch. size=%u expected=%u\n", cRegions, RT_ELEMENTS(pHv->aMmio2Regions)));
     371        return VERR_SSM_FIELD_INVALID_VALUE;
     372    }
     373
     374    for (unsigned i = 0; i < RT_ELEMENTS(pHv->aMmio2Regions); i++)
     375    {
     376        /* The regions would have been registered while constructing the GIM device. */
     377        PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[i];
     378        rc = SSMR3GetU8(pSSM,     &pRegion->iRegion);           AssertRCReturn(rc, rc);
     379        rc = SSMR3GetBool(pSSM,   &pRegion->fRCMapping);        AssertRCReturn(rc, rc);
     380        rc = SSMR3GetU32(pSSM,    &pRegion->cbRegion);          AssertRCReturn(rc, rc);
     381        rc = SSMR3GetGCPhys(pSSM, &pRegion->GCPhysPage);        AssertRCReturn(rc, rc);
     382        rc = SSMR3GetStrZ(pSSM,    pRegion->szDescription, sizeof(pRegion->szDescription));
     383        AssertRCReturn(rc, rc);
     384    }
     385
     386    /*
     387     * Enable the Hypercall-page.
     388     */
     389    PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
     390    if (MSR_GIM_HV_HYPERCALL_IS_ENABLED(pHv->u64HypercallMsr))
     391    {
     392        Assert(pRegion->GCPhysPage != NIL_RTGCPHYS);
     393        if (pRegion->fRegistered)
     394        {
     395            rc = GIMR3HvEnableHypercallPage(pVM, pRegion->GCPhysPage);
     396            if (RT_FAILURE(rc))
     397                return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to enable the hypercall page. GCPhys=%#RGp rc=%Rrc"),
     398                                        pRegion->GCPhysPage, rc);
     399        }
     400        else
     401            return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Hypercall MMIO2 region not registered. Missing GIM device?!"));
     402    }
     403
     404    /*
     405     * Enable the TSC-page.
     406     */
     407    pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
     408    if (MSR_GIM_HV_REF_TSC_IS_ENABLED(pHv->u64TscPageMsr))
     409    {
     410        Assert(pRegion->GCPhysPage != NIL_RTGCPHYS);
     411        if (pRegion->fRegistered)
     412        {
     413            rc = GIMR3HvEnableTscPage(pVM, pRegion->GCPhysPage);
     414            if (RT_FAILURE(rc))
     415                return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Failed to enable the TSC page. GCPhys=%#RGp rc=%Rrc"),
     416                                        pRegion->GCPhysPage, rc);
     417        }
     418        else
     419            return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("TSC-page MMIO2 region not registered. Missing GIM device?!"));
     420    }
     421
     422    return rc;
     423}
     424
     425
     426/**
     427 * Enables the Hyper-V TSC page.
     428 *
     429 * @returns VBox status code.
     430 * @param   pVM             Pointer to the VM.
     431 * @param   GCPhysTscPage   Where to map the TSC page.
     432 */
     433VMMR3_INT_DECL(int) GIMR3HvEnableTscPage(PVM pVM, RTGCPHYS GCPhysTscPage)
     434{
     435    PPDMDEVINSR3    pDevIns = pVM->gim.s.pDevInsR3;
     436    PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
     437    AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
     438
     439    int rc;
     440    if (pRegion->fMapped)
     441    {
     442        /*
     443         * Is it already enabled at the given guest-address?
     444         */
     445        if (pRegion->GCPhysPage == GCPhysTscPage)
     446            return VINF_SUCCESS;
     447
     448        /*
     449         * If it's mapped at a different address, unmap the previous address.
     450         */
     451        rc = GIMR3HvDisableTscPage(pVM);
     452        AssertRC(rc);
     453    }
     454
     455    /*
     456     * Map the TSC-page at the specified address.
     457     */
     458    Assert(!pRegion->fMapped);
     459    rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysTscPage);
     460    if (RT_SUCCESS(rc))
     461    {
     462        Assert(pRegion->GCPhysPage == GCPhysTscPage);
     463
     464        /*
     465         * Update the TSC scale. Windows guests expect a non-zero TSC sequence, otherwise
     466         * they fallback to using the reference count MSR which is not ideal in terms of VM-exits.
     467         *
     468         * Also, Hyper-V normalizes the time in 10 MHz, see:
     469         * http://technet.microsoft.com/it-it/sysinternals/dn553408%28v=vs.110%29
     470         */
     471        PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)pRegion->pvPageR3;
     472        Assert(pRefTsc);
     473
     474        uint64_t const u64TscKHz = TMCpuTicksPerSecond(pVM) / UINT64_C(1000);
     475        pRefTsc->u32TscSequence  = 1;
     476        //pRefTsc->u64TscScale     = ((UINT64_C(10000) << 32) / u64TscKHz) << 32;
     477        pRefTsc->u64TscScale     = 0xf4000000000000;
     478
     479        LogRel(("GIM: HyperV: Enabled TSC page at %#RGp (u64TscScale=%#RX64 u64TscKHz=%#RX64)\n", GCPhysTscPage,
     480                pRefTsc->u64TscScale, u64TscKHz));
     481        return VINF_SUCCESS;
     482    }
     483    else
     484        LogRelFunc(("GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
     485
     486    return VERR_GIM_OPERATION_FAILED;
     487}
     488
     489
     490/**
     491 * Disables the Hyper-V TSC page.
     492 *
     493 * @returns VBox status code.
     494 * @param   pVM     Pointer to the VM.
     495 */
     496VMMR3_INT_DECL(int) GIMR3HvDisableTscPage(PVM pVM)
     497{
     498    PGIMHV pHv = &pVM->gim.s.u.Hv;
     499    PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX];
     500    if (pRegion->fMapped)
     501    {
     502        GIMR3Mmio2Unmap(pVM, pRegion);
     503        Assert(!pRegion->fMapped);
     504        LogRel(("GIM: HyperV: Disabled TSC-page\n"));
     505        return VINF_SUCCESS;
     506    }
     507    return VERR_GIM_PVTSC_NOT_ENABLED;
     508}
     509
     510
     511/**
     512 * Disables the Hyper-V Hypercall page.
     513 *
     514 * @returns VBox status code.
     515 */
     516VMMR3_INT_DECL(int) GIMR3HvDisableHypercallPage(PVM pVM)
     517{
     518    PGIMHV pHv = &pVM->gim.s.u.Hv;
     519    PGIMMMIO2REGION pRegion = &pHv->aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
     520    if (pRegion->fMapped)
     521    {
     522        GIMR3Mmio2Unmap(pVM, pRegion);
     523        Assert(!pRegion->fMapped);
     524        LogRel(("GIM: HyperV: Disabled Hypercall-page\n"));
     525        return VINF_SUCCESS;
     526    }
     527    return VERR_GIM_HYPERCALLS_NOT_ENABLED;
     528}
     529
     530
     531/**
     532 * Enables the Hyper-V Hypercall page.
     533 *
     534 * @returns VBox status code.
     535 * @param   pVM                     Pointer to the VM.
     536 * @param   GCPhysHypercallPage     Where to map the hypercall page.
     537 */
     538VMMR3_INT_DECL(int) GIMR3HvEnableHypercallPage(PVM pVM, RTGCPHYS GCPhysHypercallPage)
     539{
     540    PPDMDEVINSR3    pDevIns = pVM->gim.s.pDevInsR3;
     541    PGIMMMIO2REGION pRegion = &pVM->gim.s.u.Hv.aMmio2Regions[GIM_HV_HYPERCALL_PAGE_REGION_IDX];
     542    AssertPtrReturn(pDevIns, VERR_GIM_DEVICE_NOT_REGISTERED);
     543
     544    if (pRegion->fMapped)
     545    {
     546        /*
     547         * Is it already enabled at the given guest-address?
     548         */
     549        if (pRegion->GCPhysPage == GCPhysHypercallPage)
     550            return VINF_SUCCESS;
     551
     552        /*
     553         * If it's mapped at a different address, unmap the previous address.
     554         */
     555        int rc2 = GIMR3HvDisableHypercallPage(pVM);
     556        AssertRC(rc2);
     557    }
     558
     559    /*
     560     * Map the hypercall-page at the specified address.
     561     */
     562    Assert(!pRegion->fMapped);
     563    int rc = GIMR3Mmio2Map(pVM, pRegion, GCPhysHypercallPage);
     564    if (RT_SUCCESS(rc))
     565    {
     566        Assert(pRegion->GCPhysPage == GCPhysHypercallPage);
     567
     568        /*
     569         * Patch the hypercall-page.
     570         */
     571        if (HMIsEnabled(pVM))
     572        {
     573            size_t cbWritten = 0;
     574            rc = HMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
     575            if (   RT_SUCCESS(rc)
     576                && cbWritten < PAGE_SIZE - 1)
     577            {
     578                uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
     579                *pbLast = 0xc3;  /* RET */
     580
     581                LogRel(("GIM: HyperV: Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
     582                return VINF_SUCCESS;
     583            }
     584            else
     585                LogRelFunc(("HMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
     586        }
     587        else
     588        {
     589            /** @todo Handle raw-mode hypercall page patching. */
     590            LogRelFunc(("Raw-mode not yet implemented!\n"));
     591        }
     592        GIMR3Mmio2Unmap(pVM, pRegion);
     593    }
     594    else
     595        LogRelFunc(("GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
     596
     597    return rc;
     598}
     599
  • trunk/src/VBox/VMM/VMMR3/HM.cpp

    r51220 r51643  
    733733        HM_REG_COUNTER(&pVCpu->hm.s.StatTlbShootdownFlush,      "/HM/CPU%d/Flush/Shootdown/TLB", "Inter-VCPU request to flush entire guest-TLB.");
    734734
     735        HM_REG_COUNTER(&pVCpu->hm.s.StatTscOffsetAdjusted,      "/HM/CPU%d/TSC/OffsetAdjusted", "TSC offset overflowed for paravirt. TSC. Fudged.");
     736        HM_REG_COUNTER(&pVCpu->hm.s.StatTscParavirt,            "/HM/CPU%d/TSC/Paravirt", "Paravirtualized TSC in effect.");
    735737        HM_REG_COUNTER(&pVCpu->hm.s.StatTscOffset,              "/HM/CPU%d/TSC/Offset", "TSC offsetting is in effect.");
    736738        HM_REG_COUNTER(&pVCpu->hm.s.StatTscIntercept,           "/HM/CPU%d/TSC/Intercept", "Guest is in catchup mode, intercept TSC accesses.");
     
    11721174    {
    11731175        CPUMClearGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_RDTSCP);
    1174         LogRel(("HM: RDTSCP disabled.\n"));
     1176        LogRel(("HM: RDTSCP disabled\n"));
    11751177    }
    11761178
     
    12411243
    12421244    LogRel((pVM->hm.s.fAllow64BitGuests
    1243             ? "HM: Guest support: 32-bit and 64-bit.\n"
    1244             : "HM: Guest support: 32-bit only.\n"));
     1245            ? "HM: Guest support: 32-bit and 64-bit\n"
     1246            : "HM: Guest support: 32-bit only\n"));
    12451247
    12461248    /*
     
    12871289            CPUMSetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
    12881290        else
    1289             LogRel(("HM: NX not enabled on the host, unavailable to PAE guest.\n"));
     1291            LogRel(("HM: NX not enabled on the host, unavailable to PAE guest\n"));
    12901292    }
    12911293
     
    12961298    {
    12971299        LogRel(("HM: Nested paging enabled!\n"));
    1298         if (pVM->hm.s.vmx.enmFlushEpt == VMX_FLUSH_EPT_SINGLE_CONTEXT)
    1299             LogRel(("HM:   EPT flush type                = VMX_FLUSH_EPT_SINGLE_CONTEXT\n"));
    1300         else if (pVM->hm.s.vmx.enmFlushEpt == VMX_FLUSH_EPT_ALL_CONTEXTS)
    1301             LogRel(("HM:   EPT flush type                = VMX_FLUSH_EPT_ALL_CONTEXTS\n"));
    1302         else if (pVM->hm.s.vmx.enmFlushEpt == VMX_FLUSH_EPT_NOT_SUPPORTED)
    1303             LogRel(("HM:   EPT flush type                = VMX_FLUSH_EPT_NOT_SUPPORTED\n"));
     1300        if (pVM->hm.s.vmx.enmFlushEpt == VMXFLUSHEPT_SINGLE_CONTEXT)
     1301            LogRel(("HM:   EPT flush type                = VMXFLUSHEPT_SINGLE_CONTEXT\n"));
     1302        else if (pVM->hm.s.vmx.enmFlushEpt == VMXFLUSHEPT_ALL_CONTEXTS)
     1303            LogRel(("HM:   EPT flush type                = VMXFLUSHEPT_ALL_CONTEXTS\n"));
     1304        else if (pVM->hm.s.vmx.enmFlushEpt == VMXFLUSHEPT_NOT_SUPPORTED)
     1305            LogRel(("HM:   EPT flush type                = VMXFLUSHEPT_NOT_SUPPORTED\n"));
    13041306        else
    13051307            LogRel(("HM:   EPT flush type                = %d\n", pVM->hm.s.vmx.enmFlushEpt));
     
    13131315            /* Use large (2 MB) pages for our EPT PDEs where possible. */
    13141316            PGMSetLargePageUsage(pVM, true);
    1315             LogRel(("HM: Large page support enabled!\n"));
     1317            LogRel(("HM: Large page support enabled\n"));
    13161318        }
    13171319#endif
     
    13231325    {
    13241326        LogRel(("HM: VPID enabled!\n"));
    1325         if (pVM->hm.s.vmx.enmFlushVpid == VMX_FLUSH_VPID_INDIV_ADDR)
    1326             LogRel(("HM:   VPID flush type               = VMX_FLUSH_VPID_INDIV_ADDR\n"));
    1327         else if (pVM->hm.s.vmx.enmFlushVpid == VMX_FLUSH_VPID_SINGLE_CONTEXT)
    1328             LogRel(("HM:   VPID flush type               = VMX_FLUSH_VPID_SINGLE_CONTEXT\n"));
    1329         else if (pVM->hm.s.vmx.enmFlushVpid == VMX_FLUSH_VPID_ALL_CONTEXTS)
    1330             LogRel(("HM:   VPID flush type               = VMX_FLUSH_VPID_ALL_CONTEXTS\n"));
    1331         else if (pVM->hm.s.vmx.enmFlushVpid == VMX_FLUSH_VPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
    1332             LogRel(("HM:   VPID flush type               = VMX_FLUSH_VPID_SINGLE_CONTEXT_RETAIN_GLOBALS\n"));
     1327        if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_INDIV_ADDR)
     1328            LogRel(("HM:   VPID flush type               = VMXFLUSHVPID_INDIV_ADDR\n"));
     1329        else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_SINGLE_CONTEXT)
     1330            LogRel(("HM:   VPID flush type               = VMXFLUSHVPID_SINGLE_CONTEXT\n"));
     1331        else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_ALL_CONTEXTS)
     1332            LogRel(("HM:   VPID flush type               = VMXFLUSHVPID_ALL_CONTEXTS\n"));
     1333        else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
     1334            LogRel(("HM:   VPID flush type               = VMXFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS\n"));
    13331335        else
    13341336            LogRel(("HM:   VPID flush type               = %d\n", pVM->hm.s.vmx.enmFlushVpid));
    13351337    }
    1336     else if (pVM->hm.s.vmx.enmFlushVpid == VMX_FLUSH_VPID_NOT_SUPPORTED)
    1337         LogRel(("HM: Ignoring VPID capabilities of CPU.\n"));
     1338    else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_NOT_SUPPORTED)
     1339        LogRel(("HM: Ignoring VPID capabilities of CPU\n"));
    13381340
    13391341    /*
     
    13471349    }
    13481350    if (pVM->hm.s.vmx.fUsePreemptTimer)
    1349         LogRel(("HM: VMX-preemption timer enabled (cPreemptTimerShift=%u).\n", pVM->hm.s.vmx.cPreemptTimerShift));
     1351        LogRel(("HM: VMX-preemption timer enabled (cPreemptTimerShift=%u)\n", pVM->hm.s.vmx.cPreemptTimerShift));
    13501352    else
    1351         LogRel(("HM: VMX-preemption timer disabled.\n"));
     1353        LogRel(("HM: VMX-preemption timer disabled\n"));
    13521354
    13531355    return VINF_SUCCESS;
     
    14651467        CPUMSetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
    14661468
    1467     LogRel(("HM: TPR patching %s.\n", (pVM->hm.s.fTprPatchingAllowed) ? "enabled" : "disabled"));
     1469    LogRel(("HM: TPR patching %s\n", (pVM->hm.s.fTprPatchingAllowed) ? "enabled" : "disabled"));
    14681470
    14691471    LogRel((pVM->hm.s.fAllow64BitGuests
    1470             ? "HM: Guest support: 32-bit and 64-bit.\n"
    1471             : "HM: Guest support: 32-bit only.\n"));
     1472            ? "HM: Guest support: 32-bit and 64-bit\n"
     1473            : "HM: Guest support: 32-bit only\n"));
    14721474
    14731475    return VINF_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

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