VirtualBox

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


Ignore:
Timestamp:
Sep 4, 2009 8:35:09 AM (15 years ago)
Author:
vboxsync
Message:

Backed out 51884 (caused gurus) and 51924 (not responsible).
Rewrote pgmPoolAccessHandlerFlush handling.

File:
1 edited

Legend:

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

    r22749 r22760  
    898898
    899899/**
    900  * Flushes the page being accessed.
     900 * Handles the STOSD write accesses.
     901 *
     902 * @returns VBox status code suitable for scheduling.
     903 * @param   pVM         The VM handle.
     904 * @param   pPool       The pool.
     905 * @param   pPage       The pool page (head).
     906 * @param   pDis        The disassembly of the write instruction.
     907 * @param   pRegFrame   The trap register frame.
     908 * @param   GCPhysFault The fault address as guest physical address.
     909 * @param   pvFault     The fault address.
     910 */
     911DECLINLINE(int) pgmPoolAccessHandlerSTOSD(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
     912                                          PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
     913{
     914    unsigned uIncrement = pDis->param1.size;
     915
     916    Assert(pDis->mode == CPUMODE_32BIT || pDis->mode == CPUMODE_64BIT);
     917    Assert(pRegFrame->rcx <= 0x20);
     918
     919#ifdef VBOX_STRICT
     920    if (pDis->opmode == CPUMODE_32BIT)
     921        Assert(uIncrement == 4);
     922    else
     923        Assert(uIncrement == 8);
     924#endif
     925
     926    Log3(("pgmPoolAccessHandlerSTOSD\n"));
     927
     928    /*
     929     * Increment the modification counter and insert it into the list
     930     * of modified pages the first time.
     931     */
     932    if (!pPage->cModifications++)
     933        pgmPoolMonitorModifiedInsert(pPool, pPage);
     934
     935    /*
     936     * Execute REP STOSD.
     937     *
     938     * This ASSUMES that we're not invoked by Trap0e on in a out-of-sync
     939     * write situation, meaning that it's safe to write here.
     940     */
     941    PVMCPU      pVCpu = VMMGetCpu(pPool->CTX_SUFF(pVM));
     942    RTGCUINTPTR pu32 = (RTGCUINTPTR)pvFault;
     943    while (pRegFrame->rcx)
     944    {
     945#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
     946        uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
     947        pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
     948        PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
     949#else
     950        pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
     951#endif
     952#ifdef IN_RC
     953        *(uint32_t *)pu32 = pRegFrame->eax;
     954#else
     955        PGMPhysSimpleWriteGCPhys(pVM, GCPhysFault, &pRegFrame->rax, uIncrement);
     956#endif
     957        pu32           += uIncrement;
     958        GCPhysFault    += uIncrement;
     959        pRegFrame->rdi += uIncrement;
     960        pRegFrame->rcx--;
     961    }
     962    pRegFrame->rip += pDis->opsize;
     963
     964#ifdef IN_RC
     965    /* See use in pgmPoolAccessHandlerSimple(). */
     966    PGM_INVL_VCPU_TLBS(pVCpu);
     967#endif
     968
     969    LogFlow(("pgmPoolAccessHandlerSTOSD: returns\n"));
     970    return VINF_SUCCESS;
     971}
     972
     973
     974/**
     975 * Handles the simple write accesses.
    901976 *
    902977 * @returns VBox status code suitable for scheduling.
     
    909984 * @param   GCPhysFault The fault address as guest physical address.
    910985 * @param   pvFault     The fault address.
    911  */
    912 static int pgmPoolAccessHandlerFlush(PVM pVM, PVMCPU pVCpu, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
    913                                      PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
    914 {
    915     /*
    916      * First, do the flushing.
    917      */
    918     int rc = pgmPoolMonitorChainFlush(pPool, pPage);
    919 
    920     /*
    921      * Emulate the instruction (xp/w2k problem, requires pc/cr2/sp detection).
    922      * @todo: why is this necessary? an instruction restart would be sufficient, wouldn't it?
    923      */
    924     uint32_t cbWritten;
    925     int rc2 = EMInterpretInstructionCPU(pVM, pVCpu, pDis, pRegFrame, pvFault, &cbWritten);
    926     if (RT_SUCCESS(rc2))
    927         pRegFrame->rip += pDis->opsize;
    928     else if (rc2 == VERR_EM_INTERPRETER)
    929     {
    930 #ifdef IN_RC
    931         if (PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
    932         {
    933             LogFlow(("pgmPoolAccessHandlerPTWorker: Interpretation failed for patch code %04x:%RGv, ignoring.\n",
    934                      pRegFrame->cs, (RTGCPTR)pRegFrame->eip));
    935             rc = VINF_SUCCESS;
    936             STAM_COUNTER_INC(&pPool->StatMonitorRZIntrFailPatch2);
    937         }
    938         else
    939 #endif
    940         {
    941             rc = VINF_EM_RAW_EMULATE_INSTR;
    942             STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,EmulateInstr));
    943         }
    944     }
    945     else
    946         rc = rc2;
    947 
    948     /* See use in pgmPoolAccessHandlerSimple(). */
    949     PGM_INVL_VCPU_TLBS(pVCpu);
    950 
    951     LogFlow(("pgmPoolAccessHandlerPT: returns %Rrc (flushed)\n", rc));
    952     return rc;
    953 
    954 }
    955 
    956 
    957 /**
    958  * Handles the STOSD write accesses.
    959  *
    960  * @returns VBox status code suitable for scheduling.
    961  * @param   pVM         The VM handle.
    962  * @param   pPool       The pool.
    963  * @param   pPage       The pool page (head).
    964  * @param   pDis        The disassembly of the write instruction.
    965  * @param   pRegFrame   The trap register frame.
    966  * @param   GCPhysFault The fault address as guest physical address.
    967  * @param   pvFault     The fault address.
    968  */
    969 DECLINLINE(int) pgmPoolAccessHandlerSTOSD(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
    970                                           PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
    971 {
    972     unsigned uIncrement = pDis->param1.size;
    973 
    974     Assert(pDis->mode == CPUMODE_32BIT || pDis->mode == CPUMODE_64BIT);
    975     Assert(pRegFrame->rcx <= 0x20);
    976 
    977 #ifdef VBOX_STRICT
    978     if (pDis->opmode == CPUMODE_32BIT)
    979         Assert(uIncrement == 4);
    980     else
    981         Assert(uIncrement == 8);
    982 #endif
    983 
    984     Log3(("pgmPoolAccessHandlerSTOSD\n"));
    985 
    986     /*
    987      * Increment the modification counter and insert it into the list
    988      * of modified pages the first time.
    989      */
    990     if (!pPage->cModifications++)
    991         pgmPoolMonitorModifiedInsert(pPool, pPage);
    992 
    993     /*
    994      * Execute REP STOSD.
    995      *
    996      * This ASSUMES that we're not invoked by Trap0e on in a out-of-sync
    997      * write situation, meaning that it's safe to write here.
    998      */
    999     PVMCPU      pVCpu = VMMGetCpu(pPool->CTX_SUFF(pVM));
    1000     RTGCUINTPTR pu32 = (RTGCUINTPTR)pvFault;
    1001     while (pRegFrame->rcx)
    1002     {
    1003 #ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
    1004         uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
    1005         pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
    1006         PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
    1007 #else
    1008         pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
    1009 #endif
    1010 #ifdef IN_RC
    1011         *(uint32_t *)pu32 = pRegFrame->eax;
    1012 #else
    1013         PGMPhysSimpleWriteGCPhys(pVM, GCPhysFault, &pRegFrame->rax, uIncrement);
    1014 #endif
    1015         pu32           += uIncrement;
    1016         GCPhysFault    += uIncrement;
    1017         pRegFrame->rdi += uIncrement;
    1018         pRegFrame->rcx--;
    1019     }
    1020     pRegFrame->rip += pDis->opsize;
    1021 
    1022 #ifdef IN_RC
    1023     /* See use in pgmPoolAccessHandlerSimple(). */
    1024     PGM_INVL_VCPU_TLBS(pVCpu);
    1025 #endif
    1026 
    1027     LogFlow(("pgmPoolAccessHandlerSTOSD: returns\n"));
    1028     return VINF_SUCCESS;
    1029 }
    1030 
    1031 
    1032 /**
    1033  * Handles the simple write accesses.
    1034  *
    1035  * @returns VBox status code suitable for scheduling.
    1036  * @param   pVM         The VM handle.
    1037  * @param   pVCpu       The VMCPU handle.
    1038  * @param   pPool       The pool.
    1039  * @param   pPage       The pool page (head).
    1040  * @param   pDis        The disassembly of the write instruction.
    1041  * @param   pRegFrame   The trap register frame.
    1042  * @param   GCPhysFault The fault address as guest physical address.
    1043  * @param   pvFault     The fault address.
     986 * @param   pfReused    Reused state (out)
    1044987 */
    1045988DECLINLINE(int) pgmPoolAccessHandlerSimple(PVM pVM, PVMCPU pVCpu, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
    1046                                            PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
     989                                           PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault, bool *pfReused)
    1047990{
    1048991    Log3(("pgmPoolAccessHandlerSimple\n"));
     
    10781021        rc = VINF_EM_RAW_EMULATE_INSTR;
    10791022        STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,EmulateInstr));
     1023    }
     1024
     1025    if (rc == VINF_SUCCESS)
     1026    {
     1027        switch (pPage->enmKind)
     1028        {
     1029        case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
     1030        {
     1031            X86PTEPAE GstPte;
     1032            int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvFault, GCPhysFault, sizeof(GstPte));
     1033            AssertRC(rc);
     1034
     1035            /* Check the new value written by the guest. If present and with a bogus physical address, then
     1036             * it's fairly safe to assume the guest is reusing the PT.
     1037             */
     1038            if (GstPte.n.u1Present)
     1039            {
     1040                RTHCPHYS HCPhys = -1;
     1041                int rc = PGMPhysGCPhys2HCPhys(pVM, GstPte.u & X86_PTE_PAE_PG_MASK, &HCPhys);
     1042                if (rc != VINF_SUCCESS)
     1043                {
     1044                    *pfReused = true;
     1045                    STAM_COUNTER_INC(&pPool->StatForceFlushReused);
     1046                }
     1047            }
     1048            break;
     1049        }
     1050        }
    10801051    }
    10811052
     
    11971168        if (!(pDis->prefix & (PREFIX_REP | PREFIX_REPNE)))
    11981169        {
    1199              rc = pgmPoolAccessHandlerSimple(pVM, pVCpu, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault);
    1200 
    1201              /* A mov instruction to change the first page table entry will be remembered so we can detect
    1202               * full page table changes early on. This will reduce the amount of unnecessary traps we'll take.
    1203               */
    1204              if (   rc == VINF_SUCCESS
    1205                  && pDis->pCurInstr->opcode == OP_MOV
    1206                  && (pvFault & PAGE_OFFSET_MASK) == 0)
    1207              {
    1208                  pPage->pvLastAccessHandlerFault = pvFault;
    1209                  pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
    1210                  pPage->pvLastAccessHandlerRip   = pRegFrame->rip;
    1211                  /* Make sure we don't kick out a page too quickly. */
    1212                  if (pPage->cModifications > 8)
    1213                      pPage->cModifications = 2;
    1214              }
    1215              else
    1216              if (pPage->pvLastAccessHandlerFault == pvFault)
    1217              {
    1218                  /* ignore the 2nd write to this page table entry. */
    1219                  pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
    1220              }
    1221              else
    1222              {
    1223                  pPage->pvLastAccessHandlerFault = 0;
    1224                  pPage->pvLastAccessHandlerRip   = 0;
    1225              }
    1226 
    1227              STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,Handled), a);
    1228              pgmUnlock(pVM);
    1229              return rc;
     1170            rc = pgmPoolAccessHandlerSimple(pVM, pVCpu, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault, &fReused);
     1171            if (fReused)
     1172                goto flushPage;
     1173               
     1174            /* A mov instruction to change the first page table entry will be remembered so we can detect
     1175             * full page table changes early on. This will reduce the amount of unnecessary traps we'll take.
     1176             */
     1177            if (   rc == VINF_SUCCESS
     1178                && pDis->pCurInstr->opcode == OP_MOV
     1179                && (pvFault & PAGE_OFFSET_MASK) == 0)
     1180            {
     1181                pPage->pvLastAccessHandlerFault = pvFault;
     1182                pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
     1183                pPage->pvLastAccessHandlerRip   = pRegFrame->rip;
     1184                /* Make sure we don't kick out a page too quickly. */
     1185                if (pPage->cModifications > 8)
     1186                    pPage->cModifications = 2;
     1187            }
     1188            else
     1189            if (pPage->pvLastAccessHandlerFault == pvFault)
     1190            {
     1191                /* ignore the 2nd write to this page table entry. */
     1192                pPage->cLastAccessHandlerCount  = pVCpu->pgm.s.cPoolAccessHandler;
     1193            }
     1194            else
     1195            {
     1196                pPage->pvLastAccessHandlerFault = 0;
     1197                pPage->pvLastAccessHandlerRip   = 0;
     1198            }
     1199
     1200            STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,Handled), a);
     1201            pgmUnlock(pVM);
     1202            return rc;
    12301203        }
    12311204
     
    13531326    /*
    13541327     * Not worth it, so flush it.
    1355      *
    1356      * If we considered it to be reused, don't go back to ring-3
    1357      * to emulate failed instructions since we usually cannot
    1358      * interpret then. This may be a bit risky, in which case
    1359      * the reuse detection must be fixed.
    1360      */       
    1361     rc = pgmPoolAccessHandlerFlush(pVM, pVCpu, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault);
    1362     if (rc == VINF_EM_RAW_EMULATE_INSTR && fReused)
    1363         rc = VINF_SUCCESS;
     1328     */     
     1329flushPage:
     1330    rc = pgmPoolMonitorChainFlush(pPool, pPage);
    13641331    STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,FlushPage), a);
    13651332    pgmUnlock(pVM);
     
    17951762
    17961763    /*
    1797      * Found a usable page, flush it and return.
    1798      */
    1799     int rc = pgmPoolFlushPage(pPool, pPage);
    1800     /* This flush was initiated by us and not the guest, so explicitly flush the TLB. */
    1801     if (rc == VINF_SUCCESS)
    1802         PGM_INVL_ALL_VCPU_TLBS(pVM);
    1803     return rc;
     1764     * Found a usable page, flush it and return.
     1765     */
     1766    return pgmPoolFlushPage(pPool, pPage);
    18041767}
    18051768
     
    19751938                        STAM_COUNTER_INC(&pPool->StatCacheKindMismatches);
    19761939                        pgmPoolFlushPage(pPool, pPage);
    1977                         PGM_INVL_VCPU_TLBS(VMMGetCpu(pVM)); /* see PT handler. */
    19781940                        break;
    19791941                    }
     
    25102472                case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
    25112473                case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
     2474                case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
     2475                case PGMPOOLKIND_PAE_PT_FOR_PHYS:
    25122476                {
    25132477#ifdef PGMPOOL_WITH_USER_TRACKING
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