Changeset 22760 in vbox for trunk/src/VBox/VMM/VMMAll
- Timestamp:
- Sep 4, 2009 8:35:09 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/PGMAllPool.cpp
r22749 r22760 898 898 899 899 /** 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 */ 911 DECLINLINE(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. 901 976 * 902 977 * @returns VBox status code suitable for scheduling. … … 909 984 * @param GCPhysFault The fault address as guest physical address. 910 985 * @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) 1044 987 */ 1045 988 DECLINLINE(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) 1047 990 { 1048 991 Log3(("pgmPoolAccessHandlerSimple\n")); … … 1078 1021 rc = VINF_EM_RAW_EMULATE_INSTR; 1079 1022 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 } 1080 1051 } 1081 1052 … … 1197 1168 if (!(pDis->prefix & (PREFIX_REP | PREFIX_REPNE))) 1198 1169 { 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; 1230 1203 } 1231 1204 … … 1353 1326 /* 1354 1327 * 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 */ 1329 flushPage: 1330 rc = pgmPoolMonitorChainFlush(pPool, pPage); 1364 1331 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,FlushPage), a); 1365 1332 pgmUnlock(pVM); … … 1795 1762 1796 1763 /* 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); 1804 1767 } 1805 1768 … … 1975 1938 STAM_COUNTER_INC(&pPool->StatCacheKindMismatches); 1976 1939 pgmPoolFlushPage(pPool, pPage); 1977 PGM_INVL_VCPU_TLBS(VMMGetCpu(pVM)); /* see PT handler. */1978 1940 break; 1979 1941 } … … 2510 2472 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT: 2511 2473 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB: 2474 case PGMPOOLKIND_32BIT_PT_FOR_PHYS: 2475 case PGMPOOLKIND_PAE_PT_FOR_PHYS: 2512 2476 { 2513 2477 #ifdef PGMPOOL_WITH_USER_TRACKING
Note:
See TracChangeset
for help on using the changeset viewer.