VirtualBox

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

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

Attempt to recreate patches who's dirty instruction(s) we can't correct.
Additional checks for dirty instructions that served as targets for trampoline patches.

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