VirtualBox

source: vbox/trunk/src/VBox/VMM/PATM/PATMInternal.h@ 11925

Last change on this file since 11925 was 11925, checked in by vboxsync, 16 years ago

More patm compatibility fixes

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