VirtualBox

source: vbox/trunk/src/VBox/VMM/include/PATMInternal.h@ 36801

Last change on this file since 36801 was 36801, checked in by vboxsync, 14 years ago

PATM: Indentation and comments of the structures. Fix remaining RTAvl*Insert return values

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.8 KB
Line 
1/* $Id: PATMInternal.h 36801 2011-04-21 18:14:13Z vboxsync $ */
2/** @file
3 * PATM - Internal header file.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef ___PATMInternal_h
19#define ___PATMInternal_h
20
21#include <VBox/cdefs.h>
22#include <VBox/types.h>
23#include <VBox/vmm/patm.h>
24#include <VBox/vmm/stam.h>
25#include <VBox/dis.h>
26#include <VBox/vmm/pgm.h>
27#include <iprt/avl.h>
28#include <iprt/param.h>
29#include <VBox/log.h>
30
31
32
33#define PATM_SSM_VERSION 55
34#define PATM_SSM_VERSION_FIXUP_HACK 54
35#define PATM_SSM_VERSION_FIXUP_HACK 54
36#define PATM_SSM_VERSION_VER16 53
37
38/* Enable for call patching. */
39#define PATM_ENABLE_CALL
40#define PATCH_MEMORY_SIZE (2*1024*1024)
41#define MAX_PATCH_SIZE (1024*4)
42
43/*
44 * Internal patch type flags (starts at RT_BIT(11))
45 */
46
47#define PATMFL_CHECK_SIZE RT_BIT_64(11)
48#define PATMFL_FOUND_PATCHEND RT_BIT_64(12)
49#define PATMFL_SINGLE_INSTRUCTION RT_BIT_64(13)
50#define PATMFL_SYSENTER_XP RT_BIT_64(14)
51#define PATMFL_JUMP_CONFLICT RT_BIT_64(15)
52#define PATMFL_READ_ORIGINAL_BYTES RT_BIT_64(16) /** opcode might have already been patched */
53#define PATMFL_INT3_REPLACEMENT RT_BIT_64(17)
54#define PATMFL_SUPPORT_CALLS RT_BIT_64(18)
55#define PATMFL_SUPPORT_INDIRECT_CALLS RT_BIT_64(19)
56#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT RT_BIT_64(20) /** internal flag to avoid duplicate entrypoints */
57#define PATMFL_INHIBIT_IRQS RT_BIT_64(21) /** temporary internal flag */
58#define PATMFL_GENERATE_JUMPTOGUEST RT_BIT_64(22) /** temporary internal flag */
59#define PATMFL_RECOMPILE_NEXT RT_BIT_64(23) /** for recompilation of the next instruction */
60#define PATMFL_CODE_MONITORED RT_BIT_64(24) /** code pages of guest monitored for self-modifying code. */
61#define PATMFL_CALLABLE_AS_FUNCTION RT_BIT_64(25) /** cli and pushf blocks can be used as callable functions. */
62#define PATMFL_GLOBAL_FUNCTIONS RT_BIT_64(26) /** fake patch for global patm functions. */
63#define PATMFL_TRAMPOLINE RT_BIT_64(27) /** trampoline patch that clears PATM_INTERRUPTFLAG and jumps to patch destination */
64#define PATMFL_GENERATE_SETPIF RT_BIT_64(28) /** generate set PIF for the next instruction */
65#define PATMFL_INSTR_HINT RT_BIT_64(29) /** Generate patch, but don't activate it. */
66#define PATMFL_PATCHED_GUEST_CODE RT_BIT_64(30) /** Patched guest code. */
67#define PATMFL_MUST_INSTALL_PATCHJMP RT_BIT_64(31) /** Need to patch guest code in order to activate patch. */
68#define PATMFL_INT3_REPLACEMENT_BLOCK RT_BIT_64(32) /** int 3 replacement block */
69#define PATMFL_EXTERNAL_JUMP_INSIDE RT_BIT_64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */
70#define PATMFL_CODE_REFERENCED RT_BIT_64(34) /** patch block referenced (called, jumped to) by another patch. */
71
72#define SIZEOF_NEARJUMP8 2 //opcode byte + 1 byte relative offset
73#define SIZEOF_NEARJUMP16 3 //opcode byte + 2 byte relative offset
74#define SIZEOF_NEARJUMP32 5 //opcode byte + 4 byte relative offset
75#define SIZEOF_NEAR_COND_JUMP32 6 //0xF + opcode byte + 4 byte relative offset
76
77#define MAX_INSTR_SIZE 16
78
79/* Patch states */
80#define PATCH_REFUSED 1
81#define PATCH_DISABLED 2
82#define PATCH_ENABLED 4
83#define PATCH_UNUSABLE 8
84#define PATCH_DIRTY 16
85#define PATCH_DISABLE_PENDING 32
86
87
88#define MAX_PATCH_TRAPS 4
89#define PATM_MAX_CALL_DEPTH 32
90/* Maximum nr of writes before a patch is marked dirty. (disabled) */
91#define PATM_MAX_CODE_WRITES 32
92/* Maximum nr of invalid writes before a patch is disabled. */
93#define PATM_MAX_INVALID_WRITES 16384
94
95#define FIXUP_ABSOLUTE 0
96#define FIXUP_REL_JMPTOPATCH 1
97#define FIXUP_REL_JMPTOGUEST 2
98
99#define PATM_ILLEGAL_DESTINATION 0xDEADBEEF
100
101/** Size of the instruction that's used for requests from patch code (currently only call) */
102#define PATM_ILLEGAL_INSTR_SIZE 2
103
104
105/** No statistics counter index allocated just yet */
106#define PATM_STAT_INDEX_NONE (uint32_t)-1
107/** Dummy counter to handle overflows */
108#define PATM_STAT_INDEX_DUMMY 0
109#define PATM_STAT_INDEX_IS_VALID(a) (a != PATM_STAT_INDEX_DUMMY && a != PATM_STAT_INDEX_NONE)
110
111#ifdef VBOX_WITH_STATISTICS
112#define PATM_STAT_RUN_INC(pPatch) \
113 if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx)) \
114 CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32A++;
115#define PATM_STAT_FAULT_INC(pPatch) \
116 if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx)) \
117 CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32B++;
118#else
119#define PATM_STAT_RUN_INC(pPatch) do { } while (0)
120#define PATM_STAT_FAULT_INC(pPatch) do { } while (0)
121#endif
122
123/** Maximum number of stat counters. */
124#define PATM_STAT_MAX_COUNTERS 1024
125/** Size of memory allocated for patch statistics. */
126#define PATM_STAT_MEMSIZE (PATM_STAT_MAX_COUNTERS*sizeof(STAMRATIOU32))
127
128/** aCpus[0].fLocalForcedActions fixup (must be uneven to avoid theoretical clashes with valid pointers) */
129#define PATM_FIXUP_CPU_FF_ACTION 0xffffff01
130/** default cpuid pointer fixup */
131#define PATM_FIXUP_CPUID_DEFAULT 0xffffff03
132/** standard cpuid pointer fixup */
133#define PATM_FIXUP_CPUID_STANDARD 0xffffff05
134/** extended cpuid pointer fixup */
135#define PATM_FIXUP_CPUID_EXTENDED 0xffffff07
136/** centaur cpuid pointer fixup */
137#define PATM_FIXUP_CPUID_CENTAUR 0xffffff09
138
139typedef struct
140{
141 /** The key is a HC virtual address. */
142 AVLPVNODECORE Core;
143
144 uint32_t uType;
145 R3PTRTYPE(uint8_t *) pRelocPos;
146 RTRCPTR pSource;
147 RTRCPTR pDest;
148} RELOCREC, *PRELOCREC;
149
150/* forward decl */
151struct _PATCHINFO;
152
153/* Cache record for guest to host pointer conversions. */
154typedef struct
155{
156 R3PTRTYPE(uint8_t *) pPageLocStartHC;
157 RCPTRTYPE(uint8_t *) pGuestLoc;
158 R3PTRTYPE(void *) pPatch;
159 PGMPAGEMAPLOCK Lock;
160} PATMP2GLOOKUPREC, *PPATMP2GLOOKUPREC;
161
162/* Obsolete; do not use. */
163typedef struct
164{
165 R3PTRTYPE(uint8_t *) pPatchLocStartHC;
166 R3PTRTYPE(uint8_t *) pPatchLocEndHC;
167 RCPTRTYPE(uint8_t *) pGuestLoc;
168 uint32_t opsize;
169} PATMP2GLOOKUPREC_OBSOLETE;
170
171typedef struct
172{
173 /** The key is a pointer to a JUMPREC structure. */
174 AVLPVNODECORE Core;
175
176 R3PTRTYPE(uint8_t *) pJumpHC;
177 RCPTRTYPE(uint8_t *) pTargetGC;
178 uint32_t offDispl;
179 uint32_t opcode;
180} JUMPREC, *PJUMPREC;
181
182/**
183 * Patch to guest lookup type (single or both direction)
184 */
185typedef enum
186{
187 /** patch to guest */
188 PATM_LOOKUP_PATCH2GUEST,
189 /** guest to patch + patch to guest */
190 PATM_LOOKUP_BOTHDIR
191} PATM_LOOKUP_TYPE;
192
193/**
194 * Patch to guest address lookup record.
195 */
196typedef struct RECPATCHTOGUEST
197{
198 /** The key is an offset inside the patch memory block. */
199 AVLU32NODECORE Core;
200 /** GC address of the guest instruction this record is for. */
201 RTRCPTR pOrgInstrGC;
202 /** Patch to guest lookup type. */
203 PATM_LOOKUP_TYPE enmType;
204 /** Flag whether the original instruction was changed by the guest. */
205 bool fDirty;
206 /** Flag whether this guest instruction is a jump target from
207 * a trampoline patch. */
208 bool fJumpTarget;
209 /** Original opcode before writing 0xCC there to mark it dirty. */
210 uint8_t u8DirtyOpcode;
211} RECPATCHTOGUEST, *PRECPATCHTOGUEST;
212
213/**
214 * Guest to patch address lookup record
215 */
216typedef struct RECGUESTTOPATCH
217{
218 /** The key is a GC virtual address. */
219 AVLU32NODECORE Core;
220 /** Patch offset (relative to PATM::pPatchMemGC / PATM::pPatchMemHC). */
221 uint32_t PatchOffset;
222} RECGUESTTOPATCH, *PRECGUESTTOPATCH;
223
224/**
225 * Temporary information used in ring 3 only; no need to waste memory in the patch record itself.
226 */
227typedef struct
228{
229 /* Temporary tree for storing the addresses of illegal instructions. */
230 R3PTRTYPE(PAVLPVNODECORE) IllegalInstrTree;
231 uint32_t nrIllegalInstr;
232
233 int32_t nrJumps;
234 uint32_t nrRetInstr;
235
236 /* Temporary tree of encountered jumps. (debug only) */
237 R3PTRTYPE(PAVLPVNODECORE) DisasmJumpTree;
238
239 int32_t nrCalls;
240
241 /** Last original guest instruction pointer; used for disassembly log. */
242 RTRCPTR pLastDisasmInstrGC;
243
244 /** Keeping track of multiple ret instructions. */
245 RTRCPTR pPatchRetInstrGC;
246 uint32_t uPatchRetParam1;
247} PATCHINFOTEMP, *PPATCHINFOTEMP;
248
249/** Forward declaration for a pointer to a trampoline patch record. */
250typedef struct TRAMPREC *PTRAMPREC;
251
252/**
253 * Patch information.
254 */
255typedef struct _PATCHINFO
256{
257 /** Current patch state (enabled, disabled, etc.). */
258 uint32_t uState;
259 /** Previous patch state. Used when enabling a disabled patch. */
260 uint32_t uOldState;
261 /** CPU mode (16bit or 32bit). */
262 DISCPUMODE uOpMode;
263 /** GC pointer of privileged instruction */
264 RCPTRTYPE(uint8_t *) pPrivInstrGC;
265 /** @todo: Can't remove due to structure size dependencies in saved states. */
266 R3PTRTYPE(uint8_t *) unusedHC;
267 /** Original privileged guest instructions overwritten by the jump patch. */
268 uint8_t aPrivInstr[MAX_INSTR_SIZE];
269 /** Number of valid bytes in the instruction buffer. */
270 uint32_t cbPrivInstr;
271 /** Opcode for priv instr (OP_*). */
272 uint32_t opcode;
273 /** Size of the patch jump in the guest code. */
274 uint32_t cbPatchJump;
275 /* Only valid for PATMFL_JUMP_CONFLICT patches */
276 RTRCPTR pPatchJumpDestGC;
277 /** Offset of the patch code from the beginning of the patch memory area. */
278 RTGCUINTPTR32 pPatchBlockOffset;
279 /** Size of the patch code in bytes. */
280 uint32_t cbPatchBlockSize;
281 /** Current offset of the patch starting from pPatchBlockOffset.
282 * Used during patch creation. */
283 uint32_t uCurPatchOffset;
284#if HC_ARCH_BITS == 64
285 uint32_t Alignment0; /**< Align flags correctly. */
286#endif
287 /** PATM flags (see PATMFL_*). */
288 uint64_t flags;
289 /**
290 * Lowest and highest patched GC instruction address. To optimize searches.
291 */
292 RTRCPTR pInstrGCLowest;
293 RTRCPTR pInstrGCHighest;
294 /* Tree of fixup records for the patch. */
295 R3PTRTYPE(PAVLPVNODECORE) FixupTree;
296 uint32_t nrFixups;
297 /* Tree of jumps inside the generated patch code. */
298 uint32_t nrJumpRecs;
299 R3PTRTYPE(PAVLPVNODECORE) JumpTree;
300 /**
301 * Lookup trees for determining the corresponding guest address of an
302 * instruction in the patch block.
303 */
304 R3PTRTYPE(PAVLU32NODECORE) Patch2GuestAddrTree;
305 R3PTRTYPE(PAVLU32NODECORE) Guest2PatchAddrTree;
306 uint32_t nrPatch2GuestRecs;
307#if HC_ARCH_BITS == 64
308 uint32_t Alignment1;
309#endif
310 /** Unused, but can't remove due to structure size dependencies in the saved state. */
311 PATMP2GLOOKUPREC_OBSOLETE unused;
312 /** Temporary information during patch creation. Don't waste hypervisor memory for this. */
313 R3PTRTYPE(PPATCHINFOTEMP) pTempInfo;
314 /** List of trampoline patches referencing this patch.
315 * Used when refreshing the patch. (Only for function duplicates) */
316 R3PTRTYPE(PTRAMPREC) pTrampolinePatchesHead;
317 /** Count the number of writes to the corresponding guest code. */
318 uint32_t cCodeWrites;
319 /** Some statistics to determine if we should keep this patch activated. */
320 uint32_t cTraps;
321 /** Count the number of invalid writes to pages monitored for the patch. */
322 uint32_t cInvalidWrites;
323 /** Index into the uPatchRun and uPatchTrap arrays (0..MAX_PATCHES-1) */
324 uint32_t uPatchIdx;
325 /** First opcode byte, that's overwritten when a patch is marked dirty. */
326 uint8_t bDirtyOpcode;
327 /** Align the structure size on a 8-byte boundary. */
328 uint8_t Alignment2[HC_ARCH_BITS == 64 ? 7 : 3];
329} PATCHINFO, *PPATCHINFO;
330
331#define PATCHCODE_PTR_GC(pPatch) (RTRCPTR) (pVM->patm.s.pPatchMemGC + (pPatch)->pPatchBlockOffset)
332#define PATCHCODE_PTR_HC(pPatch) (uint8_t *)(pVM->patm.s.pPatchMemHC + (pPatch)->pPatchBlockOffset)
333
334/**
335 * Lookup record for patches
336 */
337typedef struct PATMPATCHREC
338{
339 /** The key is a GC virtual address. */
340 AVLOU32NODECORE Core;
341 /** The key is a patch offset. */
342 AVLOU32NODECORE CoreOffset;
343 /** The patch information. */
344 PATCHINFO patch;
345} PATMPATCHREC, *PPATMPATCHREC;
346
347/**
348 * Record for a trampoline patch.
349 */
350typedef struct TRAMPREC
351{
352 /** Pointer to the next trampoline patch. */
353 struct TRAMPREC *pNext;
354 /** Pointer to the trampoline patch record. */
355 PPATMPATCHREC pPatchTrampoline;
356} TRAMPREC;
357
358/** Increment for allocating room for pointer array */
359#define PATMPATCHPAGE_PREALLOC_INCREMENT 16
360
361/**
362 * Lookup record for patch pages
363 */
364typedef struct PATMPATCHPAGE
365{
366 /** The key is a GC virtual address. */
367 AVLOU32NODECORE Core;
368 /** Region to monitor. */
369 RTRCPTR pLowestAddrGC;
370 RTRCPTR pHighestAddrGC;
371 /** Number of patches for this page. */
372 uint32_t cCount;
373 /** Maximum nr of pointers in the array. */
374 uint32_t cMaxPatches;
375 /** Array of patch pointers for this page. */
376 R3PTRTYPE(PPATCHINFO *) aPatch;
377} PATMPATCHPAGE, *PPATMPATCHPAGE;
378
379#define PATM_PATCHREC_FROM_COREOFFSET(a) (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, CoreOffset))
380#define PATM_PATCHREC_FROM_PATCHINFO(a) (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, patch))
381
382/**
383 * AVL trees used by PATM.
384 */
385typedef struct PATMTREES
386{
387 /**
388 * AVL tree with all patches (active or disabled) sorted by guest instruction address
389 */
390 AVLOU32TREE PatchTree;
391
392 /**
393 * AVL tree with all patches sorted by patch address (offset actually)
394 */
395 AVLOU32TREE PatchTreeByPatchAddr;
396
397 /**
398 * AVL tree with all pages which were (partly) patched
399 */
400 AVLOU32TREE PatchTreeByPage;
401
402 uint32_t align[1];
403} PATMTREES, *PPATMTREES;
404
405/**
406 * PATM VM Instance data.
407 * Changes to this must checked against the padding of the patm union in VM!
408 */
409typedef struct PATM
410{
411 /** Offset to the VM structure.
412 * See PATM2VM(). */
413 RTINT offVM;
414 /** Pointer to the patch memory area (GC) */
415 RCPTRTYPE(uint8_t *) pPatchMemGC;
416 /** Pointer to the patch memory area (HC) */
417 R3PTRTYPE(uint8_t *) pPatchMemHC;
418 /** Size of the patch memory area in bytes. */
419 uint32_t cbPatchMem;
420 /** Relative offset to the next free byte starting from the start of the region. */
421 uint32_t offPatchMem;
422 /** Flag whether PATM ran out of patch memory. */
423 bool fOutOfMemory;
424 /** Delta to the new relocated HMA area.
425 * Used only during PATMR3Relocate(). */
426 int32_t deltaReloc;
427 /* GC PATM state pointer - HC pointer. */
428 R3PTRTYPE(PPATMGCSTATE) pGCStateHC;
429 /* GC PATM state pointer - GC pointer. */
430 RCPTRTYPE(PPATMGCSTATE) pGCStateGC;
431 /** PATM stack page for call instruction execution. (2 parts: one for our private stack and one to store the original return address */
432 RCPTRTYPE(RTRCPTR *) pGCStackGC;
433 /** HC pointer of the PATM stack page. */
434 R3PTRTYPE(RTRCPTR *) pGCStackHC;
435 /** GC pointer to CPUMCTX structure. */
436 RCPTRTYPE(PCPUMCTX) pCPUMCtxGC;
437 /** GC statistics pointer. */
438 RCPTRTYPE(PSTAMRATIOU32) pStatsGC;
439 /** HC statistics pointer. */
440 R3PTRTYPE(PSTAMRATIOU32) pStatsHC;
441 /* Current free index value (uPatchRun/uPatchTrap arrays). */
442 uint32_t uCurrentPatchIdx;
443 /* Temporary counter for patch installation call depth. (in order not to go on forever) */
444 uint32_t ulCallDepth;
445 /** Number of page lookup records. */
446 uint32_t cPageRecords;
447 /** Lowest and highest patched GC instruction addresses. To optimize searches. */
448 RTRCPTR pPatchedInstrGCLowest;
449 RTRCPTR pPatchedInstrGCHighest;
450 /** Pointer to the patch tree for instructions replaced by 'int 3'. */
451 RCPTRTYPE(PPATMTREES) PatchLookupTreeGC;
452 R3PTRTYPE(PPATMTREES) PatchLookupTreeHC;
453 /** Global PATM lookup and call function (used by call patches). */
454 RTRCPTR pfnHelperCallGC;
455 /** Global PATM return function (used by ret patches). */
456 RTRCPTR pfnHelperRetGC;
457 /** Global PATM jump function (used by indirect jmp patches). */
458 RTRCPTR pfnHelperJumpGC;
459 /** Global PATM return function (used by iret patches). */
460 RTRCPTR pfnHelperIretGC;
461 /** Fake patch record for global functions. */
462 R3PTRTYPE(PPATMPATCHREC) pGlobalPatchRec;
463 /** Pointer to original sysenter handler */
464 RTRCPTR pfnSysEnterGC;
465 /** Pointer to sysenter handler trampoline */
466 RTRCPTR pfnSysEnterPatchGC;
467 /** Sysenter patch index (for stats only) */
468 uint32_t uSysEnterPatchIdx;
469 /** GC address of fault in monitored page (set by PATMGCMonitorPage, used by PATMR3HandleMonitoredPage)- */
470 RTRCPTR pvFaultMonitor;
471 /** Temporary information for pending MMIO patch. Set in GC or R0 context. */
472 struct
473 {
474 RTGCPHYS GCPhys;
475 RTRCPTR pCachedData;
476 RTRCPTR Alignment0; /**< Align the structure size on a 8-byte boundary. */
477 } mmio;
478 /** Temporary storage during load/save state */
479 struct
480 {
481 R3PTRTYPE(PSSMHANDLE) pSSM;
482 uint32_t cPatches;
483#if HC_ARCH_BITS == 64
484 uint32_t Alignment0; /**< Align the structure size on a 8-byte boundary. */
485#endif
486 } savedstate;
487
488 STAMCOUNTER StatNrOpcodeRead;
489 STAMCOUNTER StatDisabled;
490 STAMCOUNTER StatUnusable;
491 STAMCOUNTER StatEnabled;
492 STAMCOUNTER StatInstalled;
493 STAMCOUNTER StatInstalledFunctionPatches;
494 STAMCOUNTER StatInstalledTrampoline;
495 STAMCOUNTER StatInstalledJump;
496 STAMCOUNTER StatInt3Callable;
497 STAMCOUNTER StatInt3BlockRun;
498 STAMCOUNTER StatOverwritten;
499 STAMCOUNTER StatFixedConflicts;
500 STAMCOUNTER StatFlushed;
501 STAMCOUNTER StatPageBoundaryCrossed;
502 STAMCOUNTER StatMonitored;
503 STAMPROFILEADV StatHandleTrap;
504 STAMCOUNTER StatSwitchBack;
505 STAMCOUNTER StatSwitchBackFail;
506 STAMCOUNTER StatPATMMemoryUsed;
507 STAMCOUNTER StatDuplicateREQSuccess;
508 STAMCOUNTER StatDuplicateREQFailed;
509 STAMCOUNTER StatDuplicateUseExisting;
510 STAMCOUNTER StatFunctionFound;
511 STAMCOUNTER StatFunctionNotFound;
512 STAMPROFILEADV StatPatchWrite;
513 STAMPROFILEADV StatPatchWriteDetect;
514 STAMCOUNTER StatDirty;
515 STAMCOUNTER StatPushTrap;
516 STAMCOUNTER StatPatchWriteInterpreted;
517 STAMCOUNTER StatPatchWriteInterpretedFailed;
518
519 STAMCOUNTER StatSysEnter;
520 STAMCOUNTER StatSysExit;
521 STAMCOUNTER StatEmulIret;
522 STAMCOUNTER StatEmulIretFailed;
523
524 STAMCOUNTER StatInstrDirty;
525 STAMCOUNTER StatInstrDirtyGood;
526 STAMCOUNTER StatInstrDirtyBad;
527
528 STAMCOUNTER StatPatchPageInserted;
529 STAMCOUNTER StatPatchPageRemoved;
530
531 STAMCOUNTER StatPatchRefreshSuccess;
532 STAMCOUNTER StatPatchRefreshFailed;
533
534 STAMCOUNTER StatGenRet;
535 STAMCOUNTER StatGenRetReused;
536 STAMCOUNTER StatGenJump;
537 STAMCOUNTER StatGenCall;
538 STAMCOUNTER StatGenPopf;
539
540 STAMCOUNTER StatCheckPendingIRQ;
541
542 STAMCOUNTER StatFunctionLookupReplace;
543 STAMCOUNTER StatFunctionLookupInsert;
544 uint32_t StatU32FunctionMaxSlotsUsed;
545 uint32_t Alignment0; /**< Align the structure size on a 8-byte boundary. */
546} PATM, *PPATM;
547
548
549
550DECLCALLBACK(int) patmVirtPageHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
551
552DECLCALLBACK(int) patmR3Save(PVM pVM, PSSMHANDLE pSSM);
553DECLCALLBACK(int) patmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
554
555#ifdef IN_RING3
556RTRCPTR patmPatchGCPtr2GuestGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pPatchGC);
557RTRCPTR patmGuestGCPtrToPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC);
558RTRCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC);
559#endif
560
561/* Add a patch to guest lookup record
562 *
563 * @param pVM The VM to operate on.
564 * @param pPatch Patch structure ptr
565 * @param pPatchInstrHC Guest context pointer to patch block
566 * @param pInstrGC Guest context pointer to privileged instruction
567 * @param enmType Lookup type
568 * @param fDirty Dirty flag
569 *
570 */
571void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty=false);
572
573/**
574 * Insert page records for all guest pages that contain instructions that were recompiled for this patch
575 *
576 * @returns VBox status code.
577 * @param pVM The VM to operate on.
578 * @param pPatch Patch record
579 */
580int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch);
581
582/**
583 * Remove page records for all guest pages that contain instructions that were recompiled for this patch
584 *
585 * @returns VBox status code.
586 * @param pVM The VM to operate on.
587 * @param pPatch Patch record
588 */
589int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch);
590
591/**
592 * Returns the GC address of the corresponding patch statistics counter
593 *
594 * @returns Stat address
595 * @param pVM The VM to operate on.
596 * @param pPatch Patch structure
597 */
598RTRCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch);
599
600/**
601 * Remove patch for privileged instruction at specified location
602 *
603 * @returns VBox status code.
604 * @param pVM The VM to operate on.
605 * @param pPatchRec Patch record
606 * @param fForceRemove Remove *all* patches
607 */
608int PATMRemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove);
609
610/**
611 * Call for analysing the instructions following the privileged instr. for compliance with our heuristics
612 *
613 * @returns VBox status code.
614 * @param pVM The VM to operate on.
615 * @param pCpu CPU disassembly state
616 * @param pInstrHC Guest context pointer to privileged instruction
617 * @param pCurInstrHC Guest context pointer to current instruction
618 * @param pCacheRec Cache record ptr
619 *
620 */
621typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PPATMP2GLOOKUPREC pCacheRec);
622
623/**
624 * Install guest OS specific patch
625 *
626 * @returns VBox status code.
627 * @param pVM The VM to operate on
628 * @param pCpu Disassembly state of instruction.
629 * @param pInstrGC GC Instruction pointer for instruction
630 * @param pInstrHC GC Instruction pointer for instruction
631 * @param pPatchRec Patch structure
632 *
633 */
634int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTRCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);
635
636
637/**
638 * Check if the instruction is patched as a duplicated function
639 *
640 * @returns patch record
641 * @param pVM The VM to operate on.
642 * @param pInstrGC Guest context point to the instruction
643 *
644 */
645VMMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC);
646
647
648/**
649 * Empty the specified tree (PV tree, MMR3 heap)
650 *
651 * @param pVM The VM to operate on.
652 * @param ppTree Tree to empty
653 */
654void patmEmptyTree(PVM pVM, PPAVLPVNODECORE ppTree);
655
656
657/**
658 * Empty the specified tree (U32 tree, MMR3 heap)
659 *
660 * @param pVM The VM to operate on.
661 * @param ppTree Tree to empty
662 */
663void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree);
664
665
666/**
667 * Return the name of the patched instruction
668 *
669 * @returns instruction name
670 *
671 * @param opcode DIS instruction opcode
672 * @param fPatchFlags Patch flags
673 */
674VMMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags);
675
676
677/**
678 * Read callback for disassembly function; supports reading bytes that cross a page boundary
679 *
680 * @returns VBox status code.
681 * @param pSrc GC source pointer
682 * @param pDest HC destination pointer
683 * @param size Number of bytes to read
684 * @param pvUserdata Callback specific user data (pCpu)
685 *
686 */
687int patmReadBytes(RTUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata);
688
689
690#ifndef IN_RC
691
692#define PATMREAD_RAWCODE 1 /* read code as-is */
693#define PATMREAD_ORGCODE 2 /* read original guest opcode bytes; not the patched bytes */
694#define PATMREAD_NOCHECK 4 /* don't check for patch conflicts */
695
696/*
697 * Private structure used during disassembly
698 */
699typedef struct
700{
701 PVM pVM;
702 PPATCHINFO pPatchInfo;
703 R3PTRTYPE(uint8_t *) pInstrHC;
704 RTRCPTR pInstrGC;
705 uint32_t fReadFlags;
706} PATMDISASM, *PPATMDISASM;
707
708inline bool PATMR3DISInstr(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR InstrGC,
709 uint8_t *InstrHC, uint32_t *pOpsize, char *pszOutput,
710 uint32_t fReadFlags = PATMREAD_ORGCODE)
711{
712 PATMDISASM disinfo;
713 disinfo.pVM = pVM;
714 disinfo.pPatchInfo = pPatch;
715 disinfo.pInstrHC = InstrHC;
716 disinfo.pInstrGC = InstrGC;
717 disinfo.fReadFlags = fReadFlags;
718 (pCpu)->pfnReadBytes = patmReadBytes;
719 (pCpu)->apvUserData[0] = &disinfo;
720 return RT_SUCCESS(DISInstr(pCpu, InstrGC, 0, pOpsize, pszOutput));
721}
722#endif /* !IN_RC */
723
724RT_C_DECLS_BEGIN
725/**
726 * #PF Virtual Handler callback for Guest access a page monitored by PATM
727 *
728 * @returns VBox status code (appropriate for trap handling and GC return).
729 * @param pVM VM Handle.
730 * @param uErrorCode CPU Error code.
731 * @param pRegFrame Trap register frame.
732 * @param pvFault The fault address (cr2).
733 * @param pvRange The base address of the handled virtual range.
734 * @param offRange The offset of the access into this range.
735 * (If it's a EIP range this is the EIP, if not it's pvFault.)
736 */
737VMMRCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
738
739/**
740 * Find patch for privileged instruction at specified location
741 *
742 * @returns Patch structure pointer if found; else NULL
743 * @param pVM The VM to operate on.
744 * @param pInstr Guest context point to instruction that might lie within 5 bytes of an existing patch jump
745 * @param fIncludeHints Include hinted patches or not
746 *
747 */
748PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncludeHints=false);
749
750/**
751 * Patch cli/sti pushf/popf instruction block at specified location
752 *
753 * @returns VBox status code.
754 * @param pVM The VM to operate on.
755 * @param pInstrGC Guest context point to privileged instruction
756 * @param pInstrHC Host context point to privileged instruction
757 * @param uOpcode Instruction opcodee
758 * @param uOpSize Size of starting instruction
759 * @param pPatchRec Patch record
760 *
761 * @note returns failure if patching is not allowed or possible
762 *
763 */
764VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC,
765 uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec);
766
767
768/**
769 * Replace an instruction with a breakpoint (0xCC), that is handled dynamically in the guest context.
770 *
771 * @returns VBox status code.
772 * @param pVM The VM to operate on.
773 * @param pInstrGC Guest context point to privileged instruction
774 * @param pInstrHC Host context point to privileged instruction
775 * @param pCpu Disassembly CPU structure ptr
776 * @param pPatch Patch record
777 *
778 * @note returns failure if patching is not allowed or possible
779 *
780 */
781VMMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);
782
783/**
784 * Mark patch as dirty
785 *
786 * @returns VBox status code.
787 * @param pVM The VM to operate on.
788 * @param pPatch Patch record
789 *
790 * @note returns failure if patching is not allowed or possible
791 *
792 */
793VMMR3DECL(int) PATMR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch);
794
795R3PTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr);
796
797/**
798 * Calculate the branch destination
799 *
800 * @returns branch destination or 0 if failed
801 * @param pCpu Disassembly state of instruction.
802 * @param pBranchInstrGC GC pointer of branch instruction
803 */
804inline RTRCPTR PATMResolveBranch(PDISCPUSTATE pCpu, RTRCPTR pBranchInstrGC)
805{
806 uint32_t disp;
807 if (pCpu->param1.flags & USE_IMMEDIATE8_REL)
808 {
809 disp = (int32_t)(char)pCpu->param1.parval;
810 }
811 else
812 if (pCpu->param1.flags & USE_IMMEDIATE16_REL)
813 {
814 disp = (int32_t)(uint16_t)pCpu->param1.parval;
815 }
816 else
817 if (pCpu->param1.flags & USE_IMMEDIATE32_REL)
818 {
819 disp = (int32_t)pCpu->param1.parval;
820 }
821 else
822 {
823 Log(("We don't support far jumps here!! (%08X)\n", pCpu->param1.flags));
824 return 0;
825 }
826#ifdef IN_RC
827 return (RTRCPTR)((uint8_t *)pBranchInstrGC + pCpu->opsize + disp);
828#else
829 return pBranchInstrGC + pCpu->opsize + disp;
830#endif
831}
832
833RT_C_DECLS_END
834
835#ifdef LOG_ENABLED
836int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PPATMP2GLOOKUPREC pCacheRec);
837int patmr3DisasmCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, PPATMP2GLOOKUPREC pCacheRec);
838#endif
839
840#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette