PATMInternal.h revision d4c86e452c164353ab87a2e6455abd365be348a5
/* $Id$ */
/** @file
* PATM - Internal header file.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#ifndef ___PATMInternal_h
#define ___PATMInternal_h
# error "Not in PATM! This is an internal header!"
#endif
#define PATM_SSM_VERSION 53
/* Enable for call patching. */
#define PATM_ENABLE_CALL
/*
* Internal patch type flags (starts at RT_BIT(11))
*/
#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT RT_BIT_64(20) /** internal flag to avoid duplicate entrypoints */
#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_TRAMPOLINE RT_BIT_64(27) /** trampoline patch that clears PATM_INTERRUPTFLAG and jumps to patch destination */
#define PATMFL_MUST_INSTALL_PATCHJMP RT_BIT_64(31) /** Need to patch guest code in order to activate patch. */
#define PATMFL_EXTERNAL_JUMP_INSIDE RT_BIT_64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */
#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
#define FIXUP_ABSOLUTE 0
#define FIXUP_REL_JMPTOPATCH 1
#define FIXUP_REL_JMPTOGUEST 2
#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 */
/** Dummy counter to handle overflows */
#define PATM_STAT_INDEX_DUMMY 0
#ifdef VBOX_WITH_STATISTICS
#define PATM_STAT_RUN_INC(pPatch) \
#define PATM_STAT_FAULT_INC(pPatch) \
#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. */
typedef struct
{
/** The key is a HC virtual address. */
typedef struct
{
typedef struct
{
/** The key is a pointer to a JUMPREC structure. */
/**
* Patch to guest lookup type (single or both direction)
*/
typedef enum
{
PATM_LOOKUP_PATCH2GUEST, /* patch to guest */
PATM_LOOKUP_BOTHDIR /* guest to patch + patch to guest */
/**
* Patch to guest address lookup record
*/
typedef struct RECPATCHTOGUEST
{
/** The key is an offset inside the patch memory block. */
bool fDirty;
bool fJumpTarget;
/**
* Guest to patch address lookup record
*/
typedef struct RECGUESTTOPATCH
{
/** The key is a GC virtual address. */
/** Patch offset (relative to PATM::pPatchMemGC / PATM::pPatchMemHC). */
/**
* 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. */
/* Temporary tree of encountered jumps. (debug only) */
/** Last original guest instruction pointer; used for disassmebly log. */
/** Keeping track of multiple ret instructions. */
typedef struct _PATCHINFO
{
/* Only valid for PATMFL_JUMP_CONFLICT patches */
#if HC_ARCH_BITS == 64
#endif
/**
* Lowest and highest patched GC instruction address. To optimize searches.
*/
/* Tree of fixup records for the patch. */
/* Tree of jumps inside the generated patch code. */
/**
* Lookup trees for determining the corresponding guest address of an
* instruction in the patch block.
*/
#if HC_ARCH_BITS == 64
#endif
// Cache record for PATMGCVirtToHCVirt
/* Temporary information during patch creation. Don't waste hypervisor memory for this. */
/* Count the number of writes to the corresponding guest code. */
/* Count the number of invalid writes to pages monitored for the patch. */
//some statistics to determine if we should keep this patch activated
// Index into the uPatchRun and uPatchTrap arrays (0..MAX_PATCHES-1)
/* First opcode byte, that's overwritten when a patch is marked dirty. */
} PATCHINFO, *PPATCHINFO;
/**
* Lookup record for patches
*/
typedef struct PATMPATCHREC
{
/** The key is a GC virtual address. */
/** The key is a patch offset. */
/** 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. */
/** Region to monitor. */
/** Number of patches for this page. */
/** Maximum nr of pointers in the array. */
/** Array of patch pointers for this page. */
#define PATM_PATCHREC_FROM_COREOFFSET(a) (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, CoreOffset))
#define PATM_PATCHREC_FROM_PATCHINFO(a) (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, patch))
typedef struct PATMTREES
{
/**
* AVL tree with all patches (active or disabled) sorted by guest instruction address
*/
/**
* AVL tree with all patches sorted by patch address (offset actually)
*/
/**
* AVL tree with all pages which were (partly) patched
*/
} 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(). */
bool fOutOfMemory;
/* GC PATM state pointers */
/** PATM stack page for call instruction execution. (2 parts: one for our private stack and one to store the original return address */
/** GC pointer to CPUMCTX structure. */
/* GC statistics pointers */
/* Current free index value (uPatchRun/uPatchTrap arrays). */
/* Temporary counter for patch installation call depth. (in order not to go on forever) */
/** Number of page lookup records. */
/**
* Lowest and highest patched GC instruction addresses. To optimize searches.
*/
/** Pointer to the patch tree for instructions replaced by 'int 3'. */
/** Global PATM lookup and call function (used by call patches). */
/** Global PATM return function (used by ret patches). */
/** Global PATM jump function (used by indirect jmp patches). */
/** Global PATM return function (used by iret patches). */
/** Fake patch record for global functions. */
/** Pointer to original sysenter handler */
/** Pointer to sysenter handler trampoline */
/** Sysenter patch index (for stats only) */
// GC address of fault in monitored page (set by PATMGCMonitorPage, used by PATMR3HandleMonitoredPage)
/* Temporary information for pending MMIO patch. Set in GC or R0 context. */
struct
{
#if GC_ARCH_BITS == 32
#endif
} mmio;
struct
{
#if HC_ARCH_BITS == 64
#endif
} savedstate;
/**
* Execute state save operation.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSSM SSM operation handle.
*/
/**
* Execute state load operation.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSSM SSM operation handle.
* @param u32Version Data layout version.
*/
#ifdef IN_RING3
RTRCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC);
#endif
/* Add a patch to guest lookup record
*
* @param pVM The VM to operate on.
* @param pPatch Patch structure ptr
* @param pPatchInstrHC Guest context pointer to patch block
* @param pInstrGC Guest context pointer to privileged instruction
* @param enmType Lookup type
* @param fDirty Dirty flag
*
*/
void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty=false);
/**
* Insert page records for all guest pages that contain instructions that were recompiled for this patch
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pPatch Patch record
*/
/**
* Remove page records for all guest pages that contain instructions that were recompiled for this patch
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pPatch Patch record
*/
/**
* Returns the GC address of the corresponding patch statistics counter
*
* @returns Stat address
* @param pVM The VM to operate on.
* @param pPatch Patch structure
*/
/**
* Remove patch for privileged instruction at specified location
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pPatchRec Patch record
* @param fForceRemove Remove *all* patches
*/
/**
* Call for analysing the instructions following the privileged instr. for compliance with our heuristics
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pCpu CPU disassembly state
* @param pInstrHC Guest context pointer to privileged instruction
* @param pCurInstrHC Guest context pointer to current instruction
* @param pUserData User pointer
*
*/
typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
/**
* Install guest OS specific patch
*
* @returns VBox status code.
* @param pVM The VM to operate on
* @param pCpu Disassembly state of instruction.
* @param pInstrGC GC Instruction pointer for instruction
* @param pInstrHC GC Instruction pointer for instruction
* @param pPatchRec Patch structure
*
*/
int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTRCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);
/**
* Convert guest context address to host context pointer
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pPatch Patch block structure pointer
* @param pGCPtr Guest context pointer
*
* @returns Host context pointer or NULL in case of an error
*
*/
/**
* Check if the instruction is patched as a duplicated function
*
* @returns patch record
* @param pVM The VM to operate on.
* @param pInstrGC Guest context point to the instruction
*
*/
/**
* Empty the specified tree (PV tree, MMR3 heap)
*
* @param pVM The VM to operate on.
* @param ppTree Tree to empty
*/
/**
* Empty the specified tree (U32 tree, MMR3 heap)
*
* @param pVM The VM to operate on.
* @param ppTree Tree to empty
*/
/**
* Return the name of the patched instruction
*
* @returns instruction name
*
* @param opcode DIS instruction opcode
* @param fPatchFlags Patch flags
*/
/**
* Read callback for disassembly function; supports reading bytes that cross a page boundary
*
* @returns VBox status code.
* @param pSrc GC source pointer
* @param pDest HC destination pointer
* @param size Number of bytes to read
* @param pvUserdata Callback specific user data (pCpu)
*
*/
#ifndef IN_GC
/*
* Private structure used during disassembly
*/
typedef struct
{
} PATMDISASM, *PPATMDISASM;
{
}
#endif /* !IN_GC */
/**
* #PF Virtual Handler callback for Guest access a page monitored by PATM
*
* @returns VBox status code (appropritate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
PATMGCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, void *pvRange, uintptr_t offRange);
/**
* Find patch for privileged instruction at specified location
*
* @returns Patch structure pointer if found; else NULL
* @param pVM The VM to operate on.
* @param pInstr Guest context point to instruction that might lie within 5 bytes of an existing patch jump
* @param fIncludeHints Include hinted patches or not
*
*/
/**
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pInstrGC Guest context point to privileged instruction
* @param pInstrHC Host context point to privileged instruction
* @param uOpcode Instruction opcodee
* @param uOpSize Size of starting instruction
* @param pPatchRec Patch record
*
* @note returns failure if patching is not allowed or possible
*
*/
/**
* Replace an instruction with a breakpoint (0xCC), that is handled dynamically in the guest context.
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pInstrGC Guest context point to privileged instruction
* @param pInstrHC Host context point to privileged instruction
* @param pCpu Disassembly CPU structure ptr
* @param pPatch Patch record
*
* @note returns failure if patching is not allowed or possible
*
*/
PATMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);
/**
* Mark patch as dirty
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param pPatch Patch record
*
* @note returns failure if patching is not allowed or possible
*
*/
/**
* Calculate the branch destination
*
* @returns branch destination or 0 if failed
* @param pCpu Disassembly state of instruction.
* @param pBranchInstrGC GC pointer of branch instruction
*/
{
{
}
else
{
}
else
{
}
else
{
return 0;
}
#ifdef IN_GC
#else
#endif
}
#ifdef DEBUG
int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
int patmr3DisasmCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, void *pUserData);
#endif
#endif