VirtualBox

Changeset 14528 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Nov 24, 2008 4:04:48 PM (16 years ago)
Author:
vboxsync
Message:

PGMR0DynMap: fixes & testcase (PGMDynMapHCPage now works).

File:
1 edited

Legend:

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

    r14519 r14528  
    206206static int  pgmR0DynMapExpand(PPGMR0DYNMAP pThis);
    207207static void pgmR0DynMapTearDown(PPGMR0DYNMAP pThis);
     208#ifdef DEBUG
     209static int  pgmR0DynMapTest(PVM pVM);
     210#endif
    208211
    209212
     
    353356    RTSemFastMutexRelease(pThis->hInitLock);
    354357
     358#ifdef DEBUG
     359    /*
     360     * Run some tests.
     361     */
     362    if (RT_SUCCESS(rc))
     363        pgmR0DynMapTest(pVM);
     364#endif
    355365    return rc;
    356366}
     
    10401050     * already has made sure they aren't matching.
    10411051     */
    1042     uint32_t const      cPages  = cPages;
     1052    uint32_t const      cPages  = pThis->cPages;
    10431053    PPGMR0DYNMAPENTRY   paPages = pThis->paPages;
    10441054    uint32_t            iFreePage;
     
    11241134     * to a helper function.
    11251135     */
    1126     uint32_t const      cPages  = cPages;
     1136    uint32_t const      cPages  = pThis->cPages;
    11271137    uint32_t            iPage   = (HCPhys >> PAGE_SHIFT) % cPages;
    11281138    PPGMR0DYNMAPENTRY   paPages = pThis->paPages;
     
    11641174     * Reference it, update statistics and get the return address.
    11651175     */
    1166     if (ASMAtomicIncS32(&paPages[iPage].cRefs) == 1)
     1176    int32_t cRefs = ASMAtomicIncS32(&paPages[iPage].cRefs);
     1177    if (cRefs == 1)
    11671178    {
    11681179        pThis->cLoad++;
     
    11701181            pThis->cMaxLoad = pThis->cLoad;
    11711182        Assert(pThis->cLoad <= pThis->cPages);
     1183    }
     1184    else if (RT_UNLIKELY(cRefs <= 0))
     1185    {
     1186        ASMAtomicDecS32(&paPages[iPage].cRefs);
     1187        RTSpinlockRelease(pThis->hSpinlock, &Tmp);
     1188        AssertLogRelMsgFailedReturn(("cRefs=%d iPage=%p HCPhys=%RHp\n", cRefs, iPage, HCPhys), NULL);
    11721189    }
    11731190    void *pvPage = paPages[iPage].pvPage;
     
    13001317            if (pSet->aEntries[j].iPage != iPage)
    13011318                j++;
    1302             else
     1319            else if ((uint32_t)pSet->aEntries[i].cRefs + (uint32_t)pSet->aEntries[j].cRefs < UINT16_MAX)
    13031320            {
    1304                 /* merge j with i removing j. */
     1321                /* merge j into i removing j. */
    13051322                pSet->aEntries[i].cRefs += pSet->aEntries[j].cRefs;
    13061323                pSet->cEntries--;
     
    13171334                }
    13181335            }
     1336            else
     1337            {
     1338                /* migrate the max number of refs from j into i and quit the inner loop. */
     1339                uint32_t cMigrate = UINT16_MAX - 1 - pSet->aEntries[i].cRefs;
     1340                Assert(pSet->aEntries[j].cRefs > cMigrate);
     1341                pSet->aEntries[j].cRefs -= cMigrate;
     1342                pSet->aEntries[i].cRefs = UINT16_MAX - 1;
     1343                break;
     1344            }
    13191345        }
    13201346    }
     
    13281354     * Validate state.
    13291355     */
     1356    AssertPtr(ppv);
     1357    *ppv = NULL;
    13301358    AssertMsgReturn(pVM->pgm.s.pvR0DynMapUsed == g_pPGMR0DynMap,
    13311359                    ("%p != %p\n", pVM->pgm.s.pvR0DynMapUsed, g_pPGMR0DynMap),
     
    13351363    PPGMMAPSET      pSet    = &pVCpu->pgm.s.AutoSet;
    13361364    AssertPtrReturn(pVCpu, VERR_INTERNAL_ERROR);
    1337     AssertMsgReturn(pSet->cEntries > RT_ELEMENTS(pSet->aEntries),
     1365    AssertMsgReturn(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries),
    13381366                    ("%#x (%u)\n", pSet->cEntries, pSet->cEntries), VERR_WRONG_ORDER);
    13391367
     
    13511379        return VERR_PGM_DYNMAP_FAILED;
    13521380    }
     1381    *ppv = pvPage;
    13531382
    13541383    /*
     
    13601389        pSet->aEntries[pSet->cEntries].cRefs = 1;
    13611390        pSet->aEntries[pSet->cEntries].iPage = iPage;
     1391        pSet->cEntries++;
    13621392    }
    13631393    else
     
    13661396        int32_t     i = pSet->cEntries;
    13671397        while (i-- > 0)
    1368             if (pSet->aEntries[i].iPage)
     1398            if (    pSet->aEntries[i].iPage == iPage
     1399                &&  pSet->aEntries[i].cRefs < UINT16_MAX - 1)
    13691400            {
    13701401                pSet->aEntries[i].cRefs++;
     
    13791410                pSet->aEntries[pSet->cEntries].cRefs = 1;
    13801411                pSet->aEntries[pSet->cEntries].iPage = iPage;
     1412                pSet->cEntries++;
    13811413            }
    13821414            else
     
    13881420                if (++s_cBitched < 10)
    13891421                    LogRel(("PGMDynMapHCPage: set is full!\n"));
     1422                *ppv = NULL;
    13901423                return VERR_PGM_DYNMAP_FULL_SET;
    13911424            }
     
    13961429}
    13971430
     1431
     1432#ifdef DEBUG
     1433/**
     1434 * Performs some basic tests in debug builds.
     1435 */
     1436static int pgmR0DynMapTest(PVM pVM)
     1437{
     1438    PPGMR0DYNMAP    pThis = g_pPGMR0DynMap;
     1439    PPGMMAPSET      pSet  = &pVM->aCpus[0].pgm.s.AutoSet;
     1440
     1441    /*
     1442     * Simple test, map CR3 twice and check that we're getting the
     1443     * same mapping address back.
     1444     */
     1445    LogRel(("pgmR0DynMapTest: 1\n"));
     1446    ASMIntDisable();
     1447    PGMDynMapStartAutoSet(&pVM->aCpus[0]);
     1448
     1449    uint64_t cr3 = ASMGetCR3() & ~(uint64_t)PAGE_OFFSET_MASK;
     1450    void    *pv  = (void *)(intptr_t)-1;
     1451    void    *pv2 = (void *)(intptr_t)-2;
     1452    int      rc  = PGMDynMapHCPage(pVM, cr3, &pv);
     1453    int      rc2 = PGMDynMapHCPage(pVM, cr3, &pv2);
     1454    ASMIntEnable();
     1455    if (    RT_SUCCESS(rc2)
     1456        &&  RT_SUCCESS(rc)
     1457        &&  pv == pv2)
     1458    {
     1459        LogRel(("Load=%u/%u/%u Set=%u/%u\n", pThis->cLoad, pThis->cMaxLoad, pThis->cPages, pSet->cEntries, RT_ELEMENTS(pSet->aEntries)));
     1460
     1461        /*
     1462         * Check that the simple set overflow code works by filling it
     1463         * with more CR3 mappings.
     1464         */
     1465        LogRel(("pgmR0DynMapTest: 2\n"));
     1466        ASMIntDisable();
     1467        for (uint32_t i = 0 ; i < UINT16_MAX*2 + RT_ELEMENTS(pSet->aEntries) / 2 && RT_SUCCESS(rc) && pv2 == pv; i++)
     1468        {
     1469            pv2 = (void *)(intptr_t)-4;
     1470            rc = PGMDynMapHCPage(pVM, cr3, &pv2);
     1471        }
     1472        ASMIntEnable();
     1473        if (RT_FAILURE(rc) || pv != pv2)
     1474        {
     1475            LogRel(("failed(%d): rc=%Rrc; pv=%p pv2=%p\n", __LINE__, rc, pv, pv2));
     1476            if (RT_SUCCESS(rc2)) rc2 = VERR_INTERNAL_ERROR;
     1477        }
     1478        else if (pSet->cEntries != RT_ELEMENTS(pSet->aEntries) / 2)
     1479        {
     1480            LogRel(("failed(%d): cEntries=%d expected %d\n", __LINE__, pSet->cEntries, RT_ELEMENTS(pSet->aEntries) / 2));
     1481            rc = VERR_INTERNAL_ERROR;
     1482        }
     1483        else if (   pSet->aEntries[(RT_ELEMENTS(pSet->aEntries) / 2) - 1].cRefs != UINT16_MAX - 1
     1484                 || pSet->aEntries[(RT_ELEMENTS(pSet->aEntries) / 2) - 2].cRefs != UINT16_MAX - 1
     1485                 || pSet->aEntries[(RT_ELEMENTS(pSet->aEntries) / 2) - 3].cRefs != 2+2+3
     1486                 || pSet->aEntries[(RT_ELEMENTS(pSet->aEntries) / 2) - 4].cRefs != 1)
     1487        {
     1488            LogRel(("failed(%d): bad set dist: ", __LINE__));
     1489            for (uint32_t i = 0; i < pSet->cEntries; i++)
     1490                LogRel(("[%d]=%d, ", i, pSet->aEntries[i].cRefs));
     1491            LogRel(("\n"));
     1492            rc = VERR_INTERNAL_ERROR;
     1493        }
     1494        if (RT_SUCCESS(rc))
     1495        {
     1496            /*
     1497             * Trigger an set optimization run (exactly).
     1498             */
     1499            LogRel(("pgmR0DynMapTest: 2\n"));
     1500            ASMIntDisable();
     1501            for (uint32_t i = 0 ; i < RT_ELEMENTS(pSet->aEntries) / 2 && RT_SUCCESS(rc) && pv2 != pv; i++)
     1502            {
     1503                pv2 = (void *)(intptr_t)(-5 - i);
     1504                rc = PGMDynMapHCPage(pVM, cr3 + (PAGE_SIZE * i), &pv2);
     1505            }
     1506            ASMIntEnable();
     1507            if (RT_FAILURE(rc) || pv == pv2)
     1508            {
     1509                LogRel(("failed(%d): rc=%Rrc; pv=%p pv2=%p\n", __LINE__, rc, pv, pv2));
     1510                if (RT_SUCCESS(rc2)) rc2 = VERR_INTERNAL_ERROR;
     1511            }
     1512            else if (pSet->cEntries != RT_ELEMENTS(pSet->aEntries) / 2 + 3)
     1513            {
     1514                LogRel(("failed(%d): cEntries=%d expected %d\n", __LINE__, pSet->cEntries, RT_ELEMENTS(pSet->aEntries) / 2 + 3));
     1515                rc = VERR_INTERNAL_ERROR;
     1516            }
     1517        }
     1518        LogRel(("Load=%u/%u/%u Set=%u/%u\n", pThis->cLoad, pThis->cMaxLoad, pThis->cPages, pSet->cEntries, RT_ELEMENTS(pSet->aEntries)));
     1519    }
     1520    else
     1521    {
     1522        LogRel(("failed(%d): rc=%Rrc rc2=%Rrc; pv=%p pv2=%p\n", __LINE__, rc, rc2, pv, pv2));
     1523        if (RT_SUCCESS(rc))
     1524            rc = rc2;
     1525    }
     1526
     1527    /* clean up */
     1528    LogRel(("pgmR0DynMapTest: cleanup\n"));
     1529    ASMIntDisable();
     1530    PGMDynMapMigrateAutoSet(&pVM->aCpus[0]);
     1531    PGMDynMapReleaseAutoSet(&pVM->aCpus[0]);
     1532    ASMIntEnable();
     1533
     1534    LogRel(("Load=%u/%u/%u Set=%#x/%u\n", pThis->cLoad, pThis->cMaxLoad, pThis->cPages, pSet->cEntries, RT_ELEMENTS(pSet->aEntries)));
     1535    return rc;
     1536}
     1537#endif /* DEBUG */
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