VirtualBox

Changeset 14362 in vbox


Ignore:
Timestamp:
Nov 19, 2008 5:04:25 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
39582
Message:

#1865: ring-0 mapping cache, code in progress.

File:
1 edited

Legend:

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

    r14244 r14362  
    152152
    153153
    154 
    155154/**
    156155 * Terminates the ring-0 dynamic mapping cache.
     
    159158{
    160159}
    161 
    162160
    163161
     
    183181{
    184182    NOREF(pVM);
     183}
     184
     185
     186/**
     187 * Release references to a page, caller owns the spin lock.
     188 *
     189 * @param   pThis       The dynamic mapping cache instance.
     190 * @param   iPage       The page.
     191 * @param   cRefs       The number of references to release.
     192 */
     193DECLINLINE(void) pgmR0DynMapReleasePageLocked(PPGMR0DYNMAP pThis, uint32_t iPage, int32_t cRefs)
     194{
     195    cRefs = ASMAtomicSubS32(&pThis->paPages[iPage].cRefs, cRefs);
     196    AssertMsg(cRefs >= 0, ("%d\n", cRefs));
     197    if (!cRefs)
     198        pThis->cLoad--;
     199}
     200
     201
     202/**
     203 * Release references to a page, caller does not own the spin lock.
     204 *
     205 * @param   pThis       The dynamic mapping cache instance.
     206 * @param   iPage       The page.
     207 * @param   cRefs       The number of references to release.
     208 */
     209static void pgmR0DynMapReleasePage(PPGMR0DYNMAP pThis, uint32_t iPage, uint32_t cRefs)
     210{
     211    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     212    RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
     213    pgmR0DynMapReleasePageLocked(pThis, iPage, cRefs);
     214    RTSpinlockRelease(pThis->hSpinlock, &Tmp);
     215}
     216
     217
     218/**
     219 * pgmR0DynMapPage worker that deals with the tedious bits.
     220 *
     221 * @returns The page index on success, UINT32_MAX on failure.
     222 * @param   pThis       The dynamic mapping cache instance.
     223 * @param   HCPhys      The address of the page to be mapped.
     224 * @param   iPage       The page index pgmR0DynMapPage hashed HCPhys to.
     225 */
     226static uint32_t pgmR0DynMapPageSlow(PPGMR0DYNMAP pThis, RTHCPHYS HCPhys, uint32_t iPage)
     227{
     228    /*
     229     * Check if any of the first 5 pages are unreferenced since the caller
     230     * already has made sure they aren't matching.
     231     */
     232    uint32_t const      cPages  = cPages;
     233    PPGMR0DYNMAPENTRY   paPages = pThis->paPages;
     234    uint32_t            iFreePage;
     235    if (!paPages[iPage].cRefs)
     236        iFreePage = iPage;
     237    else if (!paPages[(iPage + 1) % cPages].cRefs)
     238        iFreePage = iPage;
     239    else if (!paPages[(iPage + 2) % cPages].cRefs)
     240        iFreePage = iPage;
     241    else if (!paPages[(iPage + 3) % cPages].cRefs)
     242        iFreePage = iPage;
     243    else if (!paPages[(iPage + 4) % cPages].cRefs)
     244        iFreePage = iPage;
     245    else
     246    {
     247        /*
     248         * Search for an unused or matching entry.
     249         */
     250        iFreePage = (iPage + 5) % pThis->cPages;
     251        for (;;)
     252        {
     253            if (paPages[iFreePage].HCPhys == HCPhys)
     254                return iFreePage;
     255            if (!paPages[iFreePage].cRefs)
     256                break;
     257
     258            /* advance */
     259            iFreePage = (iFreePage + 1) % cPages;
     260            if (RT_UNLIKELY(iFreePage != iPage))
     261                return UINT32_MAX;
     262        }
     263    }
     264
     265    /*
     266     * Setup the new entry.
     267     */
     268    paPages[iFreePage].HCPhys = HCPhys;
     269    RTCpuSetFill(&paPages[iFreePage].PendingSet);
     270    if (pThis->fLegacyMode)
     271        paPages[iFreePage].uPte.pLegacy->u = (paPages[iFreePage].uPte.pLegacy->u & X86_PTE_G | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT)
     272                                           | X86_PTE_P | X86_PTE_A | X86_PTE_D
     273                                           | (HCPhys & X86_PTE_PG_MASK);
     274    else
     275        paPages[iFreePage].uPte.pPae->u    = (paPages[iFreePage].uPte.pPae->u    & X86_PTE_G | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT)
     276                                           | X86_PTE_P | X86_PTE_A | X86_PTE_D
     277                                           | (HCPhys & X86_PTE_PAE_PG_MASK);
     278    return iFreePage;
     279}
     280
     281
     282/**
     283 * Maps a page into the pool.
     284 *
     285 * @returns Pointer to the mapping.
     286 * @param   pThis       The dynamic mapping cache instance.
     287 * @param   HCPhys      The address of the page to be mapped.
     288 * @param   piPage      Where to store the page index.
     289 */
     290DECLINLINE(void *) pgmR0DynMapPage(PPGMR0DYNMAP pThis, RTHCPHYS HCPhys, uint32_t *piPage)
     291{
     292    RTSPINLOCKTMP   Tmp       = RTSPINLOCKTMP_INITIALIZER;
     293    RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
     294    AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys));
     295
     296    /*
     297     * Find an entry, if possible a matching one. The HCPhys address is hashed
     298     * down to a page index, collisions are handled by linear searching. Optimize
     299     * for a hit in the first 5 pages.
     300     *
     301     * To the cheap hits here and defer the tedious searching and inserting
     302     * to a helper function.
     303     */
     304    uint32_t const      cPages  = cPages;
     305    uint32_t            iPage   = (HCPhys >> PAGE_SHIFT) % cPages;
     306    PPGMR0DYNMAPENTRY   paPages = pThis->paPages;
     307    if (paPages[iPage].HCPhys != HCPhys)
     308    {
     309        uint32_t    iPage2 = (iPage + 1) % cPages;
     310        if (paPages[iPage2].HCPhys != HCPhys)
     311        {
     312            iPage2 = (iPage + 2) % cPages;
     313            if (paPages[iPage2].HCPhys != HCPhys)
     314            {
     315                iPage2 = (iPage + 3) % cPages;
     316                if (paPages[iPage2].HCPhys != HCPhys)
     317                {
     318                    iPage2 = (iPage + 4) % cPages;
     319                    if (paPages[iPage2].HCPhys != HCPhys)
     320                    {
     321                        iPage = pgmR0DynMapPageSlow(pThis, HCPhys, iPage);
     322                        if (RT_UNLIKELY(iPage == UINT32_MAX))
     323                        {
     324                            RTSpinlockRelease(pThis->hSpinlock, &Tmp);
     325                            return NULL;
     326                        }
     327                    }
     328                    else
     329                        iPage = iPage2;
     330                }
     331                else
     332                    iPage = iPage2;
     333            }
     334            else
     335                iPage = iPage2;
     336        }
     337        else
     338            iPage = iPage2;
     339    }
     340
     341    /*
     342     * Reference it, update statistics and get the return address.
     343     */
     344    if (ASMAtomicIncS32(&paPages[iPage].cRefs) == 1)
     345    {
     346        pThis->cLoad++;
     347        if (pThis->cLoad > pThis->cMaxLoad)
     348            pThis->cMaxLoad = pThis->cLoad;
     349        Assert(pThis->cLoad <= pThis->cPages);
     350    }
     351    void *pvPage = paPages[iPage].pvPage;
     352
     353    /*
     354     * Invalidate the entry?
     355     */
     356    RTCPUID idRealCpu = RTMpCpuId();
     357    bool fInvalidateIt = RTCpuSetIsMember(&paPages[iPage].PendingSet, idRealCpu);
     358    if (fInvalidateIt)
     359        RTCpuSetDel(&paPages[iPage].PendingSet, idRealCpu);
     360
     361    RTSpinlockRelease(pThis->hSpinlock, &Tmp);
     362
     363    /*
     364     * Do the actual invalidation outside the spinlock.
     365     */
     366    ASMInvalidatePage(pvPage);
     367
     368    *piPage = iPage;
     369    return pvPage;
    185370}
    186371
     
    229414            int32_t  cRefs = pSet->aEntries[i].cRefs;
    230415            Assert(cRefs > 0);
    231             cRefs = ASMAtomicSubS32(&pThis->paPages[iPage].cRefs, cRefs);
    232             AssertMsg(cRefs >= 0, ("%d\n", cRefs)); NOREF(cRefs);
     416            pgmR0DynMapReleasePageLocked(pThis, iPage, cRefs);
    233417        }
    234418
     419        Assert(pThis->cLoad <= pThis->cPages);
    235420        RTSpinlockRelease(pThis->hSpinlock, &Tmp);
    236421    }
     
    275460
    276461
    277 DECLINLINE(void *) pgmR0DynMapHCPhys(PPGMR0DYNMAP pThis, RTHCPHYS HCPhys)
    278 {
    279     RTSPINLOCKTMP   Tmp       = RTSPINLOCKTMP_INITIALIZER;
    280     RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
    281 
    282     /*
    283      * Find an entry, if possible a matching one.
    284      */
    285 
    286     /* First hash. */
    287     uint32_t        iPage = (HCPhys >> PAGE_SHIFT) % pThis->cPages;
    288     if (pThis->paPages[iPage].HCPhys != HCPhys)
    289     {
    290 
    291 //        uint32_t    iPage2 =
    292 //        if (pThis->paPages[iPage].cRefs)
    293 
    294     }
    295 
    296     /*
    297      * Invalidate the entry?
    298      */
    299     RTCPUID idRealCpu = RTMpCpuId();
    300     if (RTCpuSetIsMember(&pThis->paPages[iPage].PendingSet, idRealCpu))
    301     {
    302         RTCpuSetDel(&pThis->paPages[iPage].PendingSet, idRealCpu);
    303         ASMInvalidatePage(pThis->paPages[iPage].pvPage);
    304     }
    305 
    306     /*
    307      * Reference it and get the return address.
    308      */
    309     ASMAtomicIncS32(&pThis->paPages[iPage].cRefs);
    310     void *pvPage = pThis->paPages[iPage].pvPage;
    311 
    312     RTSpinlockRelease(pThis->hSpinlock, &Tmp);
    313 
    314     return pvPage;
     462/**
     463 * As a final resort for a full auto set, try merge duplicate entries.
     464 *
     465 * @param   pSet        The set.
     466 */
     467static void pgmDynMapOptimizeAutoSet(PPGMMAPSET pSet)
     468{
     469    for (uint32_t i = 0 ; i < pSet->cEntries; i++)
     470    {
     471        uint16_t const  iPage = pSet->aEntries[i].iPage;
     472        uint32_t        j     = i + 1;
     473        while (j < pSet->cEntries)
     474        {
     475            if (pSet->aEntries[j].iPage != iPage)
     476                j++;
     477            else
     478            {
     479                /* merge j with i removing j. */
     480                pSet->aEntries[i].cRefs += pSet->aEntries[j].cRefs;
     481                pSet->cEntries--;
     482                if (j < pSet->cEntries)
     483                {
     484                    pSet->aEntries[j] = pSet->aEntries[pSet->cEntries];
     485                    pSet->aEntries[pSet->cEntries].iPage = UINT16_MAX;
     486                    pSet->aEntries[pSet->cEntries].cRefs = 0;
     487                }
     488                else
     489                {
     490                    pSet->aEntries[j].iPage = UINT16_MAX;
     491                    pSet->aEntries[j].cRefs = 0;
     492                }
     493            }
     494        }
     495    }
    315496}
    316497
     
    320501{
    321502    AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys));
    322     PVMCPU          pVCpu     = VMMGetCpu(pVM);
    323     PPGMMAPSET      pSet      = &pVCpu->pgm.s.AutoSet;
     503
     504    /*
     505     * Map it.
     506     */
     507    uint32_t        iPage;
     508    void           *pvPage  = pgmR0DynMapPage(g_pPGMR0DynMap, HCPhys, &iPage);
     509    if (RT_UNLIKELY(!pvPage))
     510    {
     511        static uint32_t s_cBitched = 0;
     512        if (++s_cBitched < 10)
     513            LogRel(("PGMDynMapHCPage: cLoad=%u/%u cPages=%u\n",
     514                    g_pPGMR0DynMap->cLoad, g_pPGMR0DynMap->cMaxLoad, g_pPGMR0DynMap->cPages));
     515        return VERR_PGM_DYNMAP_FAILED;
     516    }
    324517
    325518    /*
    326519     * Add the page to the auto reference set.
    327      */
     520     * If it's less than half full, don't bother looking for duplicates.
     521     */
     522    PVMCPU          pVCpu   = VMMGetCpu(pVM);
     523    PPGMMAPSET      pSet    = &pVCpu->pgm.s.AutoSet;
     524    if (pSet->cEntries < RT_ELEMENTS(pSet->aEntries) / 2)
     525    {
     526        pSet->aEntries[pSet->cEntries].cRefs = 1;
     527        pSet->aEntries[pSet->cEntries].iPage = iPage;
     528    }
     529    else
     530    {
     531        Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
     532        int32_t     i = pSet->cEntries;
     533        while (i-- > 0)
     534            if (pSet->aEntries[i].iPage)
     535            {
     536                pSet->aEntries[i].cRefs++;
     537                break;
     538            }
     539        if (i < 0)
     540        {
     541            if (RT_UNLIKELY(pSet->cEntries >= RT_ELEMENTS(pSet->aEntries)))
     542                pgmDynMapOptimizeAutoSet(pSet);
     543            if (RT_LIKELY(pSet->cEntries < RT_ELEMENTS(pSet->aEntries)))
     544            {
     545                pSet->aEntries[pSet->cEntries].cRefs = 1;
     546                pSet->aEntries[pSet->cEntries].iPage = iPage;
     547            }
     548            else
     549            {
     550                /* We're screwed. */
     551                pgmR0DynMapReleasePage(g_pPGMR0DynMap, iPage, 1);
     552
     553                static uint32_t s_cBitched = 0;
     554                if (++s_cBitched < 10)
     555                    LogRel(("PGMDynMapHCPage: set is full!\n"));
     556                return VERR_PGM_DYNMAP_FULL_SET;
     557            }
     558        }
     559    }
    328560
    329561    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