- Timestamp:
- Apr 11, 2007 1:33:28 PM (18 years ago)
- Location:
- trunk/src/VBox/VMM/PATM
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/PATM/PATM.cpp
r1926 r2030 233 233 STAM_REG(pVM, &pVM->patm.s.StatPatchWriteInterpreted, STAMTYPE_COUNTER, "/PATM/Write/Interpreted/Success", STAMUNIT_OCCURENCES, "Nr of interpreted patch writes."); 234 234 STAM_REG(pVM, &pVM->patm.s.StatPatchWriteInterpretedFailed, STAMTYPE_COUNTER, "/PATM/Write/Interpreted/Failed", STAMUNIT_OCCURENCES, "Nr of failed interpreted patch writes."); 235 236 STAM_REG(pVM, &pVM->patm.s.StatPatchRefreshSuccess, STAMTYPE_COUNTER, "/PATM/Refresh/Success", STAMUNIT_OCCURENCES, "Successful patch refreshes"); 237 STAM_REG(pVM, &pVM->patm.s.StatPatchRefreshFailed, STAMTYPE_COUNTER, "/PATM/Refresh/Failure", STAMUNIT_OCCURENCES, "Failed patch refreshes"); 235 238 236 239 STAM_REG(pVM, &pVM->patm.s.StatPatchPageInserted, STAMTYPE_COUNTER, "/PATM/Page/Inserted", STAMUNIT_OCCURENCES, "Nr of inserted guest pages that were patched"); … … 1166 1169 pPatchToGuestRec->pOrgInstrGC = pInstrGC; 1167 1170 pPatchToGuestRec->enmType = enmType; 1168 pPatchToGuestRec->fDirty 1171 pPatchToGuestRec->fDirty = fDirty; 1169 1172 1170 1173 ret = RTAvlU32Insert(&pPatch->Patch2GuestAddrTree, &pPatchToGuestRec->Core); … … 3075 3078 * @returns VBox status code. 3076 3079 * @param pVM The VM to operate on. 3077 * @param pCpu Disassembly CPU structure ptr3078 3080 * @param pInstrGC Guest context point to privileged instruction 3079 3081 * @param pPatchRec Patch record 3080 3082 * 3081 3083 */ 3082 static int patmDuplicateFunction(PVM pVM, DISCPUSTATE *pCpu,RTGCPTR pInstrGC, PPATMPATCHREC pPatchRec)3084 static int patmDuplicateFunction(PVM pVM, RTGCPTR pInstrGC, PPATMPATCHREC pPatchRec) 3083 3085 { 3084 3086 PPATCHINFO pPatch = &pPatchRec->patch; … … 3241 3243 pPatchTargetGC = patmGuestGCPtrToPatchGCPtr(pVM, pPatch, pInstrGC); 3242 3244 if (pPatchTargetGC) 3245 { 3246 uint32_t offsetPatch = pPatchTargetGC - pVM->patm.s.pPatchMemGC; 3247 PRECPATCHTOGUEST pPatchToGuestRec = (PRECPATCHTOGUEST)RTAvlU32GetBestFit(&pPatch->Patch2GuestAddrTree, offsetPatch, false); 3248 Assert(pPatchToGuestRec); 3249 3250 pPatchToGuestRec->fJumpTarget = true; 3251 Assert(pPatchTargetGC != pPatch->pPrivInstrGC); 3252 Log(("patmCreateTrampoline: generating jump to code inside patch at %VGv\n", pPatch->pPrivInstrGC)); 3253 pPatch->flags |= PATMFL_EXTERNAL_JUMP_INSIDE; 3243 3254 break; 3255 } 3244 3256 } 3245 3257 } … … 4156 4168 if (pPatchRec->patch.flags & (PATMFL_DUPLICATE_FUNCTION )) 4157 4169 { 4158 rc = patmDuplicateFunction(pVM, &cpu,pInstrGC, pPatchRec);4170 rc = patmDuplicateFunction(pVM, pInstrGC, pPatchRec); 4159 4171 } 4160 4172 else … … 4900 4912 { 4901 4913 TRPMR3SetGuestTrapHandler(pVM, iGate, TRPM_INVALID_HANDLER); 4902 LogRel((" Disabling IDT %x patch handler %VGv\n", iGate, pInstrGC));4914 LogRel(("PATM: Disabling IDT %x patch handler %VGv\n", iGate, pInstrGC)); 4903 4915 } 4904 4916 } … … 5307 5319 5308 5320 /** 5321 * Attempt to refresh the patch by recompiling its entire code block 5322 * 5323 * @returns VBox status code. 5324 * @param pVM The VM to operate on. 5325 * @param pPatchRec Patch record 5326 */ 5327 int patmR3RefreshPatch(PVM pVM, PPATMPATCHREC pPatchRec) 5328 { 5329 PPATCHINFO pPatch; 5330 int rc; 5331 RTGCPTR pInstrGC = pPatchRec->patch.pPrivInstrGC; 5332 5333 Log(("patmR3RefreshPatch: attempt to refresh patch at %VGv\n", pInstrGC)); 5334 5335 pPatch = &pPatchRec->patch; 5336 AssertReturn(pPatch->flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_IDTHANDLER|PATMFL_TRAPHANDLER), VERR_PATCHING_REFUSED); 5337 AssertReturn(!(pPatch->flags & PATMFL_EXTERNAL_JUMP_INSIDE), VERR_PATCHING_REFUSED); 5338 5339 /** Note: quite ugly to enable/disable/remove/insert old and new patches, but there's no easy way around it. */ 5340 5341 rc = PATMR3DisablePatch(pVM, pInstrGC); 5342 AssertRC(rc); 5343 5344 /** Kick it out of the lookup tree to make sure PATMR3InstallPatch doesn't fail (hack alert) */ 5345 RTAvloGCPtrRemove(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pPatchRec->Core.Key); 5346 #ifdef VBOX_WITH_STATISTICS 5347 if (PATM_STAT_INDEX_IS_VALID(pPatchRec->patch.uPatchIdx)) 5348 { 5349 STAMR3Deregister(pVM, &pPatchRec->patch); 5350 #ifndef DEBUG_sandervl 5351 STAMR3Deregister(pVM, &pVM->patm.s.pStatsHC[pPatchRec->patch.uPatchIdx]); 5352 STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchBlockSize); 5353 STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchJump); 5354 STAMR3Deregister(pVM, &pPatchRec->patch.cbPrivInstr); 5355 STAMR3Deregister(pVM, &pPatchRec->patch.cCodeWrites); 5356 STAMR3Deregister(pVM, &pPatchRec->patch.cInvalidWrites); 5357 STAMR3Deregister(pVM, &pPatchRec->patch.cTraps); 5358 STAMR3Deregister(pVM, &pPatchRec->patch.flags); 5359 STAMR3Deregister(pVM, &pPatchRec->patch.nrJumpRecs); 5360 STAMR3Deregister(pVM, &pPatchRec->patch.nrFixups); 5361 STAMR3Deregister(pVM, &pPatchRec->patch.opcode); 5362 STAMR3Deregister(pVM, &pPatchRec->patch.uState); 5363 STAMR3Deregister(pVM, &pPatchRec->patch.uOldState); 5364 STAMR3Deregister(pVM, &pPatchRec->patch.uOpMode); 5365 #endif 5366 } 5367 #endif 5368 5369 /** Note: We don't attempt to reuse patch memory here as it's quite common that the new code block requires more memory. */ 5370 5371 /* Attempt to install a new patch. */ 5372 rc = PATMR3InstallPatch(pVM, pInstrGC, pPatch->flags & (PATMFL_CODE32|PATMFL_IDTHANDLER|PATMFL_INTHANDLER|PATMFL_TRAPHANDLER|PATMFL_DUPLICATE_FUNCTION|PATMFL_TRAPHANDLER_WITH_ERRORCODE|PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT)); 5373 if (VBOX_SUCCESS(rc)) 5374 { 5375 RTGCPTR pPatchTargetGC; 5376 PPATMPATCHREC pNewPatchRec; 5377 5378 /* Determine target address in new patch */ 5379 pPatchTargetGC = PATMR3QueryPatchGCPtr(pVM, pInstrGC); 5380 Assert(pPatchTargetGC); 5381 if (!pPatchTargetGC) 5382 { 5383 rc = VERR_PATCHING_REFUSED; 5384 goto failure; 5385 } 5386 5387 /* Reset offset into patch memory to put the next code blocks right at the beginning. */ 5388 pPatch->uCurPatchOffset = 0; 5389 5390 /* insert jump to new patch in old patch block */ 5391 rc = patmPatchGenPatchJump(pVM, pPatch, pInstrGC, pPatchTargetGC, false /* no lookup record */); 5392 if (VBOX_FAILURE(rc)) 5393 goto failure; 5394 5395 pNewPatchRec = (PPATMPATCHREC)RTAvloGCPtrGet(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC); 5396 Assert(pNewPatchRec); /* can't fail */ 5397 5398 /* Remove old patch (only do that when everything is finished) */ 5399 int rc2 = PATMRemovePatch(pVM, pPatchRec, true /* force removal */); 5400 AssertRC(rc2); 5401 5402 /* Put the new patch back into the tree, because removing the old one kicked this one out. (hack alert) */ 5403 RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pNewPatchRec->Core); 5404 5405 LogRel(("PATM: patmR3RefreshPatch: succeeded to refresh patch at %VGv \n", pInstrGC)); 5406 STAM_COUNTER_INC(&pVM->patm.s.StatPatchRefreshSuccess); 5407 } 5408 5409 failure: 5410 if (VBOX_FAILURE(rc)) 5411 { 5412 LogRel(("PATM: patmR3RefreshPatch: failed to refresh patch at %VGv. Reactiving old one. \n", pInstrGC)); 5413 5414 /* Remove the new inactive patch */ 5415 rc = PATMR3RemovePatch(pVM, pInstrGC); 5416 AssertRC(rc); 5417 5418 /* Put the old patch back into the tree (or else it won't be saved) (hack alert) */ 5419 RTAvloGCPtrInsert(&pVM->patm.s.PatchLookupTreeHC->PatchTree, &pPatchRec->Core); 5420 5421 /* Enable again in case the dirty instruction is near the end and there are safe code paths. */ 5422 int rc2 = PATMR3EnablePatch(pVM, pInstrGC); 5423 AssertRC(rc2); 5424 5425 STAM_COUNTER_INC(&pVM->patm.s.StatPatchRefreshFailed); 5426 } 5427 return rc; 5428 } 5429 5430 /** 5309 5431 * Find patch for privileged instruction at specified location 5310 5432 * … … 5614 5736 while (true) 5615 5737 { 5738 if (pRec->fJumpTarget) 5739 { 5740 LogRel(("PATM: patmR3HandleDirtyInstr: dirty instruction at %VGv (%VGv) ignored, because instruction in function was reused as target of jump\n", pEip, pPatchToGuestRec->pOrgInstrGC)); 5741 pRec->fDirty = false; 5742 return VERR_PATCHING_REFUSED; 5743 } 5744 5616 5745 /* Restore original instruction opcode byte so we can check if the write was indeed safe. */ 5617 5746 pCurPatchInstrHC = patmPatchGCPtr2PatchHCPtr(pVM, pCurPatchInstrGC); … … 5620 5749 /* Only harmless instructions are acceptable. */ 5621 5750 rc = CPUMR3DisasmInstrCPU(pVM, pCtx, pCurPatchInstrGC, &CpuOld, 0); 5622 if (VBOX_FAILURE(rc) || !(CpuOld.pCurInstr->optype & OPTYPE_HARMLESS)) 5751 if ( VBOX_FAILURE(rc) 5752 || !(CpuOld.pCurInstr->optype & OPTYPE_HARMLESS)) 5623 5753 break; 5624 5754 … … 5729 5859 /* Mark the whole instruction stream with breakpoints. */ 5730 5860 memset(pPatchInstrHC, 0xCC, cbDirty); 5861 5862 if ( pVM->patm.s.fOutOfMemory == false 5863 && (pPatch->patch.flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_IDTHANDLER|PATMFL_TRAPHANDLER))) 5864 { 5865 rc = patmR3RefreshPatch(pVM, pPatch); 5866 if (VBOX_FAILURE(rc)) 5867 { 5868 LogRel(("PATM: Failed to refresh dirty patch at %VGv. Disabling it.\n", pPatch->patch.pPrivInstrGC)); 5869 } 5870 /* Even if we succeed, we must go back to the original instruction as the patched one could be invalid. */ 5871 rc = VERR_PATCHING_REFUSED; 5872 } 5731 5873 } 5732 5874 return rc; … … 5873 6015 } 5874 6016 else 6017 { 6018 /* Reset the PATM stack. */ 6019 CTXSUFF(pVM->patm.s.pGCState)->Psp = PATM_STACK_SIZE; 6020 5875 6021 rc = VINF_SUCCESS; /* Continue at original instruction. */ 6022 } 5876 6023 5877 6024 *ppNewEip = pNewEip; -
trunk/src/VBox/VMM/PATM/PATMInternal.h
r1875 r2030 37 37 38 38 39 #define PATM_SSM_VERSION 5 239 #define PATM_SSM_VERSION 53 40 40 41 41 /* Enable for call patching. */ … … 70 70 #define PATMFL_MUST_INSTALL_PATCHJMP BIT64(31) /** Need to patch guest code in order to activate patch. */ 71 71 #define PATMFL_INT3_REPLACEMENT_BLOCK BIT64(32) /** int 3 replacement block */ 72 #define PATMFL_EXTERNAL_JUMP_INSIDE BIT64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */ 72 73 73 74 #define SIZEOF_NEARJUMP8 2 //opcode byte + 1 byte relative offset … … 90 91 #define PATM_MAX_CALL_DEPTH 32 91 92 /* Maximum nr of writes before a patch is marked dirty. (disabled) */ 92 #define PATM_MAX_CODE_WRITES 1693 #define PATM_MAX_CODE_WRITES 32 93 94 /* Maximum nr of invalid writes before a patch is disabled. */ 94 95 #define PATM_MAX_INVALID_WRITES 16384 … … 178 179 PATM_LOOKUP_TYPE enmType; 179 180 bool fDirty; 181 bool fJumpTarget; 180 182 uint8_t u8DirtyOpcode; /* original opcode before writing 0xCC there to mark it dirty */ 181 183 } RECPATCHTOGUEST, *PRECPATCHTOGUEST; … … 485 487 STAMCOUNTER StatPatchPageRemoved; 486 488 489 STAMCOUNTER StatPatchRefreshSuccess; 490 STAMCOUNTER StatPatchRefreshFailed; 491 487 492 STAMCOUNTER StatGenRet; 488 493 STAMCOUNTER StatGenRetReused; -
trunk/src/VBox/VMM/PATM/PATMPatch.cpp
r1465 r2030 1531 1531 * Relative jump from patch code to patch code (no fixup required) 1532 1532 */ 1533 int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC )1533 int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC, bool fAddLookupRecord) 1534 1534 { 1535 1535 int32_t displ; … … 1539 1539 PATCHGEN_PROLOG(pVM, pPatch); 1540 1540 1541 /* Add lookup record for patch to guest address translation */ 1542 patmr3AddP2GLookupRecord(pVM, pPatch, pPB, pCurInstrGC, PATM_LOOKUP_PATCH2GUEST); 1541 if (fAddLookupRecord) 1542 { 1543 /* Add lookup record for patch to guest address translation */ 1544 patmr3AddP2GLookupRecord(pVM, pPatch, pPB, pCurInstrGC, PATM_LOOKUP_PATCH2GUEST); 1545 } 1543 1546 1544 1547 pPB[0] = 0xE9; //JMP -
trunk/src/VBox/VMM/PATM/PATMPatch.h
r23 r2030 46 46 int patmPatchGenRet(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pCurInstrGC); 47 47 48 int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC );48 int patmPatchGenPatchJump(PVM pVM, PPATCHINFO pPatch, RTGCPTR pCurInstrGC, GCPTRTYPE(uint8_t *)pPatchAddrGC, bool fAddLookupRecord = true); 49 49 50 50 /**
Note:
See TracChangeset
for help on using the changeset viewer.