VirtualBox

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

最後變更 在這個檔案從23099是 23099,由 vboxsync 提交於 16 年 前

PATM: implemented couple tweaks to make NetBSD bootable (still some spurious segfaults)

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

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