VirtualBox

Changeset 99316 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Apr 6, 2023 3:19:22 PM (21 months ago)
Author:
vboxsync
Message:

VMM/PGM: Nested VMX: bugref:10318 Added PGMHandlerPhysicalRegisterVmxApicAccessPage which holds the PGM lock to fix registeration of the same VMX APIC-access page by multiple VCPUs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp

    r99051 r99316  
    125125
    126126/**
    127  * Creates a physical access handler, allocation part.
    128  *
    129  * @returns VBox status code.
    130  * @retval  VERR_OUT_OF_RESOURCES if no more handlers available.
    131  *
    132  * @param   pVM             The cross context VM structure.
    133  * @param   hType           The handler type registration handle.
    134  * @param   uUser           User argument to the handlers (not pointer).
    135  * @param   pszDesc         Description of this handler.  If NULL, the type
    136  *                          description will be used instead.
    137  * @param   ppPhysHandler   Where to return the access handler structure on
    138  *                          success.
    139  */
    140 int pgmHandlerPhysicalExCreate(PVMCC pVM, PGMPHYSHANDLERTYPE hType, uint64_t uUser,
    141                                R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler)
    142 {
    143     /*
    144      * Validate input.
    145      */
    146     PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
    147     AssertReturn(pType, VERR_INVALID_HANDLE);
    148     AssertReturn(pType->enmKind > PGMPHYSHANDLERKIND_INVALID && pType->enmKind < PGMPHYSHANDLERKIND_END, VERR_INVALID_HANDLE);
    149     AssertPtr(ppPhysHandler);
    150 
    151     Log(("pgmHandlerPhysicalExCreate: uUser=%#RX64 hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
    152          uUser, hType, pType->enmKind, pType->pszDesc, pszDesc, R3STRING(pszDesc)));
    153 
    154     /*
    155      * Allocate and initialize the new entry.
    156      */
    157     int rc = PGM_LOCK(pVM);
    158     AssertRCReturn(rc, rc);
    159 
     127 * Worker for pgmHandlerPhysicalExCreate.
     128 *
     129 * @returns A new physical handler on success or NULL on failure.
     130 * @param   pVM         The cross context VM structure.
     131 * @param   pType       The physical handler type.
     132 * @param   hType       The physical handler type registeration handle.
     133 * @param   uUser       User argument to the handlers (not pointer).
     134 * @param   pszDesc     Description of this handler.  If NULL, the type description
     135 *                      will be used instead.
     136 */
     137DECL_FORCE_INLINE(PPGMPHYSHANDLER) pgmHandlerPhysicalExCreateWorker(PVMCC pVM, PCPGMPHYSHANDLERTYPEINT pType,
     138                                                                    PGMPHYSHANDLERTYPE hType, uint64_t uUser,
     139                                                                    R3PTRTYPE(const char *) pszDesc)
     140{
     141    PGM_LOCK_ASSERT_OWNER(pVM);
    160142    PPGMPHYSHANDLER pNew = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.allocateNode();
    161143    if (pNew)
     
    174156                            : pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK].pszDesc;
    175157#endif
    176 
    177         PGM_UNLOCK(pVM);
    178         *ppPhysHandler = pNew;
     158    }
     159    return pNew;
     160}
     161
     162
     163/**
     164 * Creates a physical access handler, allocation part.
     165 *
     166 * @returns VBox status code.
     167 * @retval  VERR_OUT_OF_RESOURCES if no more handlers available.
     168 *
     169 * @param   pVM             The cross context VM structure.
     170 * @param   hType           The handler type registration handle.
     171 * @param   uUser           User argument to the handlers (not pointer).
     172 * @param   pszDesc         Description of this handler.  If NULL, the type
     173 *                          description will be used instead.
     174 * @param   ppPhysHandler   Where to return the access handler structure on
     175 *                          success.
     176 */
     177int pgmHandlerPhysicalExCreate(PVMCC pVM, PGMPHYSHANDLERTYPE hType, uint64_t uUser,
     178                               R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler)
     179{
     180    /*
     181     * Validate input.
     182     */
     183    PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
     184    AssertReturn(pType, VERR_INVALID_HANDLE);
     185    AssertReturn(pType->enmKind > PGMPHYSHANDLERKIND_INVALID && pType->enmKind < PGMPHYSHANDLERKIND_END, VERR_INVALID_HANDLE);
     186    AssertPtr(ppPhysHandler);
     187
     188    Log(("pgmHandlerPhysicalExCreate: uUser=%#RX64 hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
     189         uUser, hType, pType->enmKind, pType->pszDesc, pszDesc, R3STRING(pszDesc)));
     190
     191    /*
     192     * Allocate and initialize the new entry.
     193     */
     194    int rc = PGM_LOCK(pVM);
     195    AssertRCReturn(rc, rc);
     196    *ppPhysHandler = pgmHandlerPhysicalExCreateWorker(pVM, pType, hType, uUser, pszDesc);
     197    PGM_UNLOCK(pVM);
     198    if (*ppPhysHandler)
    179199        return VINF_SUCCESS;
    180     }
    181 
    182     PGM_UNLOCK(pVM);
    183200    return VERR_OUT_OF_RESOURCES;
    184201}
     
    313330
    314331/**
     332 * Worker for pgmHandlerPhysicalRegisterVmxApicAccessPage.
     333 *
     334 * @returns VBox status code.
     335 * @retval  VINF_SUCCESS when successfully installed.
     336 * @retval  VINF_PGM_GCPHYS_ALIASED could be returned.
     337 *
     338 * @param   pVM             The cross context VM structure.
     339 * @param   pPhysHandler    The physical handler.
     340 * @param   GCPhys          The address of the virtual VMX APIC-access page.
     341 */
     342static int pgmHandlerPhysicalRegisterVmxApicAccessPage(PVMCC pVM, PPGMPHYSHANDLER pPhysHandler, RTGCPHYS GCPhys)
     343{
     344    PGM_LOCK_ASSERT_OWNER(pVM);
     345    LogFunc(("GCPhys=%RGp\n", GCPhys));
     346
     347    /*
     348     * We require the range to be within registered ram.
     349     * There is no apparent need to support ranges which cover more than one ram range.
     350     */
     351    PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
     352    RTGCPHYS const GCPhysLast = GCPhys | X86_PAGE_4K_OFFSET_MASK;
     353    if (   !pRam
     354        || GCPhysLast > pRam->GCPhysLast)
     355    {
     356#ifdef IN_RING3
     357        DBGFR3Info(pVM->pUVM, "phys", NULL, NULL);
     358#endif
     359        AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
     360        return VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE;
     361    }
     362    Assert(GCPhys >= pRam->GCPhys && GCPhys < pRam->GCPhysLast);
     363    Assert(GCPhysLast <= pRam->GCPhysLast && GCPhysLast >= pRam->GCPhys);
     364
     365    /*
     366     * Try insert into list.
     367     */
     368    pPhysHandler->Key     = GCPhys;
     369    pPhysHandler->KeyLast = GCPhysLast;
     370    pPhysHandler->cPages  = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
     371
     372    int rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->insert(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, pPhysHandler);
     373    if (RT_SUCCESS(rc))
     374    {
     375        rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pPhysHandler, pRam, NULL /*pvBitmap*/, 0 /*offBitmap*/);
     376        if (rc == VINF_PGM_SYNC_CR3)
     377            rc = VINF_PGM_GCPHYS_ALIASED;
     378
     379#if defined(IN_RING3) || defined(IN_RING0)
     380        NEMHCNotifyHandlerPhysicalRegister(pVM, PGMPHYSHANDLERKIND_ALL, GCPhys, GCPhysLast - GCPhys + 1);
     381#endif
     382        return rc;
     383    }
     384
     385    pPhysHandler->Key     = NIL_RTGCPHYS;
     386    pPhysHandler->KeyLast = NIL_RTGCPHYS;
     387
     388    AssertMsgReturn(rc == VERR_ALREADY_EXISTS, ("%Rrc GCPhys=%RGp GCPhysLast=%RGp\n", rc, GCPhys, GCPhysLast), rc);
     389#if defined(IN_RING3) && defined(VBOX_STRICT)
     390    DBGFR3Info(pVM->pUVM, "handlers", "phys nostats", NULL);
     391#endif
     392    AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp\n", GCPhys, GCPhysLast));
     393    return VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
     394}
     395
     396
     397/**
    315398 * Register a access handler for a physical range.
    316399 *
     
    349432        pgmHandlerPhysicalExDestroy(pVM, pNew);
    350433    }
     434    return rc;
     435}
     436
     437
     438/**
     439 * Register an access handler for a virtual VMX APIC-access page.
     440 *
     441 * This holds the PGM lock across the whole operation to resolve races between
     442 * VCPUs registering the same page simultaneously. It's also a slightly slimmer
     443 * version of the regular registeration function as it's specific to the VMX
     444 * APIC-access page.
     445 *
     446 * @returns VBox status code.
     447 * @retval  VINF_SUCCESS when successfully installed.
     448 * @retval  VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
     449 *          the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
     450 *          flagged together with a pool clearing.
     451 * @retval  VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
     452 *          one. A debug assertion is raised.
     453 *
     454 * @param   pVM             The cross context VM structure.
     455 * @param   GCPhys          Start physical address.
     456 * @param   hType           The handler type registration handle.
     457 */
     458VMMDECL(int) PGMHandlerPhysicalRegisterVmxApicAccessPage(PVMCC pVM, RTGCPHYS GCPhys, PGMPHYSHANDLERTYPE hType)
     459{
     460    PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
     461    AssertReturn(pType, VERR_INVALID_HANDLE);
     462    AssertReturn(pType->enmKind == PGMPHYSHANDLERKIND_ALL, VERR_INVALID_HANDLE);
     463    AssertMsgReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_INVALID_PARAMETER);
     464
     465    /*
     466     * Find if the VMX APIC access page has already been registered at this address.
     467     */
     468    int rc = PGM_LOCK_VOID(pVM);
     469    AssertRCReturn(rc, rc);
     470
     471    PPGMPHYSHANDLER pHandler;
     472    rc = pgmHandlerPhysicalLookup(pVM, GCPhys, &pHandler);
     473    if (RT_SUCCESS(rc))
     474    {
     475        PCPGMPHYSHANDLERTYPEINT const pHandlerType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pHandler);
     476        Assert(GCPhys >= pHandler->Key && GCPhys <= pHandler->KeyLast);
     477        Assert(   pHandlerType->enmKind == PGMPHYSHANDLERKIND_WRITE
     478               || pHandlerType->enmKind == PGMPHYSHANDLERKIND_ALL
     479               || pHandlerType->enmKind == PGMPHYSHANDLERKIND_MMIO);
     480
     481        /* Check it's the virtual VMX APIC-access page. */
     482        if (   pHandlerType->fNotInHm
     483            && pHandlerType->enmKind == PGMPHYSHANDLERKIND_ALL)
     484            rc = VINF_SUCCESS;
     485        else
     486        {
     487            rc = VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
     488            AssertMsgFailed(("Conflict! GCPhys=%RGp enmKind=%#x fNotInHm=%RTbool\n", GCPhys, pHandlerType->enmKind,
     489                             pHandlerType->fNotInHm));
     490        }
     491
     492        PGM_UNLOCK(pVM);
     493        return rc;
     494    }
     495
     496    /*
     497     * Create and register a physical handler for the virtual VMX APIC-access page.
     498     */
     499    pHandler = pgmHandlerPhysicalExCreateWorker(pVM, pType, hType, 0 /*uUser*/, NULL /*pszDesc*/);
     500    if (pHandler)
     501    {
     502        rc = pgmHandlerPhysicalRegisterVmxApicAccessPage(pVM, pHandler, GCPhys);
     503        if (RT_SUCCESS(rc))
     504        { /* likely */ }
     505        else
     506            pgmHandlerPhysicalExDestroy(pVM, pHandler);
     507    }
     508    else
     509        rc = VERR_OUT_OF_RESOURCES;
     510
     511    PGM_UNLOCK(pVM);
    351512    return rc;
    352513}
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