VirtualBox

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

Last change on this file since 5869 was 5610, checked in by vboxsync, 17 years ago

Fixed boundary checks and support partial instruction updates (e.g. destination address of jmp instruction)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.1 KB
Line 
1/* $Id: PATMInternal.h 5610 2007-11-02 11:10:07Z 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 RT_BIT(11))
44 */
45
46#define PATMFL_CHECK_SIZE RT_BIT_64(11)
47#define PATMFL_FOUND_PATCHEND RT_BIT_64(12)
48#define PATMFL_SINGLE_INSTRUCTION RT_BIT_64(13)
49#define PATMFL_SYSENTER_XP RT_BIT_64(14)
50#define PATMFL_JUMP_CONFLICT RT_BIT_64(15)
51#define PATMFL_READ_ORIGINAL_BYTES RT_BIT_64(16) /** opcode might have already been patched */
52#define PATMFL_INT3_REPLACEMENT RT_BIT_64(17)
53#define PATMFL_SUPPORT_CALLS RT_BIT_64(18)
54#define PATMFL_SUPPORT_INDIRECT_CALLS RT_BIT_64(19)
55#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT RT_BIT_64(20) /** internal flag to avoid duplicate entrypoints */
56#define PATMFL_INHIBIT_IRQS RT_BIT_64(21) /** temporary internal flag */
57#define PATMFL_GENERATE_JUMPTOGUEST RT_BIT_64(22) /** temporary internal flag */
58#define PATMFL_RECOMPILE_NEXT RT_BIT_64(23) /** for recompilation of the next instruction */
59#define PATMFL_CODE_MONITORED RT_BIT_64(24) /** code pages of guest monitored for self-modifying code. */
60#define PATMFL_CALLABLE_AS_FUNCTION RT_BIT_64(25) /** cli and pushf blocks can be used as callable functions. */
61#define PATMFL_GLOBAL_FUNCTIONS RT_BIT_64(26) /** fake patch for global patm functions. */
62#define PATMFL_TRAMPOLINE RT_BIT_64(27) /** trampoline patch that clears PATM_INTERRUPTFLAG and jumps to patch destination */
63#define PATMFL_GENERATE_SETPIF RT_BIT_64(28) /** generate set PIF for the next instruction */
64#define PATMFL_INSTR_HINT RT_BIT_64(29) /** Generate patch, but don't activate it. */
65#define PATMFL_PATCHED_GUEST_CODE RT_BIT_64(30) /** Patched guest code. */
66#define PATMFL_MUST_INSTALL_PATCHJMP RT_BIT_64(31) /** Need to patch guest code in order to activate patch. */
67#define PATMFL_INT3_REPLACEMENT_BLOCK RT_BIT_64(32) /** int 3 replacement block */
68#define PATMFL_EXTERNAL_JUMP_INSIDE RT_BIT_64(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);
526RTGCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t*) pInstrGC);
527#endif
528
529/* Add a patch to guest lookup record
530 *
531 * @param pVM The VM to operate on.
532 * @param pPatch Patch structure ptr
533 * @param pPatchInstrHC Guest context pointer to patch block
534 * @param pInstrGC Guest context pointer to privileged instruction
535 * @param enmType Lookup type
536 * @param fDirty Dirty flag
537 *
538 */
539void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTGCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty=false);
540
541/**
542 * Insert page records for all guest pages that contain instructions that were recompiled for this patch
543 *
544 * @returns VBox status code.
545 * @param pVM The VM to operate on.
546 * @param pPatch Patch record
547 */
548int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch);
549
550/**
551 * Remove page records for all guest pages that contain instructions that were recompiled for this patch
552 *
553 * @returns VBox status code.
554 * @param pVM The VM to operate on.
555 * @param pPatch Patch record
556 */
557int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch);
558
559/**
560 * Returns the GC address of the corresponding patch statistics counter
561 *
562 * @returns Stat address
563 * @param pVM The VM to operate on.
564 * @param pPatch Patch structure
565 */
566RTGCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch);
567
568/**
569 * Remove patch for privileged instruction at specified location
570 *
571 * @returns VBox status code.
572 * @param pVM The VM to operate on.
573 * @param pPatchRec Patch record
574 * @param fForceRemove Remove *all* patches
575 */
576int PATMRemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove);
577
578/**
579 * Call for analysing the instructions following the privileged instr. for compliance with our heuristics
580 *
581 * @returns VBox status code.
582 * @param pVM The VM to operate on.
583 * @param pCpu CPU disassembly state
584 * @param pInstrHC Guest context pointer to privileged instruction
585 * @param pCurInstrHC Guest context pointer to current instruction
586 * @param pUserData User pointer
587 *
588 */
589typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
590
591/**
592 * Install guest OS specific patch
593 *
594 * @returns VBox status code.
595 * @param pVM The VM to operate on
596 * @param pCpu Disassembly state of instruction.
597 * @param pInstrGC GC Instruction pointer for instruction
598 * @param pInstrHC GC Instruction pointer for instruction
599 * @param pPatchRec Patch structure
600 *
601 */
602int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);
603
604/**
605 * Convert guest context address to host context pointer
606 *
607 * @returns VBox status code.
608 * @param pVM The VM to operate on.
609 * @param pPatch Patch block structure pointer
610 * @param pGCPtr Guest context pointer
611 *
612 * @returns Host context pointer or NULL in case of an error
613 *
614 */
615R3PTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t *) pGCPtr);
616
617
618/**
619 * Check if the instruction is patched as a duplicated function
620 *
621 * @returns patch record
622 * @param pVM The VM to operate on.
623 * @param pInstrGC Guest context point to the instruction
624 *
625 */
626PATMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTGCPTR pInstrGC);
627
628
629/**
630 * Empty the specified tree (PV tree, MMR3 heap)
631 *
632 * @param pVM The VM to operate on.
633 * @param ppTree Tree to empty
634 */
635void patmEmptyTree(PVM pVM, PPAVLPVNODECORE ppTree);
636
637
638/**
639 * Empty the specified tree (U32 tree, MMR3 heap)
640 *
641 * @param pVM The VM to operate on.
642 * @param ppTree Tree to empty
643 */
644void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree);
645
646
647/**
648 * Return the name of the patched instruction
649 *
650 * @returns instruction name
651 *
652 * @param opcode DIS instruction opcode
653 * @param fPatchFlags Patch flags
654 */
655PATMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags);
656
657
658/**
659 * Read callback for disassembly function; supports reading bytes that cross a page boundary
660 *
661 * @returns VBox status code.
662 * @param pSrc GC source pointer
663 * @param pDest HC destination pointer
664 * @param size Number of bytes to read
665 * @param pvUserdata Callback specific user data (pCpu)
666 *
667 */
668int patmReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata);
669
670
671#ifndef IN_GC
672
673#define PATMREAD_RAWCODE 1 /* read code as-is */
674#define PATMREAD_ORGCODE 2 /* read original guest opcode bytes; not the patched bytes */
675#define PATMREAD_NOCHECK 4 /* don't check for patch conflicts */
676
677/*
678 * Private structure used during disassembly
679 */
680typedef struct
681{
682 PVM pVM;
683 PPATCHINFO pPatchInfo;
684 R3PTRTYPE(uint8_t *) pInstrHC;
685 RTGCPTR pInstrGC;
686 uint32_t fReadFlags;
687} PATMDISASM, *PPATMDISASM;
688
689inline bool PATMR3DISInstr(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTGCPTR InstrGC,
690 uint8_t *InstrHC, uint32_t *pOpsize, char *pszOutput,
691 uint32_t fReadFlags = PATMREAD_ORGCODE)
692{
693 PATMDISASM disinfo;
694 disinfo.pVM = pVM;
695 disinfo.pPatchInfo = pPatch;
696 disinfo.pInstrHC = InstrHC;
697 disinfo.pInstrGC = InstrGC;
698 disinfo.fReadFlags = fReadFlags;
699 (pCpu)->pfnReadBytes = patmReadBytes;
700 (pCpu)->apvUserData[0] = &disinfo;
701 return VBOX_SUCCESS(DISInstr(pCpu, InstrGC, 0, pOpsize, pszOutput));
702}
703#endif /* !IN_GC */
704
705__BEGIN_DECLS
706/**
707 * #PF Virtual Handler callback for Guest access a page monitored by PATM
708 *
709 * @returns VBox status code (appropritate for trap handling and GC return).
710 * @param pVM VM Handle.
711 * @param uErrorCode CPU Error code.
712 * @param pRegFrame Trap register frame.
713 * @param pvFault The fault address (cr2).
714 * @param pvRange The base address of the handled virtual range.
715 * @param offRange The offset of the access into this range.
716 * (If it's a EIP range this's the EIP, if not it's pvFault.)
717 */
718PATMGCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, void *pvRange, uintptr_t offRange);
719
720/**
721 * Find patch for privileged instruction at specified location
722 *
723 * @returns Patch structure pointer if found; else NULL
724 * @param pVM The VM to operate on.
725 * @param pInstr Guest context point to instruction that might lie within 5 bytes of an existing patch jump
726 * @param fIncludeHints Include hinted patches or not
727 *
728 */
729PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTGCPTR pInstrGC, bool fIncludeHints=false);
730
731/**
732 * Patch cli/sti pushf/popf instruction block at specified location
733 *
734 * @returns VBox status code.
735 * @param pVM The VM to operate on.
736 * @param pInstrGC Guest context point to privileged instruction
737 * @param pInstrHC Host context point to privileged instruction
738 * @param uOpcode Instruction opcodee
739 * @param uOpSize Size of starting instruction
740 * @param pPatchRec Patch record
741 *
742 * @note returns failure if patching is not allowed or possible
743 *
744 */
745PATMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTGCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC,
746 uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec);
747
748
749/**
750 * Replace an instruction with a breakpoint (0xCC), that is handled dynamically in the guest context.
751 *
752 * @returns VBox status code.
753 * @param pVM The VM to operate on.
754 * @param pInstrGC Guest context point to privileged instruction
755 * @param pInstrHC Host context point to privileged instruction
756 * @param pCpu Disassembly CPU structure ptr
757 * @param pPatch Patch record
758 *
759 * @note returns failure if patching is not allowed or possible
760 *
761 */
762PATMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTGCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);
763
764/**
765 * Mark patch as dirty
766 *
767 * @returns VBox status code.
768 * @param pVM The VM to operate on.
769 * @param pPatch Patch record
770 *
771 * @note returns failure if patching is not allowed or possible
772 *
773 */
774PATMR3DECL(int) PATMR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch);
775
776/**
777 * Calculate the branch destination
778 *
779 * @returns branch destination or 0 if failed
780 * @param pCpu Disassembly state of instruction.
781 * @param pBranchInstrGC GC pointer of branch instruction
782 */
783inline RTGCPTR PATMResolveBranch(PDISCPUSTATE pCpu, RTGCPTR pBranchInstrGC)
784{
785 uint32_t disp;
786 if (pCpu->param1.flags & USE_IMMEDIATE8_REL)
787 {
788 disp = (int32_t)(char)pCpu->param1.parval;
789 }
790 else
791 if (pCpu->param1.flags & USE_IMMEDIATE16_REL)
792 {
793 disp = (int32_t)(uint16_t)pCpu->param1.parval;
794 }
795 else
796 if (pCpu->param1.flags & USE_IMMEDIATE32_REL)
797 {
798 disp = (int32_t)pCpu->param1.parval;
799 }
800 else
801 {
802 Log(("We don't support far jumps here!! (%08X)\n", pCpu->param1.flags));
803 return 0;
804 }
805#ifdef IN_GC
806 return (RTGCPTR)((uint8_t *)pBranchInstrGC + pCpu->opsize + disp);
807#else
808 return pBranchInstrGC + pCpu->opsize + disp;
809#endif
810}
811
812__END_DECLS
813
814#ifdef DEBUG
815int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
816int patmr3DisasmCodeStream(PVM pVM, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, void *pUserData);
817#endif
818
819#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