diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
|---|---|---|
| committer | <> | 2014-05-08 15:03:54 +0000 |
| commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
| tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/VMM/VMMR3/PATM.cpp | |
| parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
| download | VirtualBox-master.tar.gz | |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/VMM/VMMR3/PATM.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMR3/PATM.cpp | 511 |
1 files changed, 296 insertions, 215 deletions
diff --git a/src/VBox/VMM/VMMR3/PATM.cpp b/src/VBox/VMM/VMMR3/PATM.cpp index 51a766c0..64773715 100644 --- a/src/VBox/VMM/VMMR3/PATM.cpp +++ b/src/VBox/VMM/VMMR3/PATM.cpp @@ -2,11 +2,11 @@ /** @file * PATM - Dynamic Guest OS Patching Manager * - * NOTE: Never ever reuse patch memory!! + * @note Never ever reuse patch memory!! */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,16 +29,18 @@ #include <VBox/vmm/iom.h> #include <VBox/vmm/mm.h> #include <VBox/vmm/em.h> +#include <VBox/vmm/hm.h> #include <VBox/vmm/ssm.h> #include <VBox/vmm/trpm.h> #include <VBox/vmm/cfgm.h> #include <VBox/param.h> #include <VBox/vmm/selm.h> +#include <VBox/vmm/csam.h> #include <iprt/avl.h> #include "PATMInternal.h" #include "PATMPatch.h" #include <VBox/vmm/vm.h> -#include <VBox/vmm/csam.h> +#include <VBox/vmm/uvm.h> #include <VBox/dbg.h> #include <VBox/err.h> #include <VBox/log.h> @@ -107,11 +109,13 @@ static void patmPrintStat(PVM pVM, void *pvSample, char *pszBuf, size_t static int patmReinit(PVM pVM); static DECLCALLBACK(int) RelocatePatches(PAVLOU32NODECORE pNode, void *pParam); +static RTRCPTR patmR3GuestGCPtrToPatchGCPtrSimple(PVM pVM, RCPTRTYPE(uint8_t*) pInstrGC); +static int patmR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch); #ifdef VBOX_WITH_DEBUGGER static DECLCALLBACK(int) DisableAllPatches(PAVLOU32NODECORE pNode, void *pVM); -static DECLCALLBACK(int) patmr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); -static DECLCALLBACK(int) patmr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); +static FNDBGCCMD patmr3CmdOn; +static FNDBGCCMD patmr3CmdOff; /** Command descriptors. */ static const DBGCCMD g_aCmds[] = @@ -131,10 +135,22 @@ static unsigned int cIDTHandlersDisabled = 0; * @returns VBox status code. * @param pVM Pointer to the VM. */ -VMMR3DECL(int) PATMR3Init(PVM pVM) +VMMR3_INT_DECL(int) PATMR3Init(PVM pVM) { int rc; + /* + * We only need a saved state dummy loader if HM is enabled. + */ + if (HMIsEnabled(pVM)) + { + pVM->fPATMEnabled = false; + return SSMR3RegisterStub(pVM, "PATM", 0); + } + + /* + * Raw-mode. + */ Log(("PATMR3Init: Patch record size %d\n", sizeof(PATCHINFO))); /* These values can't change as they are hardcoded in patch code (old saved states!) */ @@ -162,6 +178,8 @@ VMMR3DECL(int) PATMR3Init(PVM pVM) pVM->patm.s.pGCStackHC = (RTRCPTR *)(pVM->patm.s.pPatchMemHC + PATCH_MEMORY_SIZE + PAGE_SIZE); pVM->patm.s.pGCStackGC = MMHyperR3ToRC(pVM, pVM->patm.s.pGCStackHC); + patmR3DbgInit(pVM); + /* * Hypervisor memory for GC status data (read/write) * @@ -307,8 +325,11 @@ VMMR3DECL(int) PATMR3Init(PVM pVM) * @returns VBox status code. * @param pVM Pointer to the VM. */ -VMMR3DECL(int) PATMR3InitFinalize(PVM pVM) +VMMR3_INT_DECL(int) PATMR3InitFinalize(PVM pVM) { + if (HMIsEnabled(pVM)) + return VINF_SUCCESS; + /* The GC state, stack and statistics must be read/write for the guest (supervisor only of course). */ int rc = PGMMapSetPage(pVM, pVM->patm.s.pGCStateGC, PAGE_SIZE, X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW); if (RT_FAILURE(rc)) @@ -404,6 +425,7 @@ static int patmReinit(PVM pVM) pVM->patm.s.fOutOfMemory = false; pVM->patm.s.pfnHelperCallGC = 0; + patmR3DbgReset(pVM); /* Generate all global functions to be used by future patches. */ /* We generate a fake patch in order to use the existing code for relocation. */ @@ -424,6 +446,8 @@ static int patmReinit(PVM pVM) pVM->patm.s.offPatchMem += pVM->patm.s.pGlobalPatchRec->patch.uCurPatchOffset; /* Round to next 8 byte boundary. */ pVM->patm.s.offPatchMem = RT_ALIGN_32(pVM->patm.s.offPatchMem, 8); + + return rc; } @@ -437,8 +461,11 @@ static int patmReinit(PVM pVM) * * @param pVM The VM. */ -VMMR3DECL(void) PATMR3Relocate(PVM pVM) +VMMR3_INT_DECL(void) PATMR3Relocate(PVM pVM) { + if (HMIsEnabled(pVM)) + return; + RTRCPTR GCPtrNew = MMHyperR3ToRC(pVM, pVM->patm.s.pGCStateHC); RTRCINTPTR delta = GCPtrNew - pVM->patm.s.pGCStateGC; @@ -492,10 +519,14 @@ VMMR3DECL(void) PATMR3Relocate(PVM pVM) * @returns VBox status code. * @param pVM Pointer to the VM. */ -VMMR3DECL(int) PATMR3Term(PVM pVM) +VMMR3_INT_DECL(int) PATMR3Term(PVM pVM) { + if (HMIsEnabled(pVM)) + return VINF_SUCCESS; + + patmR3DbgTerm(pVM); + /* Memory was all allocated from the two MM heaps and requires no freeing. */ - NOREF(pVM); return VINF_SUCCESS; } @@ -506,18 +537,18 @@ VMMR3DECL(int) PATMR3Term(PVM pVM) * @returns VBox status code. * @param pVM The VM which is reset. */ -VMMR3DECL(int) PATMR3Reset(PVM pVM) +VMMR3_INT_DECL(int) PATMR3Reset(PVM pVM) { Log(("PATMR3Reset\n")); + if (HMIsEnabled(pVM)) + return VINF_SUCCESS; /* Free all patches. */ - while (true) + for (;;) { PPATMPATCHREC pPatchRec = (PPATMPATCHREC)RTAvloU32RemoveBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, 0, true); if (pPatchRec) - { - PATMRemovePatch(pVM, pPatchRec, true); - } + patmR3RemovePatch(pVM, pPatchRec, true); else break; } @@ -920,8 +951,8 @@ DECLCALLBACK(int) patmVirtPageHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void return VINF_PGM_HANDLER_DO_DEFAULT; } - #ifdef VBOX_WITH_DEBUGGER + /** * Callback function for RTAvloU32DoWithAll * @@ -938,10 +969,8 @@ static DECLCALLBACK(int) EnableAllPatches(PAVLOU32NODECORE pNode, void *pVM) PATMR3EnablePatch((PVM)pVM, (RTRCPTR)pPatch->Core.Key); return 0; } -#endif /* VBOX_WITH_DEBUGGER */ -#ifdef VBOX_WITH_DEBUGGER /** * Callback function for RTAvloU32DoWithAll * @@ -958,20 +987,23 @@ static DECLCALLBACK(int) DisableAllPatches(PAVLOU32NODECORE pNode, void *pVM) PATMR3DisablePatch((PVM)pVM, (RTRCPTR)pPatch->Core.Key); return 0; } -#endif + +#endif /* VBOX_WITH_DEBUGGER */ +#ifdef UNUSED_FUNCTIONS /** * Returns the host context pointer and size of the patch memory block * - * @returns VBox status code. + * @returns Host context pointer. * @param pVM Pointer to the VM. * @param pcb Size of the patch memory block + * @internal */ -VMMR3DECL(void *) PATMR3QueryPatchMemHC(PVM pVM, uint32_t *pcb) +VMMR3_INT_DECL(void *) PATMR3QueryPatchMemHC(PVM pVM, uint32_t *pcb) { + AssertReturn(!HMIsEnabled(pVM), NULL); if (pcb) *pcb = pVM->patm.s.cbPatchMem; - return pVM->patm.s.pPatchMemHC; } @@ -979,18 +1011,19 @@ VMMR3DECL(void *) PATMR3QueryPatchMemHC(PVM pVM, uint32_t *pcb) /** * Returns the guest context pointer and size of the patch memory block * - * @returns VBox status code. + * @returns Guest context pointer. * @param pVM Pointer to the VM. * @param pcb Size of the patch memory block */ -VMMR3DECL(RTRCPTR) PATMR3QueryPatchMemGC(PVM pVM, uint32_t *pcb) +VMMR3_INT_DECL(RTRCPTR) PATMR3QueryPatchMemGC(PVM pVM, uint32_t *pcb) { + AssertReturn(!HMIsEnabled(pVM), NIL_RTRCPTR); if (pcb) *pcb = pVM->patm.s.cbPatchMem; - return pVM->patm.s.pPatchMemGC; } +#endif /* UNUSED_FUNCTIONS */ /** * Returns the host context pointer of the GC context structure @@ -998,62 +1031,78 @@ VMMR3DECL(RTRCPTR) PATMR3QueryPatchMemGC(PVM pVM, uint32_t *pcb) * @returns VBox status code. * @param pVM Pointer to the VM. */ -VMMR3DECL(PPATMGCSTATE) PATMR3QueryGCStateHC(PVM pVM) +VMMR3_INT_DECL(PPATMGCSTATE) PATMR3QueryGCStateHC(PVM pVM) { + AssertReturn(!HMIsEnabled(pVM), NULL); return pVM->patm.s.pGCStateHC; } +#ifdef UNUSED_FUNCTION /** * Checks whether the HC address is part of our patch region * - * @returns VBox status code. + * @returns true/false. * @param pVM Pointer to the VM. - * @param pAddrGC Guest context address + * @param pAddrHC Host context ring-3 address to check. */ -VMMR3DECL(bool) PATMR3IsPatchHCAddr(PVM pVM, R3PTRTYPE(uint8_t *) pAddrHC) +VMMR3_INT_DECL(bool) PATMR3IsPatchHCAddr(PVM pVM, void *pAddrHC) { - return (pAddrHC >= pVM->patm.s.pPatchMemHC && pAddrHC < pVM->patm.s.pPatchMemHC + pVM->patm.s.cbPatchMem) ? true : false; + return (uintptr_t)pAddrHC >= (uintptr_t)pVM->patm.s.pPatchMemHC + && (uintptr_t)pAddrHC < (uintptr_t)pVM->patm.s.pPatchMemHC + pVM->patm.s.cbPatchMem; } +#endif /** * Allows or disallow patching of privileged instructions executed by the guest OS * * @returns VBox status code. - * @param pVM Pointer to the VM. - * @param fAllowPatching Allow/disallow patching + * @param pUVM The user mode VM handle. + * @param fAllowPatching Allow/disallow patching */ -VMMR3DECL(int) PATMR3AllowPatching(PVM pVM, uint32_t fAllowPatching) +VMMR3DECL(int) PATMR3AllowPatching(PUVM pUVM, bool fAllowPatching) { - pVM->fPATMEnabled = (fAllowPatching) ? true : false; + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + + if (!HMIsEnabled(pVM)) + pVM->fPATMEnabled = fAllowPatching; + else + Assert(!pVM->fPATMEnabled); return VINF_SUCCESS; } + /** - * Convert a GC patch block pointer to a HC patch pointer + * Checks if the patch manager is enabled or not. * - * @returns HC pointer or NULL if it's not a GC patch pointer - * @param pVM Pointer to the VM. - * @param pAddrGC GC pointer + * @returns true if enabled, false if not (or if invalid handle). + * @param pUVM The user mode VM handle. */ -VMMR3DECL(R3PTRTYPE(void *)) PATMR3GCPtrToHCPtr(PVM pVM, RTRCPTR pAddrGC) +VMMR3DECL(bool) PATMR3IsEnabled(PUVM pUVM) { - if (pVM->patm.s.pPatchMemGC <= pAddrGC && pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem > pAddrGC) - return pVM->patm.s.pPatchMemHC + (pAddrGC - pVM->patm.s.pPatchMemGC); - else - return NULL; + UVM_ASSERT_VALID_EXT_RETURN(pUVM, false); + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, false); + return PATMIsEnabled(pVM); } + /** - * Query PATM state (enabled/disabled) + * Convert a GC patch block pointer to a HC patch pointer * - * @returns 0 - disabled, 1 - enabled + * @returns HC pointer or NULL if it's not a GC patch pointer * @param pVM Pointer to the VM. + * @param pAddrGC GC pointer */ -VMMR3DECL(int) PATMR3IsEnabled(PVM pVM) +VMMR3_INT_DECL(void *) PATMR3GCPtrToHCPtr(PVM pVM, RTRCPTR pAddrGC) { - return pVM->fPATMEnabled; + AssertReturn(!HMIsEnabled(pVM), NULL); + if (pVM->patm.s.pPatchMemGC <= pAddrGC && pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem > pAddrGC) + return pVM->patm.s.pPatchMemHC + (pAddrGC - pVM->patm.s.pPatchMemGC); + return NULL; } @@ -1068,7 +1117,7 @@ VMMR3DECL(int) PATMR3IsEnabled(PVM pVM) * @returns Host context pointer or NULL in case of an error * */ -R3PTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr) +R3PTRTYPE(uint8_t *) patmR3GCVirtToHCVirt(PVM pVM, PPATMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr) { int rc; R3PTRTYPE(uint8_t *) pHCPtr; @@ -1104,7 +1153,8 @@ R3PTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATMP2GLOOKUPREC pCacheRec, RC } -/* Calculates and fills in all branch targets +/** + * Calculates and fills in all branch targets * * @returns VBox status code. * @param pVM Pointer to the VM. @@ -1140,7 +1190,7 @@ static int patmr3SetBranchTargets(PVM pVM, PPATCHINFO pPatch) { /* Special case: call function replacement patch from this patch block. */ - PPATMPATCHREC pFunctionRec = PATMQueryFunctionPatch(pVM, pRec->pTargetGC); + PPATMPATCHREC pFunctionRec = patmQueryFunctionPatch(pVM, pRec->pTargetGC); if (!pFunctionRec) { int rc; @@ -1200,7 +1250,8 @@ static int patmr3SetBranchTargets(PVM pVM, PPATCHINFO pPatch) return VINF_SUCCESS; } -/* Add an illegal instruction record +/** + * Add an illegal instruction record * * @param pVM Pointer to the VM. * @param pPatch Patch structure ptr @@ -1241,9 +1292,10 @@ static bool patmIsIllegalInstr(PPATCHINFO pPatch, RTRCPTR pInstrGC) * @param enmType Lookup type * @param fDirty Dirty flag * + * @note Be extremely careful with this function. Make absolutely sure the guest + * address is correct! (to avoid executing instructions twice!) */ - /** @note Be extremely careful with this function. Make absolutely sure the guest address is correct! (to avoid executing instructions twice!) */ -void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty) +void patmR3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty) { bool ret; PRECPATCHTOGUEST pPatchToGuestRec; @@ -1348,7 +1400,7 @@ static DECLCALLBACK(int) patmEmptyTreePVCallback(PAVLPVNODECORE pNode, void *) * @param pVM Pointer to the VM. * @param ppTree Tree to empty */ -void patmEmptyTree(PVM pVM, PAVLPVNODECORE *ppTree) +static void patmEmptyTree(PVM pVM, PAVLPVNODECORE *ppTree) { NOREF(pVM); RTAvlPVDestroy(ppTree, patmEmptyTreePVCallback, NULL); @@ -1370,7 +1422,7 @@ static DECLCALLBACK(int) patmEmptyTreeU32Callback(PAVLU32NODECORE pNode, void *) * @param pVM Pointer to the VM. * @param ppTree Tree to empty */ -void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree) +static void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree) { NOREF(pVM); RTAvlU32Destroy(ppTree, patmEmptyTreeU32Callback, NULL); @@ -1520,6 +1572,11 @@ static int patmAnalyseBlockCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_ case OP_JMP: break; +#ifdef VBOX_WITH_SAFE_STR /** @todo remove DISOPTYPE_PRIVILEGED_NOTRAP from disasm table */ + case OP_STR: + break; +#endif + default: if (pCpu->pCurInstr->fOpType & (DISOPTYPE_PRIVILEGED_NOTRAP)) { @@ -1631,6 +1688,11 @@ static int patmAnalyseFunctionCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uin case OP_RETN: return VINF_SUCCESS; +#ifdef VBOX_WITH_SAFE_STR /** @todo remove DISOPTYPE_PRIVILEGED_NOTRAP from disasm table */ + case OP_STR: + break; +#endif + case OP_POPF: case OP_STI: return VWRN_CONTINUE_ANALYSIS; @@ -1693,7 +1755,7 @@ static int patmRecompileCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t * pPatch->flags &= ~PATMFL_RECOMPILE_NEXT; /* Add lookup record for patch to guest address translation */ - patmr3AddP2GLookupRecord(pVM, pPatch, PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset, pCurInstrGC, PATM_LOOKUP_BOTHDIR); + patmR3AddP2GLookupRecord(pVM, pPatch, PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset, pCurInstrGC, PATM_LOOKUP_BOTHDIR); /* Update lowest and highest instruction address for this patch */ if (pCurInstrGC < pPatch->pInstrGCLowest) @@ -1791,6 +1853,7 @@ static int patmRecompileCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t * goto duplicate_instr; case OP_POP: + /** @todo broken comparison!! should be if ((pCpu->Param1.fUse & DISUSE_REG_SEG) && (pCpu->Param1.Base.idxSegReg == DISSELREG_SS)) */ if (pCpu->pCurInstr->fParam1 == OP_PARM_REG_SS) { Assert(pCpu->pCurInstr->fOpType & DISOPTYPE_INHIBIT_IRQS); @@ -1825,7 +1888,7 @@ static int patmRecompileCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t * pNextInstrGC = pCurInstrGC + pCpu->cbInstr; { /* Force pNextInstrHC out of scope after using it */ - uint8_t *pNextInstrHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pNextInstrGC); + uint8_t *pNextInstrHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pNextInstrGC); if (pNextInstrHC == NULL) { AssertFailed(); @@ -1898,6 +1961,7 @@ static int patmRecompileCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t * break; case OP_PUSH: + /** @todo broken comparison!! should be if ((pCpu->Param1.fUse & DISUSE_REG_SEG) && (pCpu->Param1.Base.idxSegReg == DISSELREG_SS)) */ if (pCpu->pCurInstr->fParam1 == OP_PARM_REG_CS) { rc = patmPatchGenPushCS(pVM, pPatch); @@ -1932,6 +1996,10 @@ static int patmRecompileCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t * break; case OP_STR: +#ifdef VBOX_WITH_SAFE_STR /* @todo remove DISOPTYPE_PRIVILEGED_NOTRAP from disasm table and move OP_STR into #ifndef */ + /* Now safe because our shadow TR entry is identical to the guest's. */ + goto duplicate_instr; +#endif case OP_SLDT: rc = patmPatchGenSldtStr(pVM, pPatch, pCpu, pCurInstrGC); if (RT_SUCCESS(rc)) @@ -2087,7 +2155,8 @@ end: #ifdef LOG_ENABLED -/* Add a disasm jump record (temporary for prevent duplicate analysis) +/** + * Add a disasm jump record (temporary for prevent duplicate analysis) * * @param pVM Pointer to the VM. * @param pPatch Patch structure ptr @@ -2149,7 +2218,7 @@ int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstr pOrgJumpGC = patmPatchGCPtr2GuestGCPtr(pVM, pPatch, pCurInstrGC); { /* Force pOrgJumpHC out of scope after using it */ - uint8_t *pOrgJumpHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pOrgJumpGC); + uint8_t *pOrgJumpHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pOrgJumpGC); bool disret = patmR3DisInstr(pVM, pPatch, pOrgJumpGC, pOrgJumpHC, PATMREAD_ORGCODE, &cpu, NULL); if (!disret || cpu.pCurInstr->uOpcode != OP_CALL || cpu.Param1.cb != 4 /* only near calls */) @@ -2210,7 +2279,7 @@ int patmr3DisasmCode(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t * while (rc == VWRN_CONTINUE_ANALYSIS) { - pCurInstrHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC); + pCurInstrHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC); if (pCurInstrHC == NULL) { rc = VERR_PATCHING_REFUSED; @@ -2342,13 +2411,12 @@ int patmr3DisasmCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uin * @note also checks for patch hints to make sure they can never be enabled if a conflict is present. * */ -VMMR3DECL(int) PATMR3DetectConflict(PVM pVM, RTRCPTR pInstrGC, RTRCPTR pConflictGC) +VMMR3_INT_DECL(int) PATMR3DetectConflict(PVM pVM, RTRCPTR pInstrGC, RTRCPTR pConflictGC) { - PPATCHINFO pTargetPatch = PATMFindActivePatchByEntrypoint(pVM, pConflictGC, true /* include patch hints */); + AssertReturn(!HMIsEnabled(pVM), VERR_PATCH_NO_CONFLICT); + PPATCHINFO pTargetPatch = patmFindActivePatchByEntrypoint(pVM, pConflictGC, true /* include patch hints */); if (pTargetPatch) - { return patmDisableUnusablePatch(pVM, pInstrGC, pConflictGC, pTargetPatch); - } return VERR_PATCH_NO_CONFLICT; } @@ -2377,7 +2445,7 @@ static int patmRecompileCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTR while (rc == VWRN_CONTINUE_RECOMPILE) { - pCurInstrHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC); + pCurInstrHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC); if (pCurInstrHC == NULL) { rc = VERR_PATCHING_REFUSED; /* fatal in this case */ @@ -2395,7 +2463,7 @@ static int patmRecompileCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTR Log(("Disassembly failed (probably page not present) -> return to caller\n")); /* Add lookup record for patch to guest address translation */ - patmr3AddP2GLookupRecord(pVM, pPatch, PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset, pCurInstrGC, PATM_LOOKUP_BOTHDIR); + patmR3AddP2GLookupRecord(pVM, pPatch, PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset, pCurInstrGC, PATM_LOOKUP_BOTHDIR); patmPatchGenIllegalInstr(pVM, pPatch); rc = VINF_SUCCESS; /* Note: don't fail here; we might refuse an important patch!! */ goto end; @@ -2418,7 +2486,7 @@ static int patmRecompileCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTR /* Certain instructions (e.g. sti) force the next instruction to be executed before any interrupts can occur. * Recompile the next instruction as well */ - pNextInstrHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pNextInstrGC); + pNextInstrHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pNextInstrGC); if (pNextInstrHC == NULL) { rc = VERR_PATCHING_REFUSED; /* fatal in this case */ @@ -2511,7 +2579,7 @@ static int patmRecompileCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTR * * We rely on CSAM to detect and resolve conflicts */ - PPATCHINFO pTargetPatch = PATMFindActivePatchByEntrypoint(pVM, addr); + PPATCHINFO pTargetPatch = patmFindActivePatchByEntrypoint(pVM, addr); if(pTargetPatch) { Log(("Found active patch at target %RRv (%RRv) -> temporarily disabling it!!\n", addr, pTargetPatch->pPrivInstrGC)); @@ -2566,7 +2634,7 @@ static int patmGenJumpToPatch(PVM pVM, PPATCHINFO pPatch, PPATMP2GLOOKUPREC pCac Assert(pPatch->cbPatchJump <= sizeof(temp)); Assert(!(pPatch->flags & PATMFL_PATCHED_GUEST_CODE)); - pPB = PATMGCVirtToHCVirt(pVM, pCacheRec, pPatch->pPrivInstrGC); + pPB = patmR3GCVirtToHCVirt(pVM, pCacheRec, pPatch->pPrivInstrGC); Assert(pPB); #ifdef PATM_RESOLVE_CONFLICTS_WITH_JUMP_PATCHES @@ -2706,7 +2774,7 @@ static int patmGenCallToPatch(PVM pVM, PPATCHINFO pPatch, RTRCPTR pTargetGC, PPA Assert(pPatch->cbPatchJump <= sizeof(temp)); - pPB = PATMGCVirtToHCVirt(pVM, pCacheRec, pPatch->pPrivInstrGC); + pPB = patmR3GCVirtToHCVirt(pVM, pCacheRec, pPatch->pPrivInstrGC); Assert(pPB); Assert(pPatch->cbPatchJump == SIZEOF_NEARJUMP32); @@ -2746,8 +2814,8 @@ static int patmGenCallToPatch(PVM pVM, PPATCHINFO pPatch, RTRCPTR pTargetGC, PPA * @note returns failure if patching is not allowed or possible * */ -VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, - uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec) +static int patmR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, + uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec) { PPATCHINFO pPatch = &pPatchRec->patch; int rc = VERR_PATCHING_REFUSED; @@ -2776,7 +2844,7 @@ VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) default: if (!(pPatch->flags & PATMFL_IDTHANDLER)) { - AssertMsg(0, ("PATMR3PatchBlock: Invalid opcode %x\n", uOpcode)); + AssertMsg(0, ("patmR3PatchBlock: Invalid opcode %x\n", uOpcode)); return VERR_INVALID_PARAMETER; } } @@ -2849,7 +2917,7 @@ VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) { /* Most likely cause: we encountered an illegal instruction very early on. */ /** @todo could turn it into an int3 callable patch. */ - Log(("PATMR3PatchBlock: patch block too small -> refuse\n")); + Log(("patmR3PatchBlock: patch block too small -> refuse\n")); rc = VERR_PATCHING_REFUSED; goto failure; } @@ -2906,7 +2974,7 @@ VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) { /*uint8_t bASMInt3 = 0xCC; - unused */ - Log(("PATMR3PatchBlock %RRv -> int 3 callable patch.\n", pPatch->pPrivInstrGC)); + Log(("patmR3PatchBlock %RRv -> int 3 callable patch.\n", pPatch->pPrivInstrGC)); /* Replace first opcode byte with 'int 3'. */ rc = patmActivateInt3Patch(pVM, pPatch); if (RT_FAILURE(rc)) @@ -2930,6 +2998,8 @@ VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) } + patmR3DbgAddPatch(pVM, pPatchRec); + PATM_LOG_RAW_PATCH_INSTR(pVM, pPatch, patmGetInstructionString(pPatch->opcode, pPatch->flags)); patmEmptyTree(pVM, &pPatch->pTempInfo->IllegalInstrTree); @@ -2987,7 +3057,7 @@ static int patmIdtHandler(PVM pVM, RTRCPTR pInstrGC, uint32_t uOpSize, PPATMPATC uint8_t *pCurInstrHC, *pInstrHC; uint32_t orgOffsetPatchMem = ~0; - pInstrHC = pCurInstrHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC); + pInstrHC = pCurInstrHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC); AssertReturn(pCurInstrHC, VERR_PAGE_NOT_PRESENT); /* @@ -3042,7 +3112,7 @@ static int patmIdtHandler(PVM pVM, RTRCPTR pInstrGC, uint32_t uOpSize, PPATMPATC goto failure; /* Add lookup record for patch to guest address translation (for the push) */ - patmr3AddP2GLookupRecord(pVM, pPatch, PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset, pInstrGC, PATM_LOOKUP_BOTHDIR); + patmR3AddP2GLookupRecord(pVM, pPatch, PATCHCODE_PTR_HC(pPatch) + pPatch->uCurPatchOffset, pInstrGC, PATM_LOOKUP_BOTHDIR); /* Duplicate push. */ rc = patmPatchGenDuplicate(pVM, pPatch, &cpuPush, pInstrGC); @@ -3080,6 +3150,7 @@ static int patmIdtHandler(PVM pVM, RTRCPTR pInstrGC, uint32_t uOpSize, PPATMPATC pPatchRec->CoreOffset.Key = pPatch->pPatchBlockOffset; fInserted = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset); AssertMsg(fInserted, ("RTAvlULInsert failed for %x\n", pPatchRec->CoreOffset.Key)); + patmR3DbgAddPatch(pVM, pPatchRec); pPatch->uState = PATCH_ENABLED; @@ -3091,7 +3162,7 @@ failure: if (orgOffsetPatchMem != (uint32_t)~0) pVM->patm.s.offPatchMem = orgOffsetPatchMem; - return PATMR3PatchBlock(pVM, pInstrGC, pInstrHC, OP_CLI, uOpSize, pPatchRec); + return patmR3PatchBlock(pVM, pInstrGC, pInstrHC, OP_CLI, uOpSize, pPatchRec); } /** @@ -3154,6 +3225,7 @@ static int patmInstallTrapTrampoline(PVM pVM, RTRCPTR pInstrGC, PPATMPATCHREC pP pPatchRec->CoreOffset.Key = pPatch->pPatchBlockOffset; fInserted = RTAvloU32Insert(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, &pPatchRec->CoreOffset); AssertMsg(fInserted, ("RTAvlULInsert failed for %x\n", pPatchRec->CoreOffset.Key)); + patmR3DbgAddPatch(pVM, pPatchRec); pPatch->uState = PATCH_ENABLED; return VINF_SUCCESS; @@ -3283,6 +3355,8 @@ static int patmDuplicateFunction(PVM pVM, RTRCPTR pInstrGC, PPATMPATCHREC pPatch goto failure; } + patmR3DbgAddPatch(pVM, pPatchRec); + #ifdef LOG_ENABLED Log(("Patch code ----------------------------------------------------------\n")); patmr3DisasmCodeStream(pVM, PATCHCODE_PTR_GC(pPatch), PATCHCODE_PTR_GC(pPatch), patmr3DisasmCallback, pCacheRec); @@ -3433,6 +3507,7 @@ static int patmCreateTrampoline(PVM pVM, RTRCPTR pInstrGC, PPATMPATCHREC pPatchR rc = VERR_PATCHING_REFUSED; goto failure; } + patmR3DbgAddPatch(pVM, pPatchRec); /* size of patch block */ pPatch->cbPatchBlockSize = pPatch->uCurPatchOffset; @@ -3495,11 +3570,12 @@ failure: * @param pCtx Pointer to the guest CPU context. * */ -VMMR3DECL(int) PATMR3DuplicateFunctionRequest(PVM pVM, PCPUMCTX pCtx) +VMMR3_INT_DECL(int) PATMR3DuplicateFunctionRequest(PVM pVM, PCPUMCTX pCtx) { RTRCPTR pBranchTarget, pPage; int rc; RTRCPTR pPatchTargetGC = 0; + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); pBranchTarget = pCtx->edx; pBranchTarget = SELMToFlat(pVM, DISSELREG_CS, CPUMCTX2CORE(pCtx), pBranchTarget); @@ -3560,7 +3636,7 @@ VMMR3DECL(int) PATMR3DuplicateFunctionRequest(PVM pVM, PCPUMCTX pCtx) STAM_COUNTER_INC(&pVM->patm.s.StatDuplicateREQFailed); } Assert(PATMIsPatchGCAddr(pVM, pCtx->edi)); - rc = PATMAddBranchToLookupCache(pVM, pCtx->edi, pBranchTarget, pCtx->eax); + rc = patmAddBranchToLookupCache(pVM, pCtx->edi, pBranchTarget, pCtx->eax); AssertRC(rc); pCtx->eip += PATM_ILLEGAL_INSTR_SIZE; @@ -3615,7 +3691,7 @@ static int patmReplaceFunctionCall(PVM pVM, DISCPUSTATE *pCpu, RTRCPTR pInstrGC, */ uint8_t *pTmpInstrHC; - pTmpInstrHC = PATMGCVirtToHCVirt(pVM, pCacheRec, pTargetGC); + pTmpInstrHC = patmR3GCVirtToHCVirt(pVM, pCacheRec, pTargetGC); Assert(pTmpInstrHC); if (pTmpInstrHC == 0) break; @@ -3695,12 +3771,13 @@ static int patmPatchMMIOInstr(PVM pVM, RTRCPTR pInstrGC, DISCPUSTATE *pCpu, PPAT if (pCpu->Param2.fUse != DISUSE_DISPLACEMENT32) goto failure; - pPB = PATMGCVirtToHCVirt(pVM, pCacheRec, pPatch->pPrivInstrGC); + pPB = patmR3GCVirtToHCVirt(pVM, pCacheRec, pPatch->pPrivInstrGC); if (pPB == 0) goto failure; /* Add relocation record for cached data access. */ - if (patmPatchAddReloc32(pVM, pPatch, &pPB[pCpu->cbInstr - sizeof(RTRCPTR)], FIXUP_ABSOLUTE, pPatch->pPrivInstrGC, pVM->patm.s.mmio.pCachedData) != VINF_SUCCESS) + if (patmPatchAddReloc32(pVM, pPatch, &pPB[pCpu->cbInstr - sizeof(RTRCPTR)], FIXUP_ABSOLUTE, pPatch->pPrivInstrGC, + pVM->patm.s.mmio.pCachedData) != VINF_SUCCESS) { Log(("Relocation failed for cached mmio address!!\n")); return VERR_PATCHING_REFUSED; @@ -3714,7 +3791,8 @@ static int patmPatchMMIOInstr(PVM pVM, RTRCPTR pInstrGC, DISCPUSTATE *pCpu, PPAT pPatch->cbPatchJump = pPatch->cbPrivInstr; /* bit of a misnomer in this case; size of replacement instruction. */ /* Replace address with that of the cached item. */ - rc = PGMPhysSimpleDirtyWriteGCPtr(VMMGetCpu0(pVM), pInstrGC + pCpu->cbInstr - sizeof(RTRCPTR), &pVM->patm.s.mmio.pCachedData, sizeof(RTRCPTR)); + rc = PGMPhysSimpleDirtyWriteGCPtr(VMMGetCpu0(pVM), pInstrGC + pCpu->cbInstr - sizeof(RTRCPTR), + &pVM->patm.s.mmio.pCachedData, sizeof(RTRCPTR)); AssertRC(rc); if (RT_FAILURE(rc)) { @@ -3852,14 +3930,13 @@ static int patmDeactivateInt3Patch(PVM pVM, PPATCHINFO pPatch) * @note returns failure if patching is not allowed or possible * */ -VMMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, - PPATCHINFO pPatch) +int patmR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch) { uint8_t bASMInt3 = 0xCC; int rc; /* Note: Do not use patch memory here! It might called during patch installation too. */ - PATM_LOG_PATCH_INSTR(pVM, pPatch, PATMREAD_ORGCODE, "PATMR3PatchInstrInt3:", ""); + PATM_LOG_PATCH_INSTR(pVM, pPatch, PATMREAD_ORGCODE, "patmR3PatchInstrInt3:", ""); /* Save the original instruction. */ rc = PGMPhysSimpleReadGCPtr(VMMGetCpu0(pVM), pPatch->aPrivInstr, pPatch->pPrivInstrGC, pPatch->cbPrivInstr); @@ -3968,9 +4045,9 @@ int patmPatchJump(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISC * A conflict jump patch needs to be treated differently; we'll just replace the relative jump address with one that * references the target instruction in the conflict patch. */ - RTRCPTR pJmpDest = PATMR3GuestGCPtrToPatchGCPtr(pVM, pInstrGC + pCpu->cbInstr + (int32_t)pCpu->Param1.uValue); + RTRCPTR pJmpDest = patmR3GuestGCPtrToPatchGCPtrSimple(pVM, pInstrGC + pCpu->cbInstr + (int32_t)pCpu->Param1.uValue); - AssertMsg(pJmpDest, ("PATMR3GuestGCPtrToPatchGCPtr failed for %RRv\n", pInstrGC + pCpu->cbInstr + (int32_t)pCpu->Param1.uValue)); + AssertMsg(pJmpDest, ("patmR3GuestGCPtrToPatchGCPtrSimple failed for %RRv\n", pInstrGC + pCpu->cbInstr + (int32_t)pCpu->Param1.uValue)); pPatch->pPatchJumpDestGC = pJmpDest; PATMP2GLOOKUPREC cacheRec; @@ -4019,7 +4096,7 @@ failure: * @param pInstr Guest context point to privileged instruction * @param flags Patch flags */ -VMMR3DECL(int) PATMR3AddHint(PVM pVM, RTRCPTR pInstrGC, uint32_t flags) +VMMR3_INT_DECL(int) PATMR3AddHint(PVM pVM, RTRCPTR pInstrGC, uint32_t flags) { Assert(pInstrGC); Assert(flags == PATMFL_CODE32); @@ -4038,7 +4115,7 @@ VMMR3DECL(int) PATMR3AddHint(PVM pVM, RTRCPTR pInstrGC, uint32_t flags) * * @note returns failure if patching is not allowed or possible */ -VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) +VMMR3_INT_DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) { DISCPUSTATE cpu; R3PTRTYPE(uint8_t *) pInstrHC; @@ -4050,6 +4127,8 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) PVMCPU pVCpu = VMMGetCpu0(pVM); LogFlow(("PATMR3InstallPatch: %08x (%#llx)\n", pInstrGC, flags)); + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); + if ( !pVM || pInstrGC == 0 || (flags & ~(PATMFL_CODE32|PATMFL_IDTHANDLER|PATMFL_INTHANDLER|PATMFL_SYSENTER|PATMFL_TRAPHANDLER|PATMFL_DUPLICATE_FUNCTION|PATMFL_REPLACE_FUNCTION_CALL|PATMFL_GUEST_SPECIFIC|PATMFL_INT3_REPLACEMENT|PATMFL_TRAPHANDLER_WITH_ERRORCODE|PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT|PATMFL_MMIO_ACCESS|PATMFL_TRAMPOLINE|PATMFL_INSTR_HINT|PATMFL_JUMP_CONFLICT))) @@ -4064,7 +4143,7 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) /* Test for patch conflict only with patches that actually change guest code. */ if (!(flags & (PATMFL_GUEST_SPECIFIC|PATMFL_IDTHANDLER|PATMFL_INTHANDLER|PATMFL_TRAMPOLINE))) { - PPATCHINFO pConflictPatch = PATMFindActivePatchByEntrypoint(pVM, pInstrGC); + PPATCHINFO pConflictPatch = patmFindActivePatchByEntrypoint(pVM, pInstrGC); AssertReleaseMsg(pConflictPatch == 0, ("Unable to patch overwritten instruction at %RRv (%RRv)\n", pInstrGC, pConflictPatch->pPrivInstrGC)); if (pConflictPatch != 0) return VERR_PATCHING_REFUSED; @@ -4081,7 +4160,7 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) if (pVM->patm.s.fOutOfMemory == true) return VERR_PATCHING_REFUSED; -#if 0 /* DONT COMMIT ENABLED! */ +#if 1 /* DONT COMMIT ENABLED! */ /* Blacklisted NT4SP1 areas - debugging why we sometimes crash early on, */ if ( 0 //|| (pInstrGC - 0x80010000U) < 0x10000U // NT4SP1 HAL @@ -4231,7 +4310,7 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) PATMP2GLOOKUPREC cacheRec; RT_ZERO(cacheRec); - pInstrHC = PATMGCVirtToHCVirt(pVM, &cacheRec, pInstrGC); + pInstrHC = patmR3GCVirtToHCVirt(pVM, &cacheRec, pInstrGC); AssertReturn(pInstrHC, VERR_PATCHING_REFUSED); /* Allocate patch record. */ @@ -4336,7 +4415,7 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) else if (pPatchRec->patch.flags & PATMFL_INT3_REPLACEMENT) { - rc = PATMR3PatchInstrInt3(pVM, pInstrGC, pInstrHC, &cpu, &pPatchRec->patch); + rc = patmR3PatchInstrInt3(pVM, pInstrGC, pInstrHC, &cpu, &pPatchRec->patch); } else if (pPatchRec->patch.flags & PATMFL_MMIO_ACCESS) @@ -4365,7 +4444,7 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) { case OP_SYSENTER: case OP_PUSH: - rc = PATMInstallGuestSpecificPatch(pVM, &cpu, pInstrGC, pInstrHC, pPatchRec); + rc = patmR3InstallGuestSpecificPatch(pVM, &cpu, pInstrGC, pInstrHC, pPatchRec); if (rc == VINF_SUCCESS) { if (rc == VINF_SUCCESS) @@ -4384,7 +4463,7 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) switch (cpu.pCurInstr->uOpcode) { case OP_SYSENTER: - rc = PATMInstallGuestSpecificPatch(pVM, &cpu, pInstrGC, pInstrHC, pPatchRec); + rc = patmR3InstallGuestSpecificPatch(pVM, &cpu, pInstrGC, pInstrHC, pPatchRec); if (rc == VINF_SUCCESS) { Log(("PATMR3InstallPatch GUEST: %s %RRv code32=%d\n", patmGetInstructionString(pPatchRec->patch.opcode, pPatchRec->patch.flags), pInstrGC, (flags & PATMFL_CODE32) ? 1 : 0)); @@ -4425,10 +4504,12 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) case OP_PUSHF: case OP_CLI: Log(("PATMR3InstallPatch %s %RRv code32=%d\n", patmGetInstructionString(pPatchRec->patch.opcode, pPatchRec->patch.flags), pInstrGC, (flags & PATMFL_CODE32) ? 1 : 0)); - rc = PATMR3PatchBlock(pVM, pInstrGC, pInstrHC, cpu.pCurInstr->uOpcode, cbInstr, pPatchRec); + rc = patmR3PatchBlock(pVM, pInstrGC, pInstrHC, cpu.pCurInstr->uOpcode, cbInstr, pPatchRec); break; +#ifndef VBOX_WITH_SAFE_STR case OP_STR: +#endif case OP_SGDT: case OP_SLDT: case OP_SIDT: @@ -4439,7 +4520,10 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) case OP_VERW: case OP_VERR: case OP_IRET: - rc = PATMR3PatchInstrInt3(pVM, pInstrGC, pInstrHC, &cpu, &pPatchRec->patch); +#ifdef VBOX_WITH_RAW_RING1 + case OP_MOV: +#endif + rc = patmR3PatchInstrInt3(pVM, pInstrGC, pInstrHC, &cpu, &pPatchRec->patch); break; default: @@ -4509,6 +4593,9 @@ VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags) #endif } #endif + + /* Add debug symbol. */ + patmR3DbgAddPatch(pVM, pPatchRec); } /* Free leftover lock if any. */ if (cacheRec.Lock.pvMap) @@ -4772,7 +4859,7 @@ int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch) * @param pVM Pointer to the VM. * @param pPatch Patch record */ -int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch) +static int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch) { int rc; RTRCUINTPTR pPatchPageStart, pPatchPageEnd, pPage; @@ -4807,13 +4894,14 @@ int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch) * @param cbWrite Nr of bytes to write * */ -VMMR3DECL(int) PATMR3PatchWrite(PVM pVM, RTRCPTR GCPtr, uint32_t cbWrite) +VMMR3_INT_DECL(int) PATMR3PatchWrite(PVM pVM, RTRCPTR GCPtr, uint32_t cbWrite) { RTRCUINTPTR pWritePageStart, pWritePageEnd, pPage; Log(("PATMR3PatchWrite %RRv %x\n", GCPtr, cbWrite)); Assert(VM_IS_EMT(pVM)); + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); /* Quick boundary check */ if ( GCPtr < pVM->patm.s.pPatchedInstrGCLowest @@ -4904,7 +4992,7 @@ loop_start: { LogRel(("PATM: Disable block at %RRv - write %RRv-%RRv\n", pPatch->pPrivInstrGC, pGuestPtrGC, pGuestPtrGC+cbWrite)); - PATMR3MarkDirtyPatch(pVM, pPatch); + patmR3MarkDirtyPatch(pVM, pPatch); /* Note: jump back to the start as the pPatchPage has been deleted or changed */ goto loop_start; @@ -4957,7 +5045,7 @@ invalid_write_loop_start: else { LogRel(("PATM: Disable block at %RRv - invalid write %RRv-%RRv \n", pPatch->pPrivInstrGC, GCPtr, GCPtr+cbWrite)); - PATMR3MarkDirtyPatch(pVM, pPatch); + patmR3MarkDirtyPatch(pVM, pPatch); } /* Note: jump back to the start as the pPatchPage has been deleted or changed */ goto invalid_write_loop_start; @@ -4978,11 +5066,13 @@ invalid_write_loop_start: * @returns VBox status code * @param pVM Pointer to the VM. * @param addr GC address of the page to flush + * @note Currently only called by CSAMR3FlushPage; optimization to avoid + * having to double check if the physical address has changed */ -/** @note Currently only called by CSAMR3FlushPage; optimization to avoid having to double check if the physical address has changed - */ -VMMR3DECL(int) PATMR3FlushPage(PVM pVM, RTRCPTR addr) +VMMR3_INT_DECL(int) PATMR3FlushPage(PVM pVM, RTRCPTR addr) { + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); + addr &= PAGE_BASE_GC_MASK; PPATMPATCHPAGE pPatchPage = (PPATMPATCHPAGE)RTAvloU32Get(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPage, addr); @@ -4998,7 +5088,7 @@ VMMR3DECL(int) PATMR3FlushPage(PVM pVM, RTRCPTR addr) PPATCHINFO pPatch = pPatchPage->papPatch[i]; Log(("PATMR3FlushPage %RRv remove patch at %RRv\n", addr, pPatch->pPrivInstrGC)); - PATMR3MarkDirtyPatch(pVM, pPatch); + patmR3MarkDirtyPatch(pVM, pPatch); } } STAM_COUNTER_INC(&pVM->patm.s.StatFlushed); @@ -5013,8 +5103,9 @@ VMMR3DECL(int) PATMR3FlushPage(PVM pVM, RTRCPTR addr) * @param pVM Pointer to the VM. * @param pInstrGC Guest context pointer to instruction */ -VMMR3DECL(bool) PATMR3HasBeenPatched(PVM pVM, RTRCPTR pInstrGC) +VMMR3_INT_DECL(bool) PATMR3HasBeenPatched(PVM pVM, RTRCPTR pInstrGC) { + Assert(!HMIsEnabled(pVM)); PPATMPATCHREC pPatchRec; pPatchRec = (PPATMPATCHREC)RTAvloU32Get(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC); if (pPatchRec && pPatchRec->patch.uState == PATCH_ENABLED) @@ -5038,12 +5129,12 @@ VMMR3DECL(int) PATMR3QueryOpcode(PVM pVM, RTRCPTR pInstrGC, uint8_t *pByte) /** @todo this will not work for aliased pages! (never has, but so far not a problem for us) */ /* Shortcut. */ - if ( !PATMIsEnabled(pVM) - || pInstrGC < pVM->patm.s.pPatchedInstrGCLowest - || pInstrGC > pVM->patm.s.pPatchedInstrGCHighest) - { + if (!PATMIsEnabled(pVM)) + return VERR_PATCH_NOT_FOUND; + Assert(!HMIsEnabled(pVM)); + if ( pInstrGC < pVM->patm.s.pPatchedInstrGCLowest + || pInstrGC > pVM->patm.s.pPatchedInstrGCHighest) return VERR_PATCH_NOT_FOUND; - } pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC, false); // if the patch is enabled and the pointer lies within 5 bytes of this priv instr ptr, then we've got a hit! @@ -5076,11 +5167,13 @@ VMMR3DECL(int) PATMR3QueryOpcode(PVM pVM, RTRCPTR pInstrGC, uint8_t *pByte) * @param cbToRead The maximum number bytes to read. * @param pcbRead Where to return the acutal number of bytes read. */ -VMMR3DECL(int) PATMR3ReadOrgInstr(PVM pVM, RTGCPTR32 GCPtrInstr, uint8_t *pbDst, size_t cbToRead, size_t *pcbRead) +VMMR3_INT_DECL(int) PATMR3ReadOrgInstr(PVM pVM, RTGCPTR32 GCPtrInstr, uint8_t *pbDst, size_t cbToRead, size_t *pcbRead) { /* Shortcut. */ - if ( !PATMIsEnabled(pVM) - || GCPtrInstr < pVM->patm.s.pPatchedInstrGCLowest + if (!PATMIsEnabled(pVM)) + return VERR_PATCH_NOT_FOUND; + Assert(!HMIsEnabled(pVM)); + if ( GCPtrInstr < pVM->patm.s.pPatchedInstrGCLowest || GCPtrInstr > pVM->patm.s.pPatchedInstrGCHighest) return VERR_PATCH_NOT_FOUND; @@ -5133,12 +5226,13 @@ VMMR3DECL(int) PATMR3ReadOrgInstr(PVM pVM, RTGCPTR32 GCPtrInstr, uint8_t *pbDst, * @note returns failure if patching is not allowed or possible * */ -VMMR3DECL(int) PATMR3DisablePatch(PVM pVM, RTRCPTR pInstrGC) +VMMR3_INT_DECL(int) PATMR3DisablePatch(PVM pVM, RTRCPTR pInstrGC) { PPATMPATCHREC pPatchRec; PPATCHINFO pPatch; Log(("PATMR3DisablePatch: %RRv\n", pInstrGC)); + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); pPatchRec = (PPATMPATCHREC)RTAvloU32Get(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC); if (pPatchRec) { @@ -5292,7 +5386,7 @@ static int patmDisableUnusablePatch(PVM pVM, RTRCPTR pInstrGC, RTRCPTR pConflict int rc; RT_ZERO(patch); - pInstrHC = PATMGCVirtToHCVirt(pVM, &patch, pInstrGC); + pInstrHC = patmR3GCVirtToHCVirt(pVM, &patch, pInstrGC); disret = patmR3DisInstr(pVM, &patch, pInstrGC, pInstrHC, PATMREAD_ORGCODE, &cpu, &cbInstr); /* * If it's a 5 byte relative jump, then we can work around the problem by replacing the 32 bits relative offset @@ -5379,12 +5473,13 @@ static int patmDisableUnusablePatch(PVM pVM, RTRCPTR pInstrGC, RTRCPTR pConflict * @note returns failure if patching is not allowed or possible * */ -VMMR3DECL(int) PATMR3EnablePatch(PVM pVM, RTRCPTR pInstrGC) +VMMR3_INT_DECL(int) PATMR3EnablePatch(PVM pVM, RTRCPTR pInstrGC) { PPATMPATCHREC pPatchRec; PPATCHINFO pPatch; Log(("PATMR3EnablePatch %RRv\n", pInstrGC)); + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); pPatchRec = (PPATMPATCHREC)RTAvloU32Get(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC); if (pPatchRec) { @@ -5498,7 +5593,7 @@ VMMR3DECL(int) PATMR3EnablePatch(PVM pVM, RTRCPTR pInstrGC) * @param pPatchRec Patch record * @param fForceRemove Remove *all* patches */ -int PATMRemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove) +int patmR3RemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove) { PPATCHINFO pPatch; @@ -5532,23 +5627,8 @@ int PATMRemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove) #ifdef VBOX_WITH_STATISTICS if (PATM_STAT_INDEX_IS_VALID(pPatchRec->patch.uPatchIdx)) { - STAMR3Deregister(pVM, &pPatchRec->patch); -#ifndef DEBUG_sandervl - STAMR3Deregister(pVM, &pVM->patm.s.pStatsHC[pPatchRec->patch.uPatchIdx]); - STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchBlockSize); - STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchJump); - STAMR3Deregister(pVM, &pPatchRec->patch.cbPrivInstr); - STAMR3Deregister(pVM, &pPatchRec->patch.cCodeWrites); - STAMR3Deregister(pVM, &pPatchRec->patch.cInvalidWrites); - STAMR3Deregister(pVM, &pPatchRec->patch.cTraps); - STAMR3Deregister(pVM, &pPatchRec->patch.flags); - STAMR3Deregister(pVM, &pPatchRec->patch.nrJumpRecs); - STAMR3Deregister(pVM, &pPatchRec->patch.nrFixups); - STAMR3Deregister(pVM, &pPatchRec->patch.opcode); - STAMR3Deregister(pVM, &pPatchRec->patch.uState); - STAMR3Deregister(pVM, &pPatchRec->patch.uOldState); - STAMR3Deregister(pVM, &pPatchRec->patch.uOpMode); -#endif + STAMR3DeregisterF(pVM->pUVM, "/PATM/Stats/Patch/0x%RRv", pPatchRec->patch.pPrivInstrGC); + STAMR3DeregisterF(pVM->pUVM, "/PATM/Stats/PatchBD/0x%RRv*", pPatchRec->patch.pPrivInstrGC); } #endif @@ -5650,33 +5730,18 @@ int patmR3RefreshPatch(PVM pVM, PPATMPATCHREC pPatchRec) pTrampolinePatchesHead = pPatch->pTrampolinePatchesHead; } - /** Note: quite ugly to enable/disable/remove/insert old and new patches, but there's no easy way around it. */ + /* Note: quite ugly to enable/disable/remove/insert old and new patches, but there's no easy way around it. */ rc = PATMR3DisablePatch(pVM, pInstrGC); AssertRC(rc); - /** Kick it out of the lookup tree to make sure PATMR3InstallPatch doesn't fail (hack alert) */ + /* Kick it out of the lookup tree to make sure PATMR3InstallPatch doesn't fail (hack alert) */ RTAvloU32Remove(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pPatchRec->Core.Key); #ifdef VBOX_WITH_STATISTICS if (PATM_STAT_INDEX_IS_VALID(pPatchRec->patch.uPatchIdx)) { - STAMR3Deregister(pVM, &pPatchRec->patch); -#ifndef DEBUG_sandervl - STAMR3Deregister(pVM, &pVM->patm.s.pStatsHC[pPatchRec->patch.uPatchIdx]); - STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchBlockSize); - STAMR3Deregister(pVM, &pPatchRec->patch.cbPatchJump); - STAMR3Deregister(pVM, &pPatchRec->patch.cbPrivInstr); - STAMR3Deregister(pVM, &pPatchRec->patch.cCodeWrites); - STAMR3Deregister(pVM, &pPatchRec->patch.cInvalidWrites); - STAMR3Deregister(pVM, &pPatchRec->patch.cTraps); - STAMR3Deregister(pVM, &pPatchRec->patch.flags); - STAMR3Deregister(pVM, &pPatchRec->patch.nrJumpRecs); - STAMR3Deregister(pVM, &pPatchRec->patch.nrFixups); - STAMR3Deregister(pVM, &pPatchRec->patch.opcode); - STAMR3Deregister(pVM, &pPatchRec->patch.uState); - STAMR3Deregister(pVM, &pPatchRec->patch.uOldState); - STAMR3Deregister(pVM, &pPatchRec->patch.uOpMode); -#endif + STAMR3DeregisterF(pVM->pUVM, "/PATM/Stats/Patch/0x%RRv", pPatchRec->patch.pPrivInstrGC); + STAMR3DeregisterF(pVM->pUVM, "/PATM/Stats/PatchBD/0x%RRv*", pPatchRec->patch.pPrivInstrGC); } #endif @@ -5710,7 +5775,7 @@ int patmR3RefreshPatch(PVM pVM, PPATMPATCHREC pPatchRec) Assert(pNewPatchRec); /* can't fail */ /* Remove old patch (only do that when everything is finished) */ - int rc2 = PATMRemovePatch(pVM, pPatchRec, true /* force removal */); + int rc2 = patmR3RemovePatch(pVM, pPatchRec, true /* force removal */); AssertRC(rc2); /* Put the new patch back into the tree, because removing the old one kicked this one out. (hack alert) */ @@ -5787,7 +5852,7 @@ failure: * @param fIncludeHints Include hinted patches or not * */ -PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncludeHints) +PPATCHINFO patmFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncludeHints) { PPATMPATCHREC pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC, false); /* if the patch is enabled, the pointer is not identical to the privileged patch ptr and it lies within 5 bytes of this priv instr ptr, then we've got a hit! */ @@ -5820,14 +5885,15 @@ PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncl * * @returns true -> yes, false -> no * @param pVM Pointer to the VM. - * @param pAddr Guest context address - * @param pPatchAddr Guest context patch address (if true) + * @param pAddr Guest context address. + * @param pPatchAddr Guest context patch address (if true). */ -VMMR3DECL(bool) PATMR3IsInsidePatchJump(PVM pVM, RTRCPTR pAddr, PRTGCPTR32 pPatchAddr) +VMMR3_INT_DECL(bool) PATMR3IsInsidePatchJump(PVM pVM, RTRCPTR pAddr, PRTGCPTR32 pPatchAddr) { RTRCPTR addr; PPATCHINFO pPatch; + Assert(!HMIsEnabled(pVM)); if (PATMIsEnabled(pVM) == false) return false; @@ -5836,7 +5902,7 @@ VMMR3DECL(bool) PATMR3IsInsidePatchJump(PVM pVM, RTRCPTR pAddr, PRTGCPTR32 pPatc *pPatchAddr = 0; - pPatch = PATMFindActivePatchByEntrypoint(pVM, pAddr); + pPatch = patmFindActivePatchByEntrypoint(pVM, pAddr); if (pPatch) *pPatchAddr = pPatch->pPrivInstrGC; @@ -5853,10 +5919,11 @@ VMMR3DECL(bool) PATMR3IsInsidePatchJump(PVM pVM, RTRCPTR pAddr, PRTGCPTR32 pPatc * @note returns failure if patching is not allowed or possible * */ -VMMR3DECL(int) PATMR3RemovePatch(PVM pVM, RTRCPTR pInstrGC) +VMMR3_INT_DECL(int) PATMR3RemovePatch(PVM pVM, RTRCPTR pInstrGC) { PPATMPATCHREC pPatchRec; + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); pPatchRec = (PPATMPATCHREC)RTAvloU32Get(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC); if (pPatchRec) { @@ -5864,7 +5931,7 @@ VMMR3DECL(int) PATMR3RemovePatch(PVM pVM, RTRCPTR pInstrGC) if (rc == VWRN_PATCH_REMOVED) return VINF_SUCCESS; - return PATMRemovePatch(pVM, pPatchRec, false); + return patmR3RemovePatch(pVM, pPatchRec, false); } AssertFailed(); return VERR_PATCH_NOT_FOUND; @@ -5880,7 +5947,7 @@ VMMR3DECL(int) PATMR3RemovePatch(PVM pVM, RTRCPTR pInstrGC) * @note returns failure if patching is not allowed or possible * */ -VMMR3DECL(int) PATMR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch) +static int patmR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch) { if (pPatch->pPatchBlockOffset) { @@ -5931,7 +5998,8 @@ RTRCPTR patmPatchGCPtr2GuestGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t return 0; } -/* Converts Guest code GC ptr to Patch code GC ptr (if found) +/** + * Converts Guest code GC ptr to Patch code GC ptr (if found) * * @returns corresponding GC pointer in patch block * @param pVM Pointer to the VM. @@ -5951,37 +6019,37 @@ RTRCPTR patmGuestGCPtrToPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t return 0; } -/* Converts Guest code GC ptr to Patch code GC ptr (or nearest from below if no identical match) +/** + * Converts Guest code GC ptr to Patch code GC ptr (if found) * * @returns corresponding GC pointer in patch block * @param pVM Pointer to the VM. - * @param pPatch Current patch block pointer * @param pInstrGC Guest context pointer to privileged instruction - * */ -RTRCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC) +static RTRCPTR patmR3GuestGCPtrToPatchGCPtrSimple(PVM pVM, RCPTRTYPE(uint8_t*) pInstrGC) { - PRECGUESTTOPATCH pGuestToPatchRec = (PRECGUESTTOPATCH)RTAvlU32GetBestFit(&pPatch->Guest2PatchAddrTree, pInstrGC, false); - if (pGuestToPatchRec) - return pVM->patm.s.pPatchMemGC + pGuestToPatchRec->PatchOffset; - - return 0; + PPATMPATCHREC pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC, false); + if (pPatchRec && pPatchRec->patch.uState == PATCH_ENABLED && pInstrGC >= pPatchRec->patch.pPrivInstrGC) + return patmGuestGCPtrToPatchGCPtr(pVM, &pPatchRec->patch, pInstrGC); + return NIL_RTRCPTR; } -/* Converts Guest code GC ptr to Patch code GC ptr (if found) +/** + * Converts Guest code GC ptr to Patch code GC ptr (or nearest from below if no + * identical match) * * @returns corresponding GC pointer in patch block * @param pVM Pointer to the VM. + * @param pPatch Current patch block pointer * @param pInstrGC Guest context pointer to privileged instruction * */ -VMMR3DECL(RTRCPTR) PATMR3GuestGCPtrToPatchGCPtr(PVM pVM, RCPTRTYPE(uint8_t*) pInstrGC) +RTRCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC) { - PPATMPATCHREC pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pInstrGC, false); - if (pPatchRec && pPatchRec->patch.uState == PATCH_ENABLED && pInstrGC >= pPatchRec->patch.pPrivInstrGC) - return patmGuestGCPtrToPatchGCPtr(pVM, &pPatchRec->patch, pInstrGC); - else - return 0; + PRECGUESTTOPATCH pGuestToPatchRec = (PRECGUESTTOPATCH)RTAvlU32GetBestFit(&pPatch->Guest2PatchAddrTree, pInstrGC, false); + if (pGuestToPatchRec) + return pVM->patm.s.pPatchMemGC + pGuestToPatchRec->PatchOffset; + return NIL_RTRCPTR; } /** @@ -5993,13 +6061,14 @@ VMMR3DECL(RTRCPTR) PATMR3GuestGCPtrToPatchGCPtr(PVM pVM, RCPTRTYPE(uint8_t*) pIn * @param pEnmState State of the translated address (out) * */ -VMMR3DECL(RTRCPTR) PATMR3PatchToGCPtr(PVM pVM, RTRCPTR pPatchGC, PATMTRANSSTATE *pEnmState) +VMMR3_INT_DECL(RTRCPTR) PATMR3PatchToGCPtr(PVM pVM, RTRCPTR pPatchGC, PATMTRANSSTATE *pEnmState) { PPATMPATCHREC pPatchRec; void *pvPatchCoreOffset; RTRCPTR pPrivInstrGC; Assert(PATMIsPatchGCAddr(pVM, pPatchGC)); + Assert(!HMIsEnabled(pVM)); pvPatchCoreOffset = RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTreeByPatchAddr, pPatchGC - pVM->patm.s.pPatchMemGC, false); if (pvPatchCoreOffset == 0) { @@ -6037,7 +6106,7 @@ VMMR3DECL(RTRCPTR) PATMR3PatchToGCPtr(PVM pVM, RTRCPTR pPatchGC, PATMTRANSSTATE *pEnmState = PATMTRANS_OVERWRITTEN; } else - if (PATMFindActivePatchByEntrypoint(pVM, pPrivInstrGC)) + if (patmFindActivePatchByEntrypoint(pVM, pPrivInstrGC)) { *pEnmState = PATMTRANS_OVERWRITTEN; } @@ -6059,17 +6128,18 @@ VMMR3DECL(RTRCPTR) PATMR3PatchToGCPtr(PVM pVM, RTRCPTR pPatchGC, PATMTRANSSTATE * @param pVM Pointer to the VM. * @param pAddrGC Guest context address */ -VMMR3DECL(RTRCPTR) PATMR3QueryPatchGCPtr(PVM pVM, RTRCPTR pAddrGC) +VMMR3_INT_DECL(RTRCPTR) PATMR3QueryPatchGCPtr(PVM pVM, RTRCPTR pAddrGC) { PPATMPATCHREC pPatchRec; + Assert(!HMIsEnabled(pVM)); + /* Find the patch record. */ pPatchRec = (PPATMPATCHREC)RTAvloU32Get(&pVM->patm.s.PatchLookupTreeHC->PatchTree, pAddrGC); /** @todo we should only use patches that are enabled! always did this, but it's incorrect! */ if (pPatchRec && (pPatchRec->patch.uState == PATCH_ENABLED || pPatchRec->patch.uState == PATCH_DIRTY)) return PATCHCODE_PTR_GC(&pPatchRec->patch); - else - return 0; + return NIL_RTRCPTR; } /** @@ -6129,7 +6199,7 @@ static int patmR3HandleDirtyInstr(PVM pVM, PCPUMCTX pCtx, PPATMPATCHREC pPatch, #ifdef DEBUG char szBuf[256]; - DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs.Sel, pCurPatchInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, + DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, pCtx->cs.Sel, pCurPatchInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); Log(("DIRTY: %s\n", szBuf)); #endif @@ -6192,7 +6262,7 @@ static int patmR3HandleDirtyInstr(PVM pVM, PCPUMCTX pCtx, PPATMPATCHREC pPatch, { #ifdef DEBUG char szBuf[256]; - DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs.Sel, pCurInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, + DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, pCtx->cs.Sel, pCurInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); Log(("NEW: %s\n", szBuf)); #endif @@ -6202,18 +6272,18 @@ static int patmR3HandleDirtyInstr(PVM pVM, PCPUMCTX pCtx, PPATMPATCHREC pPatch, AssertRC(rc); /* Add a new lookup record for the duplicated instruction. */ - patmr3AddP2GLookupRecord(pVM, &pPatch->patch, pCurPatchInstrHC, pCurInstrGC, PATM_LOOKUP_BOTHDIR); + patmR3AddP2GLookupRecord(pVM, &pPatch->patch, pCurPatchInstrHC, pCurInstrGC, PATM_LOOKUP_BOTHDIR); } else { #ifdef DEBUG char szBuf[256]; - DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs.Sel, pCurInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, + DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, pCtx->cs.Sel, pCurInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); Log(("NEW: %s (FAILED)\n", szBuf)); #endif /* Restore the old lookup record for the duplicated instruction. */ - patmr3AddP2GLookupRecord(pVM, &pPatch->patch, pCurPatchInstrHC, pCurInstrGC, PATM_LOOKUP_BOTHDIR); + patmR3AddP2GLookupRecord(pVM, &pPatch->patch, pCurPatchInstrHC, pCurInstrGC, PATM_LOOKUP_BOTHDIR); /** @todo in theory we need to restore the lookup records for the remaining dirty instructions too! */ rc = VERR_PATCHING_REFUSED; @@ -6245,8 +6315,8 @@ static int patmR3HandleDirtyInstr(PVM pVM, PCPUMCTX pCtx, PPATMPATCHREC pPatch, *(uint32_t *)&pPatchFillHC[1] = cbFiller - SIZEOF_NEARJUMP32; #ifdef DEBUG char szBuf[256]; - DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs.Sel, pCurPatchInstrGC, DBGF_DISAS_FLAGS_DEFAULT_MODE, - szBuf, sizeof(szBuf), NULL); + DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, pCtx->cs.Sel, pCurPatchInstrGC, + DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); Log(("FILL: %s\n", szBuf)); #endif } @@ -6257,7 +6327,7 @@ static int patmR3HandleDirtyInstr(PVM pVM, PCPUMCTX pCtx, PPATMPATCHREC pPatch, pPatchFillHC[i] = 0x90; /* NOP */ #ifdef DEBUG char szBuf[256]; - DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs.Sel, pCurPatchInstrGC + i, + DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, pCtx->cs.Sel, pCurPatchInstrGC + i, DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); Log(("FILL: %s\n", szBuf)); #endif @@ -6308,7 +6378,7 @@ static int patmR3HandleDirtyInstr(PVM pVM, PCPUMCTX pCtx, PPATMPATCHREC pPatch, * @param pEip GC pointer of trapping instruction. * @param ppNewEip GC pointer to new instruction. */ -VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *ppNewEip) +VMMR3_INT_DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *ppNewEip) { PPATMPATCHREC pPatch = 0; void *pvPatchCoreOffset; @@ -6318,6 +6388,7 @@ VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *p PRECPATCHTOGUEST pPatchToGuestRec = 0; PVMCPU pVCpu = VMMGetCpu0(pVM); + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); Assert(pVM->cCpus == 1); pNewEip = 0; @@ -6449,7 +6520,7 @@ VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *p } char szBuf[256]; - DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, pCtx->cs.Sel, pEip, DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); + DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, pCtx->cs.Sel, pEip, DBGF_DISAS_FLAGS_DEFAULT_MODE, szBuf, sizeof(szBuf), NULL); /* Very bad. We crashed in emitted code. Probably stack? */ if (pPatch) @@ -6507,7 +6578,7 @@ VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *p RT_ZERO(cacheRec); cacheRec.pPatch = &pPatch->patch; - disret = patmR3DisInstr(pVM, &pPatch->patch, pNewEip, PATMGCVirtToHCVirt(pVM, &cacheRec, pNewEip), PATMREAD_RAWCODE, + disret = patmR3DisInstr(pVM, &pPatch->patch, pNewEip, patmR3GCVirtToHCVirt(pVM, &cacheRec, pNewEip), PATMREAD_RAWCODE, &cpu, &cbInstr); if (cacheRec.Lock.pvMap) PGMPhysReleasePageMappingLock(pVM, &cacheRec.Lock); @@ -6546,14 +6617,14 @@ VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *p RT_ZERO(cacheRec); cacheRec.pPatch = &pPatch->patch; - disret = patmR3DisInstr(pVM, &pPatch->patch, pNewEip, PATMGCVirtToHCVirt(pVM, &cacheRec, pNewEip), PATMREAD_ORGCODE, + disret = patmR3DisInstr(pVM, &pPatch->patch, pNewEip, patmR3GCVirtToHCVirt(pVM, &cacheRec, pNewEip), PATMREAD_ORGCODE, &cpu, &cbInstr); if (cacheRec.Lock.pvMap) PGMPhysReleasePageMappingLock(pVM, &cacheRec.Lock); if (disret && (cpu.pCurInstr->uOpcode == OP_SYSEXIT || cpu.pCurInstr->uOpcode == OP_HLT || cpu.pCurInstr->uOpcode == OP_INT3)) { - disret = patmR3DisInstr(pVM, &pPatch->patch, pNewEip, PATMGCVirtToHCVirt(pVM, &cacheRec, pNewEip), PATMREAD_RAWCODE, + disret = patmR3DisInstr(pVM, &pPatch->patch, pNewEip, patmR3GCVirtToHCVirt(pVM, &cacheRec, pNewEip), PATMREAD_RAWCODE, &cpu, &cbInstr); if (cacheRec.Lock.pvMap) PGMPhysReleasePageMappingLock(pVM, &cacheRec.Lock); @@ -6566,7 +6637,7 @@ VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *p } Log2(("pPatchBlockGC %RRv - pEip %RRv corresponding GC address %RRv\n", PATCHCODE_PTR_GC(&pPatch->patch), pEip, pNewEip)); - DBGFR3DisasInstrLog(pVCpu, pCtx->cs.Sel, pNewEip, "PATCHRET: "); + DBGFR3_DISAS_INSTR_LOG(pVCpu, pCtx->cs.Sel, pNewEip, "PATCHRET: "); if (pNewEip >= pPatch->patch.pPrivInstrGC && pNewEip < pPatch->patch.pPrivInstrGC + pPatch->patch.cbPatchJump) { /* We can't jump back to code that we've overwritten with a 5 byte jump! */ @@ -6600,10 +6671,11 @@ VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *p * @returns VBox status code. * @param pVM Pointer to the VM. */ -VMMR3DECL(int) PATMR3HandleMonitoredPage(PVM pVM) +VMMR3_INT_DECL(int) PATMR3HandleMonitoredPage(PVM pVM) { - RTRCPTR addr = pVM->patm.s.pvFaultMonitor; + AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE); + RTRCPTR addr = pVM->patm.s.pvFaultMonitor; addr &= PAGE_BASE_GC_MASK; int rc = PGMHandlerVirtualDeregister(pVM, addr); @@ -6752,8 +6824,8 @@ RTRCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch) } #endif /* VBOX_WITH_STATISTICS */ - #ifdef VBOX_WITH_DEBUGGER + /** * The '.patmoff' command. * @@ -6764,17 +6836,21 @@ RTRCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch) * @param paArgs Pointer to (readonly) array of arguments. * @param cArgs Number of arguments in the array. */ -static DECLCALLBACK(int) patmr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) patmr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) { /* * Validate input. */ - NOREF(pCmd); NOREF(cArgs); NOREF(paArgs); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n"); + NOREF(cArgs); NOREF(paArgs); + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + + if (HMIsEnabled(pVM)) + return DBGCCmdHlpPrintf(pCmdHlp, "PATM is permanently disabled by HM.\n"); RTAvloU32DoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, DisableAllPatches, pVM); - PATMR3AllowPatching(pVM, false); + PATMR3AllowPatching(pVM->pUVM, false); return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Patching disabled\n"); } @@ -6788,17 +6864,22 @@ static DECLCALLBACK(int) patmr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM p * @param paArgs Pointer to (readonly) array of arguments. * @param cArgs Number of arguments in the array. */ -static DECLCALLBACK(int) patmr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) patmr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) { /* * Validate input. */ - NOREF(pCmd); NOREF(cArgs); NOREF(paArgs); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n"); + NOREF(cArgs); NOREF(paArgs); + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + + if (HMIsEnabled(pVM)) + return DBGCCmdHlpPrintf(pCmdHlp, "PATM is permanently disabled by HM.\n"); - PATMR3AllowPatching(pVM, true); + PATMR3AllowPatching(pVM->pUVM, true); RTAvloU32DoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true, EnableAllPatches, pVM); return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Patching enabled\n"); } -#endif + +#endif /* VBOX_WITH_DEBUGGER */ |
