VirtualBox

Changeset 22343 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Aug 19, 2009 12:40:16 PM (15 years ago)
Author:
vboxsync
Message:

Attempt to detect full page table initialization early on.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/PGMInternal.h

    r22170 r22343  
    16091609#endif
    16101610    RTGCPHYS            GCPhys;
     1611
     1612    /** Access handler statistics to determine whether the guest is (re)initializing a page table. */
     1613    RTGCPTR             pvLastAccessHandlerRip;
     1614    RTGCPTR             pvLastAccessHandlerFault;
     1615    uint64_t            cLastAccessHandlerCount;
     1616
    16111617    /** The kind of page we're shadowing. (This is really a PGMPOOLKIND enum.) */
    16121618    uint8_t             enmKind;
     
    17921798    /** Profiling the pgmPoolFlushPage calls made from the RC/R0 access handler. */
    17931799    STAMPROFILE                 StatMonitorRZFlushPage;
     1800    /* Times we've detected a page table reinit. */
     1801    STAMCOUNTER                 StatMonitorRZFlushReinit;
    17941802    /** Times we've detected fork(). */
    17951803    STAMCOUNTER                 StatMonitorRZFork;
     
    18111819    /** Profiling the pgmPoolFlushPage calls made from the R3 access handler. */
    18121820    STAMPROFILE                 StatMonitorR3FlushPage;
     1821    /* Times we've detected a page table reinit. */
     1822    STAMCOUNTER                 StatMonitorR3FlushReinit;
    18131823    /** Times we've detected fork(). */
    18141824    STAMCOUNTER                 StatMonitorR3Fork;
     
    27292739        uint8_t                     abDisStatePadding[DISCPUSTATE_PADDING_SIZE];
    27302740    };
     2741
     2742    /* Count the number of pgm pool access handler calls. */
     2743    uint64_t                        cPoolAccessHandler;
    27312744
    27322745    /** @name Release Statistics
  • trunk/src/VBox/VMM/PGMPool.cpp

    r20764 r22343  
    344344    STAM_REG(pVM, &pPool->StatMonitorRZEmulateInstr,    STAMTYPE_COUNTER,   "/PGM/Pool/Monitor/RZ/EmulateInstr",    STAMUNIT_OCCURENCES,     "Times we've failed interpreting the instruction.");
    345345    STAM_REG(pVM, &pPool->StatMonitorRZFlushPage,       STAMTYPE_PROFILE,   "/PGM/Pool/Monitor/RZ/FlushPage",       STAMUNIT_TICKS_PER_CALL, "Profiling the pgmPoolFlushPage calls made from the RC/R0 access handler.");
     346    STAM_REG(pVM, &pPool->StatMonitorRZFlushReinit,     STAMTYPE_COUNTER,   "/PGM/Pool/Monitor/RZ/FlushReinit",     STAMUNIT_OCCURENCES,     "Times we've detected a page table reinit.");
    346347    STAM_REG(pVM, &pPool->StatMonitorRZFork,            STAMTYPE_COUNTER,   "/PGM/Pool/Monitor/RZ/Fork",            STAMUNIT_OCCURENCES,     "Times we've detected fork().");
    347348    STAM_REG(pVM, &pPool->StatMonitorRZHandled,         STAMTYPE_PROFILE,   "/PGM/Pool/Monitor/RZ/Handled",         STAMUNIT_TICKS_PER_CALL, "Profiling the RC/R0 access we've handled (except REP STOSD).");
     
    353354    STAM_REG(pVM, &pPool->StatMonitorR3EmulateInstr,    STAMTYPE_COUNTER,   "/PGM/Pool/Monitor/R3/EmulateInstr",    STAMUNIT_OCCURENCES,     "Times we've failed interpreting the instruction.");
    354355    STAM_REG(pVM, &pPool->StatMonitorR3FlushPage,       STAMTYPE_PROFILE,   "/PGM/Pool/Monitor/R3/FlushPage",       STAMUNIT_TICKS_PER_CALL, "Profiling the pgmPoolFlushPage calls made from the R3 access handler.");
     356    STAM_REG(pVM, &pPool->StatMonitorR3FlushReinit,     STAMTYPE_COUNTER,   "/PGM/Pool/Monitor/R3/FlushReinit",     STAMUNIT_OCCURENCES,     "Times we've detected a page table reinit.");
    355357    STAM_REG(pVM, &pPool->StatMonitorR3Fork,            STAMTYPE_COUNTER,   "/PGM/Pool/Monitor/R3/Fork",            STAMUNIT_OCCURENCES,     "Times we've detected fork().");
    356358    STAM_REG(pVM, &pPool->StatMonitorR3Handled,         STAMTYPE_PROFILE,   "/PGM/Pool/Monitor/R3/Handled",         STAMUNIT_TICKS_PER_CALL, "Profiling the R3 access we've handled (except REP STOSD).");
  • trunk/src/VBox/VMM/VMMAll/PGMAllPool.cpp

    r22337 r22343  
    820820 * @returns false if we consider it to still be a paging page.
    821821 * @param   pVM         VM Handle.
     822 * @param   pVCpu       VMCPU Handle.
    822823 * @param   pRegFrame   Trap register frame.
    823824 * @param   pDis        The disassembly info for the faulting instruction.
     
    826827 * @remark  The REP prefix check is left to the caller because of STOSD/W.
    827828 */
    828 DECLINLINE(bool) pgmPoolMonitorIsReused(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pDis, RTGCPTR pvFault)
     829DECLINLINE(bool) pgmPoolMonitorIsReused(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pDis, RTGCPTR pvFault)
    829830{
    830831#ifndef IN_RC
     
    840841    NOREF(pVM); NOREF(pvFault);
    841842#endif
     843
     844    LogFlow(("Reused instr %RGv %d at %RGv param1.flags=%x param1.reg=%d\n", pRegFrame->rip, pDis->pCurInstr->opcode, pvFault, pDis->param1.flags,  pDis->param1.base.reg_gen));
     845
     846    /* Non-supervisor mode write means it's used for something else. */
     847    if (CPUMGetGuestCPL(pVCpu, pRegFrame) != 0)
     848        return true;
    842849
    843850    switch (pDis->pCurInstr->opcode)
     
    961968                                          PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
    962969{
    963     unsigned uIncrement;
     970    unsigned uIncrement = pDis->param1.size;
    964971
    965972    Assert(pDis->mode == CPUMODE_32BIT || pDis->mode == CPUMODE_64BIT);
    966973    Assert(pRegFrame->rcx <= 0x20);
    967974
    968     if (pDis->mode == CPUMODE_32BIT)
    969         uIncrement = 4;
     975#ifdef VBOX_STRICT
     976    if (pDis->opmode == CPUMODE_32BIT)
     977        Assert(uIncrement == 4);
    970978    else
    971         uIncrement = 8;
     979        Assert(uIncrement == 8);
     980#endif
    972981
    973982    Log3(("pgmPoolAccessHandlerSTOSD\n"));
     
    11071116    PPGMPOOLPAGE    pPage = (PPGMPOOLPAGE)pvUser;
    11081117    PVMCPU          pVCpu = VMMGetCpu(pVM);
     1118    unsigned        cMaxModifications;
    11091119
    11101120    LogFlow(("pgmPoolAccessHandler: pvFault=%RGv pPage=%p:{.idx=%d} GCPhysFault=%RGp\n", pvFault, pPage, pPage->idx, GCPhysFault));
     
    11351145    Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
    11361146
     1147    /* Maximum nr of modifications depends on the guest mode. */
     1148    if (pDis->mode == CPUMODE_32BIT)
     1149        cMaxModifications = 32;
     1150    else
     1151        cMaxModifications = 16;
     1152
     1153    /*
     1154     * Incremental page table updates should weight more than random ones.
     1155     * (Only applies when started from offset 0)
     1156     */
     1157    pVCpu->pgm.s.cPoolAccessHandler++;
     1158    if (    pPage->pvLastAccessHandlerRip >= pRegFrame->rip - 0x40      /* observed loops in Windows 7 x64 */
     1159        &&  pPage->pvLastAccessHandlerRip <  pRegFrame->rip + 0x40
     1160        &&  pvFault == (pPage->pvLastAccessHandlerFault + pDis->param1.size)
     1161        &&  pVCpu->pgm.s.cPoolAccessHandler == (pPage->cLastAccessHandlerCount + 1))
     1162    {
     1163        Log(("Possible page reuse cMods=%d -> %d\n", pPage->cModifications, (pPage->cModifications + 2) * 2));
     1164        pPage->cModifications           = (pPage->cModifications + 1) * 2;
     1165        pPage->pvLastAccessHandlerFault = pvFault;
     1166        pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
     1167        if (pPage->cModifications > cMaxModifications)
     1168            STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FlushReinit));
     1169    }
     1170
    11371171    /*
    11381172     * Check if it's worth dealing with.
    11391173     */
    11401174    bool fReused = false;
    1141     if (    (   pPage->cModifications < 48   /** @todo #define */ /** @todo need to check that it's not mapping EIP. */ /** @todo adjust this! */
     1175    if (    (   pPage->cModifications < cMaxModifications   /** @todo #define */ /** @todo need to check that it's not mapping EIP. */ /** @todo adjust this! */
    11421176             || pgmPoolIsPageLocked(&pVM->pgm.s, pPage)
    11431177            )
    1144         &&  !(fReused = pgmPoolMonitorIsReused(pVM, pRegFrame, pDis, pvFault))
     1178        &&  !(fReused = pgmPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault))
    11451179        &&  !pgmPoolMonitorIsForking(pPool, pDis, GCPhysFault & PAGE_OFFSET_MASK))
    11461180    {
     
    11511185        {
    11521186             rc = pgmPoolAccessHandlerSimple(pVM, pVCpu, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault);
     1187
     1188             /* A mov instruction to change the first page table entry will be remembered so we can detect
     1189              * full page table changes early on. This will reduce the amount of unnecessary traps we'll take.
     1190              */
     1191             if (   rc == VINF_SUCCESS
     1192                 && pDis->pCurInstr->opcode == OP_MOV
     1193                 && (pvFault & PAGE_OFFSET_MASK) == 0)
     1194             {
     1195                 pPage->pvLastAccessHandlerFault = pvFault;
     1196                 pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
     1197                 pPage->pvLastAccessHandlerRip   = pRegFrame->rip;
     1198             }
     1199             else
     1200             if (pPage->pvLastAccessHandlerFault == pvFault)
     1201             {
     1202                 /* ignore the 2nd write to this page table entry. */
     1203                 pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
     1204             }
     1205             else
     1206             {
     1207                 pPage->pvLastAccessHandlerFault = 0;
     1208                 pPage->pvLastAccessHandlerRip   = 0;
     1209             }
     1210
    11531211             STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,Handled), a);
    11541212             pgmUnlock(pVM);
     
    11611219         */
    11621220        if (    pDis->pCurInstr->opcode == OP_STOSWD
    1163             &&  CPUMGetGuestCPL(pVCpu, pRegFrame) == 0
    11641221            &&  !pRegFrame->eflags.Bits.u1DF
    11651222            &&  pDis->opmode == pDis->mode
     
    11831240                &&  pDis->prefix == (PREFIX_REP | PREFIX_REX)
    11841241                &&  pRegFrame->rcx <= 0x20
    1185                 &&  pRegFrame->rcx * 4 <= PAGE_SIZE - ((uintptr_t)pvFault & PAGE_OFFSET_MASK)
    1186                 &&  !((uintptr_t)pvFault & 3)
     1242                &&  pRegFrame->rcx * 8 <= PAGE_SIZE - ((uintptr_t)pvFault & PAGE_OFFSET_MASK)
     1243                &&  !((uintptr_t)pvFault & 7)
    11871244                &&  (pRegFrame->rax == 0 || pRegFrame->rax == 0x80) /* the two values observed. */
    11881245                )
     
    41624219    pPage->cPresent = 0;
    41634220    pPage->iFirstPresent = ~0;
     4221    pPage->pvLastAccessHandlerFault = 0;
     4222    pPage->cLastAccessHandlerCount  = 0;
     4223    pPage->pvLastAccessHandlerRip   = 0;
    41644224
    41654225    /*
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