VirtualBox

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

Last change on this file since 29329 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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