VirtualBox

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

Last change on this file since 5458 was 4953, checked in by vboxsync, 17 years ago

Cleaned up disassembler

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