diff options
Diffstat (limited to 'src/VBox/VMM/include/PATMInternal.h')
-rw-r--r-- | src/VBox/VMM/include/PATMInternal.h | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/src/VBox/VMM/include/PATMInternal.h b/src/VBox/VMM/include/PATMInternal.h new file mode 100644 index 00000000..28c1beba --- /dev/null +++ b/src/VBox/VMM/include/PATMInternal.h @@ -0,0 +1,692 @@ +/* $Id: PATMInternal.h $ */ +/** @file + * PATM - Internal header file. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef VMM_INCLUDED_SRC_include_PATMInternal_h +#define VMM_INCLUDED_SRC_include_PATMInternal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/vmm/patm.h> +#include <VBox/vmm/stam.h> +#include <VBox/dis.h> +#include <VBox/vmm/pgm.h> +#include <iprt/avl.h> +#include <iprt/param.h> +#include <VBox/log.h> + + +/** @name Saved state version numbers. + * @{ */ +/** New concept of helper code (for CPUID). */ +#define PATM_SAVED_STATE_VERSION 58 +/** New fixup type FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL. */ +#define PATM_SAVED_STATE_VERSION_FORGET_THIS_ONE 57 +/** Uses normal structure serialization with markers and everything. */ +#define PATM_SAVED_STATE_VERSION_NO_RAW_MEM 56 +/** Last version which saves structures as raw memory. */ +#define PATM_SAVED_STATE_VERSION_MEM 55 +#define PATM_SAVED_STATE_VERSION_FIXUP_HACK 54 +#define PATM_SAVED_STATE_VERSION_FIXUP_HACK 54 +#define PATM_SAVED_STATE_VERSION_VER16 53 +/** @} */ + +/* Enable for call patching. */ +#define PATM_ENABLE_CALL +#define PATCH_MEMORY_SIZE (2*1024*1024) +#define MAX_PATCH_SIZE (1024*4) + +/* + * Internal patch type flags (starts at RT_BIT(11)) + */ + +#define PATMFL_CHECK_SIZE RT_BIT_64(11) +#define PATMFL_FOUND_PATCHEND RT_BIT_64(12) +#define PATMFL_SINGLE_INSTRUCTION RT_BIT_64(13) +#define PATMFL_SYSENTER_XP RT_BIT_64(14) +#define PATMFL_JUMP_CONFLICT RT_BIT_64(15) +#define PATMFL_READ_ORIGINAL_BYTES RT_BIT_64(16) /** opcode might have already been patched */ +#define PATMFL_INT3_REPLACEMENT RT_BIT_64(17) +#define PATMFL_SUPPORT_CALLS RT_BIT_64(18) +#define PATMFL_SUPPORT_INDIRECT_CALLS RT_BIT_64(19) +#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT RT_BIT_64(20) /** internal flag to avoid duplicate entrypoints */ +#define PATMFL_INHIBIT_IRQS RT_BIT_64(21) /** temporary internal flag */ +#define PATMFL_GENERATE_JUMPTOGUEST RT_BIT_64(22) /** temporary internal flag */ +#define PATMFL_RECOMPILE_NEXT RT_BIT_64(23) /** for recompilation of the next instruction */ +#define PATMFL_CODE_MONITORED RT_BIT_64(24) /** code pages of guest monitored for self-modifying code. */ +#define PATMFL_CALLABLE_AS_FUNCTION RT_BIT_64(25) /** cli and pushf blocks can be used as callable functions. */ +#define PATMFL_GLOBAL_FUNCTIONS RT_BIT_64(26) /** fake patch for global patm functions. */ +#define PATMFL_TRAMPOLINE RT_BIT_64(27) /** trampoline patch that clears PATM_ASMFIX_INTERRUPTFLAG and jumps to patch destination */ +#define PATMFL_GENERATE_SETPIF RT_BIT_64(28) /** generate set PIF for the next instruction */ +#define PATMFL_INSTR_HINT RT_BIT_64(29) /** Generate patch, but don't activate it. */ +#define PATMFL_PATCHED_GUEST_CODE RT_BIT_64(30) /** Patched guest code. */ +#define PATMFL_MUST_INSTALL_PATCHJMP RT_BIT_64(31) /** Need to patch guest code in order to activate patch. */ +#define PATMFL_INT3_REPLACEMENT_BLOCK RT_BIT_64(32) /** int 3 replacement block */ +#define PATMFL_EXTERNAL_JUMP_INSIDE RT_BIT_64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */ +#define PATMFL_CODE_REFERENCED RT_BIT_64(34) /** patch block referenced (called, jumped to) by another patch. */ + +#define SIZEOF_NEARJUMP8 2 //opcode byte + 1 byte relative offset +#define SIZEOF_NEARJUMP16 3 //opcode byte + 2 byte relative offset +#define SIZEOF_NEARJUMP32 5 //opcode byte + 4 byte relative offset +#define SIZEOF_NEAR_COND_JUMP32 6 //0xF + opcode byte + 4 byte relative offset + +#define MAX_INSTR_SIZE 16 + +/* Patch states */ +#define PATCH_REFUSED 1 +#define PATCH_DISABLED 2 +#define PATCH_ENABLED 4 +#define PATCH_UNUSABLE 8 +#define PATCH_DIRTY 16 +#define PATCH_DISABLE_PENDING 32 + + +#define MAX_PATCH_TRAPS 4 +#define PATM_MAX_CALL_DEPTH 32 +/* Maximum nr of writes before a patch is marked dirty. (disabled) */ +#define PATM_MAX_CODE_WRITES 32 +/* Maximum nr of invalid writes before a patch is disabled. */ +#define PATM_MAX_INVALID_WRITES 16384 + +/** @name FIXUP_XXX - RELOCREC::uType values. + * @{ */ +/** Absolute fixup. With one exception (MMIO cache), this does not take any + * source or destination. @sa FIXUP_ABSOLUTE_ASM. */ +#define FIXUP_ABSOLUTE 0 +#define FIXUP_REL_JMPTOPATCH 1 +#define FIXUP_REL_JMPTOGUEST 2 +/** Absolute fixup in patch assembly code template. + * + * The source and desination addresses both set to the patch fixup type (see + * PATM_IS_ASMFIX and friends in PATMA.h). This is recent addition (CPUID + * subleaf code), so when loading older saved states this is usally represented + * as FIXUP_ABSOLUTE. */ +#define FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL 3 +/** Constant value that only needs fixing up when loading state. Structure + * size, member offset, or similar. The source and destination address are set + * like for FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL. */ +#define FIXUP_CONSTANT_IN_PATCH_ASM_TMPL 4 +/** Relative call to a patch helper routine in VMMRC. The source and destination + * address are set like for FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL. */ +#define FIXUP_REL_HELPER_IN_PATCH_ASM_TMPL 5 +/** @} */ + + +#define PATM_ILLEGAL_DESTINATION 0xDEADBEEF + +/** Size of the instruction that's used for requests from patch code (currently only call) */ +#define PATM_ILLEGAL_INSTR_SIZE 2 + + +/** No statistics counter index allocated just yet */ +#define PATM_STAT_INDEX_NONE (uint32_t)-1 +/** Dummy counter to handle overflows */ +#define PATM_STAT_INDEX_DUMMY 0 +#define PATM_STAT_INDEX_IS_VALID(a) (a != PATM_STAT_INDEX_DUMMY && a != PATM_STAT_INDEX_NONE) + +#ifdef VBOX_WITH_STATISTICS +#define PATM_STAT_RUN_INC(pPatch) \ + if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx)) \ + CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32A++; +#define PATM_STAT_FAULT_INC(pPatch) \ + if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx)) \ + CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32B++; +#else +#define PATM_STAT_RUN_INC(pPatch) do { } while (0) +#define PATM_STAT_FAULT_INC(pPatch) do { } while (0) +#endif + +/** Maximum number of stat counters. */ +#define PATM_STAT_MAX_COUNTERS 1024 +/** Size of memory allocated for patch statistics. */ +#define PATM_STAT_MEMSIZE (PATM_STAT_MAX_COUNTERS*sizeof(STAMRATIOU32)) + +/** aCpus[0].fLocalForcedActions fixup (must be uneven to avoid theoretical clashes with valid pointers) */ +#define PATM_FIXUP_CPU_FF_ACTION 0xffffff01 +/** default cpuid pointer fixup */ +#define PATM_FIXUP_CPUID_DEFAULT 0xffffff03 +/** standard cpuid pointer fixup */ +#define PATM_FIXUP_CPUID_STANDARD 0xffffff05 +/** extended cpuid pointer fixup */ +#define PATM_FIXUP_CPUID_EXTENDED 0xffffff07 +/** centaur cpuid pointer fixup */ +#define PATM_FIXUP_CPUID_CENTAUR 0xffffff09 + +typedef struct +{ + /** The key is a HC virtual address. */ + AVLPVNODECORE Core; + + uint32_t uType; + R3PTRTYPE(uint8_t *) pRelocPos; + RTRCPTR pSource; + RTRCPTR pDest; +} RELOCREC, *PRELOCREC; + +/* Cache record for guest to host pointer conversions. */ +typedef struct +{ + R3PTRTYPE(uint8_t *) pPageLocStartHC; + RCPTRTYPE(uint8_t *) pGuestLoc; + R3PTRTYPE(void *) pPatch; + PGMPAGEMAPLOCK Lock; +} PATMP2GLOOKUPREC, *PPATMP2GLOOKUPREC; + +/* Obsolete; do not use. */ +typedef struct +{ + R3PTRTYPE(uint8_t *) pPatchLocStartHC; + R3PTRTYPE(uint8_t *) pPatchLocEndHC; + RCPTRTYPE(uint8_t *) pGuestLoc; + uint32_t opsize; +} PATMP2GLOOKUPREC_OBSOLETE; + +typedef struct +{ + /** The key is a pointer to a JUMPREC structure. */ + AVLPVNODECORE Core; + + R3PTRTYPE(uint8_t *) pJumpHC; + RCPTRTYPE(uint8_t *) pTargetGC; + uint32_t offDispl; + uint32_t opcode; +} JUMPREC, *PJUMPREC; + +/** + * Patch to guest lookup type (single or both direction) + */ +typedef enum +{ + /** patch to guest */ + PATM_LOOKUP_PATCH2GUEST, + /** guest to patch + patch to guest */ + PATM_LOOKUP_BOTHDIR +} PATM_LOOKUP_TYPE; + +/** + * Patch to guest address lookup record. + */ +typedef struct RECPATCHTOGUEST +{ + /** The key is an offset inside the patch memory block. */ + AVLU32NODECORE Core; + /** GC address of the guest instruction this record is for. */ + RTRCPTR pOrgInstrGC; + /** Patch to guest lookup type. */ + PATM_LOOKUP_TYPE enmType; + /** Flag whether the original instruction was changed by the guest. */ + bool fDirty; + /** Flag whether this guest instruction is a jump target from + * a trampoline patch. */ + bool fJumpTarget; + /** Original opcode before writing 0xCC there to mark it dirty. */ + uint8_t u8DirtyOpcode; +} RECPATCHTOGUEST, *PRECPATCHTOGUEST; + +/** + * Guest to patch address lookup record + */ +typedef struct RECGUESTTOPATCH +{ + /** The key is a GC virtual address. */ + AVLU32NODECORE Core; + /** Patch offset (relative to PATM::pPatchMemGC / PATM::pPatchMemHC). */ + uint32_t PatchOffset; +} RECGUESTTOPATCH, *PRECGUESTTOPATCH; + +/** + * Temporary information used in ring 3 only; no need to waste memory in the patch record itself. + */ +typedef struct +{ + /* Temporary tree for storing the addresses of illegal instructions. */ + R3PTRTYPE(PAVLPVNODECORE) IllegalInstrTree; + uint32_t nrIllegalInstr; + + int32_t nrJumps; + uint32_t nrRetInstr; + + /* Temporary tree of encountered jumps. (debug only) */ + R3PTRTYPE(PAVLPVNODECORE) DisasmJumpTree; + + int32_t nrCalls; + + /** Last original guest instruction pointer; used for disassembly log. */ + RTRCPTR pLastDisasmInstrGC; + + /** Keeping track of multiple ret instructions. */ + RTRCPTR pPatchRetInstrGC; + uint32_t uPatchRetParam1; +} PATCHINFOTEMP, *PPATCHINFOTEMP; + +/** Forward declaration for a pointer to a trampoline patch record. */ +typedef struct TRAMPREC *PTRAMPREC; + +/** + * Patch information. + */ +typedef struct PATCHINFO +{ + /** Current patch state (enabled, disabled, etc.). */ + uint32_t uState; + /** Previous patch state. Used when enabling a disabled patch. */ + uint32_t uOldState; + /** CPU mode (16bit or 32bit). */ + DISCPUMODE uOpMode; + /** GC pointer of privileged instruction */ + RCPTRTYPE(uint8_t *) pPrivInstrGC; + /** @todo: Can't remove due to structure size dependencies in saved states. */ + R3PTRTYPE(uint8_t *) unusedHC; + /** Original privileged guest instructions overwritten by the jump patch. */ + uint8_t aPrivInstr[MAX_INSTR_SIZE]; + /** Number of valid bytes in the instruction buffer. */ + uint32_t cbPrivInstr; + /** Opcode for priv instr (OP_*). */ + uint32_t opcode; + /** Size of the patch jump in the guest code. */ + uint32_t cbPatchJump; + /** Only valid for PATMFL_JUMP_CONFLICT patches */ + RTRCPTR pPatchJumpDestGC; + /** Offset of the patch code from the beginning of the patch memory area. */ + RTGCUINTPTR32 pPatchBlockOffset; + /** Size of the patch code in bytes. */ + uint32_t cbPatchBlockSize; + /** Current offset of the patch starting from pPatchBlockOffset. + * Used during patch creation. */ + uint32_t uCurPatchOffset; +#if HC_ARCH_BITS == 64 + uint32_t Alignment0; /**< Align flags correctly. */ +#endif + /** PATM flags (see PATMFL_*). */ + uint64_t flags; + /** + * Lowest and highest patched GC instruction address. To optimize searches. + */ + RTRCPTR pInstrGCLowest; + RTRCPTR pInstrGCHighest; + /* Tree of fixup records for the patch. */ + R3PTRTYPE(PAVLPVNODECORE) FixupTree; + uint32_t nrFixups; + /* Tree of jumps inside the generated patch code. */ + uint32_t nrJumpRecs; + R3PTRTYPE(PAVLPVNODECORE) JumpTree; + /** + * Lookup trees for determining the corresponding guest address of an + * instruction in the patch block. + */ + R3PTRTYPE(PAVLU32NODECORE) Patch2GuestAddrTree; + R3PTRTYPE(PAVLU32NODECORE) Guest2PatchAddrTree; + uint32_t nrPatch2GuestRecs; +#if HC_ARCH_BITS == 64 + uint32_t Alignment1; +#endif + /** Unused, but can't remove due to structure size dependencies in the saved state. */ + PATMP2GLOOKUPREC_OBSOLETE unused; + /** Temporary information during patch creation. Don't waste hypervisor memory for this. */ + R3PTRTYPE(PPATCHINFOTEMP) pTempInfo; + /** List of trampoline patches referencing this patch. + * Used when refreshing the patch. (Only for function duplicates) */ + R3PTRTYPE(PTRAMPREC) pTrampolinePatchesHead; + /** Count the number of writes to the corresponding guest code. */ + uint32_t cCodeWrites; + /** Some statistics to determine if we should keep this patch activated. */ + uint32_t cTraps; + /** Count the number of invalid writes to pages monitored for the patch. */ + uint32_t cInvalidWrites; + /** Index into the uPatchRun and uPatchTrap arrays (0..MAX_PATCHES-1) */ + uint32_t uPatchIdx; + /** First opcode byte, that's overwritten when a patch is marked dirty. */ + uint8_t bDirtyOpcode; + /** Align the structure size on a 8-byte boundary. */ + uint8_t Alignment2[HC_ARCH_BITS == 64 ? 7 : 3]; +} PATCHINFO, *PPATCHINFO; + +#define PATCHCODE_PTR_GC(pPatch) (RTRCPTR) (pVM->patm.s.pPatchMemGC + (pPatch)->pPatchBlockOffset) +#define PATCHCODE_PTR_HC(pPatch) (uint8_t *)(pVM->patm.s.pPatchMemHC + (pPatch)->pPatchBlockOffset) + +/** + * Lookup record for patches + */ +typedef struct PATMPATCHREC +{ + /** The key is a GC virtual address. */ + AVLOU32NODECORE Core; + /** The key is a patch offset. */ + AVLOU32NODECORE CoreOffset; + /** The patch information. */ + PATCHINFO patch; +} PATMPATCHREC, *PPATMPATCHREC; + +/** + * Record for a trampoline patch. + */ +typedef struct TRAMPREC +{ + /** Pointer to the next trampoline patch. */ + struct TRAMPREC *pNext; + /** Pointer to the trampoline patch record. */ + PPATMPATCHREC pPatchTrampoline; +} TRAMPREC; + +/** Increment for allocating room for pointer array */ +#define PATMPATCHPAGE_PREALLOC_INCREMENT 16 + +/** + * Lookup record for patch pages + */ +typedef struct PATMPATCHPAGE +{ + /** The key is a GC virtual address. */ + AVLOU32NODECORE Core; + /** Region to monitor. */ + RTRCPTR pLowestAddrGC; + RTRCPTR pHighestAddrGC; + /** Number of patches for this page. */ + uint32_t cCount; + /** Maximum nr of pointers in the array. */ + uint32_t cMaxPatches; + /** Array of patch pointers for this page. */ + R3PTRTYPE(PPATCHINFO *) papPatch; +} PATMPATCHPAGE, *PPATMPATCHPAGE; + +#define PATM_PATCHREC_FROM_COREOFFSET(a) (PPATMPATCHREC)((uintptr_t)a - RT_UOFFSETOF(PATMPATCHREC, CoreOffset)) +#define PATM_PATCHREC_FROM_PATCHINFO(a) (PPATMPATCHREC)((uintptr_t)a - RT_UOFFSETOF(PATMPATCHREC, patch)) + +/** + * AVL trees used by PATM. + */ +typedef struct PATMTREES +{ + /** + * AVL tree with all patches (active or disabled) sorted by guest instruction address + */ + AVLOU32TREE PatchTree; + + /** + * AVL tree with all patches sorted by patch address (offset actually) + */ + AVLOU32TREE PatchTreeByPatchAddr; + + /** + * AVL tree with all pages which were (partly) patched + */ + AVLOU32TREE PatchTreeByPage; + + uint32_t align[1]; +} PATMTREES, *PPATMTREES; + +/** + * PATM VM Instance data. + * Changes to this must checked against the padding of the patm union in VM! + */ +typedef struct PATM +{ + /** Offset to the VM structure. + * See PATM2VM(). */ + RTINT offVM; + /** Pointer to the patch memory area (GC) */ + RCPTRTYPE(uint8_t *) pPatchMemGC; + /** Pointer to the patch memory area (HC) */ + R3PTRTYPE(uint8_t *) pPatchMemHC; + /** Size of the patch memory area in bytes. */ + uint32_t cbPatchMem; + /** Relative offset to the next free byte starting from the start of the region. */ + uint32_t offPatchMem; + /** Flag whether PATM ran out of patch memory. */ + bool fOutOfMemory; + /** Delta to the new relocated HMA area. + * Used only during PATMR3Relocate(). */ + int32_t deltaReloc; + + /** The ring-3 address of the PatchHlp segment (for PATMReadPatchCode). */ + R3PTRTYPE(uint8_t *) pbPatchHelpersR3; + /** The raw-mode address of the PatchHlp segment. */ + RCPTRTYPE(uint8_t *) pbPatchHelpersRC; + /** Size of the PatchHlp segment containing the callable helper code. */ + uint32_t cbPatchHelpers; + + /** GC PATM state pointer - HC pointer. */ + R3PTRTYPE(PPATMGCSTATE) pGCStateHC; + /** GC PATM state pointer - RC pointer. */ + RCPTRTYPE(PPATMGCSTATE) pGCStateGC; + + /** PATM stack page for call instruction execution. + * 2 parts: one for our private stack and one to store the original return + * address. */ + RCPTRTYPE(RTRCPTR *) pGCStackGC; + /** HC pointer of the PATM stack page. */ + R3PTRTYPE(RTRCPTR *) pGCStackHC; + /** GC pointer to CPUMCTX structure. */ + RCPTRTYPE(PCPUMCTX) pCPUMCtxGC; + + /** GC statistics pointer. */ + RCPTRTYPE(PSTAMRATIOU32) pStatsGC; + /** HC statistics pointer. */ + R3PTRTYPE(PSTAMRATIOU32) pStatsHC; + + /** Current free index value (uPatchRun/uPatchTrap arrays). */ + uint32_t uCurrentPatchIdx; + /** Temporary counter for patch installation call depth. (in order not to go on forever) */ + uint32_t ulCallDepth; + /** Number of page lookup records. */ + uint32_t cPageRecords; + /** Lowest and highest patched GC instruction addresses. To optimize searches. */ + RTRCPTR pPatchedInstrGCLowest; + RTRCPTR pPatchedInstrGCHighest; + /** Pointer to the patch tree for instructions replaced by 'int 3'. */ + RCPTRTYPE(PPATMTREES) PatchLookupTreeGC; + R3PTRTYPE(PPATMTREES) PatchLookupTreeHC; + /** Global PATM lookup and call function (used by call patches). */ + RTRCPTR pfnHelperCallGC; + /** Global PATM return function (used by ret patches). */ + RTRCPTR pfnHelperRetGC; + /** Global PATM jump function (used by indirect jmp patches). */ + RTRCPTR pfnHelperJumpGC; + /** Global PATM return function (used by iret patches). */ + RTRCPTR pfnHelperIretGC; + /** Fake patch record for global functions. */ + R3PTRTYPE(PPATMPATCHREC) pGlobalPatchRec; + /** Pointer to original sysenter handler */ + RTRCPTR pfnSysEnterGC; + /** Pointer to sysenter handler trampoline */ + RTRCPTR pfnSysEnterPatchGC; + /** Sysenter patch index (for stats only) */ + uint32_t uSysEnterPatchIdx; + /** GC address of fault in monitored page (set by PATMGCMonitorPage, used by PATMR3HandleMonitoredPage)- */ + RTRCPTR pvFaultMonitor; + /** Temporary information for pending MMIO patch. Set in GC or R0 context. */ + struct + { + RTGCPHYS GCPhys; + RTRCPTR pCachedData; + RTRCPTR Alignment0; /**< Align the structure size on a 8-byte boundary. */ + } mmio; + /** Temporary storage during load/save state */ + struct + { + R3PTRTYPE(PSSMHANDLE) pSSM; + uint32_t cPatches; +#if HC_ARCH_BITS == 64 + uint32_t Alignment0; /**< Align the structure size on a 8-byte boundary. */ +#endif + } savedstate; + + /** Debug module for the patch memory. */ + RTDBGMOD hDbgModPatchMem; + + /** Virtual page access handler type (patmVirtPageHandler, + * PATMGCMonitorPage). */ + PGMVIRTHANDLERTYPE hMonitorPageType; + + /** Align statistics on a 8 byte boundary. */ + uint32_t u32Alignment1; + + STAMCOUNTER StatNrOpcodeRead; + STAMCOUNTER StatDisabled; + STAMCOUNTER StatUnusable; + STAMCOUNTER StatEnabled; + STAMCOUNTER StatInstalled; + STAMCOUNTER StatInstalledFunctionPatches; + STAMCOUNTER StatInstalledTrampoline; + STAMCOUNTER StatInstalledJump; + STAMCOUNTER StatInt3Callable; + STAMCOUNTER StatInt3BlockRun; + STAMCOUNTER StatOverwritten; + STAMCOUNTER StatFixedConflicts; + STAMCOUNTER StatFlushed; + STAMCOUNTER StatPageBoundaryCrossed; + STAMCOUNTER StatMonitored; + STAMPROFILEADV StatHandleTrap; + STAMCOUNTER StatSwitchBack; + STAMCOUNTER StatSwitchBackFail; + STAMCOUNTER StatPATMMemoryUsed; + STAMCOUNTER StatDuplicateREQSuccess; + STAMCOUNTER StatDuplicateREQFailed; + STAMCOUNTER StatDuplicateUseExisting; + STAMCOUNTER StatFunctionFound; + STAMCOUNTER StatFunctionNotFound; + STAMPROFILEADV StatPatchWrite; + STAMPROFILEADV StatPatchWriteDetect; + STAMCOUNTER StatDirty; + STAMCOUNTER StatPushTrap; + STAMCOUNTER StatPatchWriteInterpreted; + STAMCOUNTER StatPatchWriteInterpretedFailed; + + STAMCOUNTER StatSysEnter; + STAMCOUNTER StatSysExit; + STAMCOUNTER StatEmulIret; + STAMCOUNTER StatEmulIretFailed; + + STAMCOUNTER StatInstrDirty; + STAMCOUNTER StatInstrDirtyGood; + STAMCOUNTER StatInstrDirtyBad; + + STAMCOUNTER StatPatchPageInserted; + STAMCOUNTER StatPatchPageRemoved; + + STAMCOUNTER StatPatchRefreshSuccess; + STAMCOUNTER StatPatchRefreshFailed; + + STAMCOUNTER StatGenRet; + STAMCOUNTER StatGenRetReused; + STAMCOUNTER StatGenJump; + STAMCOUNTER StatGenCall; + STAMCOUNTER StatGenPopf; + + STAMCOUNTER StatCheckPendingIRQ; + + STAMCOUNTER StatFunctionLookupReplace; + STAMCOUNTER StatFunctionLookupInsert; + uint32_t StatU32FunctionMaxSlotsUsed; + uint32_t Alignment0; /**< Align the structure size on a 8-byte boundary. */ +} PATM, *PPATM; + + + +DECLCALLBACK(int) patmR3Save(PVM pVM, PSSMHANDLE pSSM); +DECLCALLBACK(int) patmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); + +#ifdef IN_RING3 +RTRCPTR patmPatchGCPtr2GuestGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pPatchGC); +RTRCPTR patmGuestGCPtrToPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC); +RTRCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC); +#endif + +void patmR3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC, + PATM_LOOKUP_TYPE enmType, bool fDirty = false); +int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch); +RTRCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch); +int patmR3RemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove); + +/** + * Call for analysing the instructions following the privileged instr. for compliance with our heuristics + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pCpu CPU disassembly state + * @param pInstrHC Guest context pointer to privileged instruction + * @param pCurInstrHC Guest context pointer to current instruction + * @param pCacheRec Cache record ptr + * + */ +typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PPATMP2GLOOKUPREC pCacheRec); + +int patmR3InstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTRCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec); +PPATMPATCHREC patmQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC); +const char *patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags); + +PPATCHINFO patmFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncludeHints = false); +int patmR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch); +int patmAddBranchToLookupCache(PVM pVM, RTRCPTR pJumpTableGC, RTRCPTR pBranchTarget, RTRCUINTPTR pRelBranchPatch); +R3PTRTYPE(uint8_t *) patmR3GCVirtToHCVirt(PVM pVM, PPATMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr); + +RT_C_DECLS_BEGIN +DECLEXPORT(FNPGMRCVIRTPFHANDLER) patmRCVirtPagePfHandler; +RT_C_DECLS_END + +/** + * Calculate the branch destination + * + * @returns branch destination or 0 if failed + * @param pCpu Disassembly state of instruction. + * @param pBranchInstrGC GC pointer of branch instruction + */ +DECLINLINE(RTRCPTR) PATMResolveBranch(PDISCPUSTATE pCpu, RTRCPTR pBranchInstrGC) +{ + uint32_t disp; + if (pCpu->Param1.fUse & DISUSE_IMMEDIATE8_REL) + { + disp = (int32_t)(char)pCpu->Param1.uValue; + } + else + if (pCpu->Param1.fUse & DISUSE_IMMEDIATE16_REL) + { + disp = (int32_t)(uint16_t)pCpu->Param1.uValue; + } + else + if (pCpu->Param1.fUse & DISUSE_IMMEDIATE32_REL) + { + disp = (int32_t)pCpu->Param1.uValue; + } + else + { + Log(("We don't support far jumps here!! (%08X)\n", pCpu->Param1.fUse)); + return 0; + } +#ifdef IN_RC + return (RTRCPTR)((uint8_t *)pBranchInstrGC + pCpu->cbInstr + disp); +#else + return pBranchInstrGC + pCpu->cbInstr + disp; +#endif +} + +#ifdef LOG_ENABLED +DECLCALLBACK(int) patmR3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PPATMP2GLOOKUPREC pCacheRec); +int patmr3DisasmCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, PPATMP2GLOOKUPREC pCacheRec); +#endif + + +void patmR3DbgInit(PVM pVM); +void patmR3DbgTerm(PVM pVM); +void patmR3DbgReset(PVM pVM); +void patmR3DbgAddPatch(PVM pVM, PPATMPATCHREC pPatchRec); + +PGM_ALL_CB2_PROTO(FNPGMVIRTHANDLER) patmVirtPageHandler; + +#endif /* !VMM_INCLUDED_SRC_include_PATMInternal_h */ |