VirtualBox

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

Last change on this file since 1237 was 1125, checked in by vboxsync, 18 years ago

Forward iret to V86 code to our trap handler for emulation.

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