1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
|
/* $Id: PATMInternal.h $ */
/** @file
* PATM - Internal header file.
*/
/*
* Copyright (C) 2006-2019 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef VMM_INCLUDED_SRC_include_PATMInternal_h
#define VMM_INCLUDED_SRC_include_PATMInternal_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/vmm/patm.h>
#include <VBox/vmm/stam.h>
#include <VBox/dis.h>
#include <VBox/vmm/pgm.h>
#include <iprt/avl.h>
#include <iprt/param.h>
#include <VBox/log.h>
/** @name Saved state version numbers.
* @{ */
/** New concept of helper code (for CPUID). */
#define PATM_SAVED_STATE_VERSION 58
/** New fixup type FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL. */
#define PATM_SAVED_STATE_VERSION_FORGET_THIS_ONE 57
/** Uses normal structure serialization with markers and everything. */
#define PATM_SAVED_STATE_VERSION_NO_RAW_MEM 56
/** Last version which saves structures as raw memory. */
#define PATM_SAVED_STATE_VERSION_MEM 55
#define PATM_SAVED_STATE_VERSION_FIXUP_HACK 54
#define PATM_SAVED_STATE_VERSION_FIXUP_HACK 54
#define PATM_SAVED_STATE_VERSION_VER16 53
/** @} */
/* Enable for call patching. */
#define PATM_ENABLE_CALL
#define PATCH_MEMORY_SIZE (2*1024*1024)
#define MAX_PATCH_SIZE (1024*4)
/*
* Internal patch type flags (starts at RT_BIT(11))
*/
#define PATMFL_CHECK_SIZE RT_BIT_64(11)
#define PATMFL_FOUND_PATCHEND RT_BIT_64(12)
#define PATMFL_SINGLE_INSTRUCTION RT_BIT_64(13)
#define PATMFL_SYSENTER_XP RT_BIT_64(14)
#define PATMFL_JUMP_CONFLICT RT_BIT_64(15)
#define PATMFL_READ_ORIGINAL_BYTES RT_BIT_64(16) /** opcode might have already been patched */
#define PATMFL_INT3_REPLACEMENT RT_BIT_64(17)
#define PATMFL_SUPPORT_CALLS RT_BIT_64(18)
#define PATMFL_SUPPORT_INDIRECT_CALLS RT_BIT_64(19)
#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT RT_BIT_64(20) /** internal flag to avoid duplicate entrypoints */
#define PATMFL_INHIBIT_IRQS RT_BIT_64(21) /** temporary internal flag */
#define PATMFL_GENERATE_JUMPTOGUEST RT_BIT_64(22) /** temporary internal flag */
#define PATMFL_RECOMPILE_NEXT RT_BIT_64(23) /** for recompilation of the next instruction */
#define PATMFL_CODE_MONITORED RT_BIT_64(24) /** code pages of guest monitored for self-modifying code. */
#define PATMFL_CALLABLE_AS_FUNCTION RT_BIT_64(25) /** cli and pushf blocks can be used as callable functions. */
#define PATMFL_GLOBAL_FUNCTIONS RT_BIT_64(26) /** fake patch for global patm functions. */
#define PATMFL_TRAMPOLINE RT_BIT_64(27) /** trampoline patch that clears PATM_ASMFIX_INTERRUPTFLAG and jumps to patch destination */
#define PATMFL_GENERATE_SETPIF RT_BIT_64(28) /** generate set PIF for the next instruction */
#define PATMFL_INSTR_HINT RT_BIT_64(29) /** Generate patch, but don't activate it. */
#define PATMFL_PATCHED_GUEST_CODE RT_BIT_64(30) /** Patched guest code. */
#define PATMFL_MUST_INSTALL_PATCHJMP RT_BIT_64(31) /** Need to patch guest code in order to activate patch. */
#define PATMFL_INT3_REPLACEMENT_BLOCK RT_BIT_64(32) /** int 3 replacement block */
#define PATMFL_EXTERNAL_JUMP_INSIDE RT_BIT_64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */
#define PATMFL_CODE_REFERENCED RT_BIT_64(34) /** patch block referenced (called, jumped to) by another patch. */
#define SIZEOF_NEARJUMP8 2 //opcode byte + 1 byte relative offset
#define SIZEOF_NEARJUMP16 3 //opcode byte + 2 byte relative offset
#define SIZEOF_NEARJUMP32 5 //opcode byte + 4 byte relative offset
#define SIZEOF_NEAR_COND_JUMP32 6 //0xF + opcode byte + 4 byte relative offset
#define MAX_INSTR_SIZE 16
/* Patch states */
#define PATCH_REFUSED 1
#define PATCH_DISABLED 2
#define PATCH_ENABLED 4
#define PATCH_UNUSABLE 8
#define PATCH_DIRTY 16
#define PATCH_DISABLE_PENDING 32
#define MAX_PATCH_TRAPS 4
#define PATM_MAX_CALL_DEPTH 32
/* Maximum nr of writes before a patch is marked dirty. (disabled) */
#define PATM_MAX_CODE_WRITES 32
/* Maximum nr of invalid writes before a patch is disabled. */
#define PATM_MAX_INVALID_WRITES 16384
/** @name FIXUP_XXX - RELOCREC::uType values.
* @{ */
/** Absolute fixup. With one exception (MMIO cache), this does not take any
* source or destination. @sa FIXUP_ABSOLUTE_ASM. */
#define FIXUP_ABSOLUTE 0
#define FIXUP_REL_JMPTOPATCH 1
#define FIXUP_REL_JMPTOGUEST 2
/** Absolute fixup in patch assembly code template.
*
* The source and desination addresses both set to the patch fixup type (see
* PATM_IS_ASMFIX and friends in PATMA.h). This is recent addition (CPUID
* subleaf code), so when loading older saved states this is usally represented
* as FIXUP_ABSOLUTE. */
#define FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL 3
/** Constant value that only needs fixing up when loading state. Structure
* size, member offset, or similar. The source and destination address are set
* like for FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL. */
#define FIXUP_CONSTANT_IN_PATCH_ASM_TMPL 4
/** Relative call to a patch helper routine in VMMRC. The source and destination
* address are set like for FIXUP_ABSOLUTE_IN_PATCH_ASM_TMPL. */
#define FIXUP_REL_HELPER_IN_PATCH_ASM_TMPL 5
/** @} */
#define PATM_ILLEGAL_DESTINATION 0xDEADBEEF
/** Size of the instruction that's used for requests from patch code (currently only call) */
#define PATM_ILLEGAL_INSTR_SIZE 2
/** No statistics counter index allocated just yet */
#define PATM_STAT_INDEX_NONE (uint32_t)-1
/** Dummy counter to handle overflows */
#define PATM_STAT_INDEX_DUMMY 0
#define PATM_STAT_INDEX_IS_VALID(a) (a != PATM_STAT_INDEX_DUMMY && a != PATM_STAT_INDEX_NONE)
#ifdef VBOX_WITH_STATISTICS
#define PATM_STAT_RUN_INC(pPatch) \
if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx)) \
CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32A++;
#define PATM_STAT_FAULT_INC(pPatch) \
if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx)) \
CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32B++;
#else
#define PATM_STAT_RUN_INC(pPatch) do { } while (0)
#define PATM_STAT_FAULT_INC(pPatch) do { } while (0)
#endif
/** Maximum number of stat counters. */
#define PATM_STAT_MAX_COUNTERS 1024
/** Size of memory allocated for patch statistics. */
#define PATM_STAT_MEMSIZE (PATM_STAT_MAX_COUNTERS*sizeof(STAMRATIOU32))
/** aCpus[0].fLocalForcedActions fixup (must be uneven to avoid theoretical clashes with valid pointers) */
#define PATM_FIXUP_CPU_FF_ACTION 0xffffff01
/** default cpuid pointer fixup */
#define PATM_FIXUP_CPUID_DEFAULT 0xffffff03
/** standard cpuid pointer fixup */
#define PATM_FIXUP_CPUID_STANDARD 0xffffff05
/** extended cpuid pointer fixup */
#define PATM_FIXUP_CPUID_EXTENDED 0xffffff07
/** centaur cpuid pointer fixup */
#define PATM_FIXUP_CPUID_CENTAUR 0xffffff09
typedef struct
{
/** The key is a HC virtual address. */
AVLPVNODECORE Core;
uint32_t uType;
R3PTRTYPE(uint8_t *) pRelocPos;
RTRCPTR pSource;
RTRCPTR pDest;
} RELOCREC, *PRELOCREC;
/* Cache record for guest to host pointer conversions. */
typedef struct
{
R3PTRTYPE(uint8_t *) pPageLocStartHC;
RCPTRTYPE(uint8_t *) pGuestLoc;
R3PTRTYPE(void *) pPatch;
PGMPAGEMAPLOCK Lock;
} PATMP2GLOOKUPREC, *PPATMP2GLOOKUPREC;
/* Obsolete; do not use. */
typedef struct
{
R3PTRTYPE(uint8_t *) pPatchLocStartHC;
R3PTRTYPE(uint8_t *) pPatchLocEndHC;
RCPTRTYPE(uint8_t *) pGuestLoc;
uint32_t opsize;
} PATMP2GLOOKUPREC_OBSOLETE;
typedef struct
{
/** The key is a pointer to a JUMPREC structure. */
AVLPVNODECORE Core;
R3PTRTYPE(uint8_t *) pJumpHC;
RCPTRTYPE(uint8_t *) pTargetGC;
uint32_t offDispl;
uint32_t opcode;
} JUMPREC, *PJUMPREC;
/**
* Patch to guest lookup type (single or both direction)
*/
typedef enum
{
/** patch to guest */
PATM_LOOKUP_PATCH2GUEST,
/** guest to patch + patch to guest */
PATM_LOOKUP_BOTHDIR
} PATM_LOOKUP_TYPE;
/**
* Patch to guest address lookup record.
*/
typedef struct RECPATCHTOGUEST
{
/** The key is an offset inside the patch memory block. */
AVLU32NODECORE Core;
/** GC address of the guest instruction this record is for. */
RTRCPTR pOrgInstrGC;
/** Patch to guest lookup type. */
PATM_LOOKUP_TYPE enmType;
/** Flag whether the original instruction was changed by the guest. */
bool fDirty;
/** Flag whether this guest instruction is a jump target from
* a trampoline patch. */
bool fJumpTarget;
/** Original opcode before writing 0xCC there to mark it dirty. */
uint8_t u8DirtyOpcode;
} RECPATCHTOGUEST, *PRECPATCHTOGUEST;
/**
* Guest to patch address lookup record
*/
typedef struct RECGUESTTOPATCH
{
/** The key is a GC virtual address. */
AVLU32NODECORE Core;
/** Patch offset (relative to PATM::pPatchMemGC / PATM::pPatchMemHC). */
uint32_t PatchOffset;
} RECGUESTTOPATCH, *PRECGUESTTOPATCH;
/**
* Temporary information used in ring 3 only; no need to waste memory in the patch record itself.
*/
typedef struct
{
/* Temporary tree for storing the addresses of illegal instructions. */
R3PTRTYPE(PAVLPVNODECORE) IllegalInstrTree;
uint32_t nrIllegalInstr;
int32_t nrJumps;
uint32_t nrRetInstr;
/* Temporary tree of encountered jumps. (debug only) */
R3PTRTYPE(PAVLPVNODECORE) DisasmJumpTree;
int32_t nrCalls;
/** Last original guest instruction pointer; used for disassembly log. */
RTRCPTR pLastDisasmInstrGC;
/** Keeping track of multiple ret instructions. */
RTRCPTR pPatchRetInstrGC;
uint32_t uPatchRetParam1;
} PATCHINFOTEMP, *PPATCHINFOTEMP;
/** Forward declaration for a pointer to a trampoline patch record. */
typedef struct TRAMPREC *PTRAMPREC;
/**
* Patch information.
*/
typedef struct PATCHINFO
{
/** Current patch state (enabled, disabled, etc.). */
uint32_t uState;
/** Previous patch state. Used when enabling a disabled patch. */
uint32_t uOldState;
/** CPU mode (16bit or 32bit). */
DISCPUMODE uOpMode;
/** GC pointer of privileged instruction */
RCPTRTYPE(uint8_t *) pPrivInstrGC;
/** @todo: Can't remove due to structure size dependencies in saved states. */
R3PTRTYPE(uint8_t *) unusedHC;
/** Original privileged guest instructions overwritten by the jump patch. */
uint8_t aPrivInstr[MAX_INSTR_SIZE];
/** Number of valid bytes in the instruction buffer. */
uint32_t cbPrivInstr;
/** Opcode for priv instr (OP_*). */
uint32_t opcode;
/** Size of the patch jump in the guest code. */
uint32_t cbPatchJump;
/** Only valid for PATMFL_JUMP_CONFLICT patches */
RTRCPTR pPatchJumpDestGC;
/** Offset of the patch code from the beginning of the patch memory area. */
RTGCUINTPTR32 pPatchBlockOffset;
/** Size of the patch code in bytes. */
uint32_t cbPatchBlockSize;
/** Current offset of the patch starting from pPatchBlockOffset.
* Used during patch creation. */
uint32_t uCurPatchOffset;
#if HC_ARCH_BITS == 64
uint32_t Alignment0; /**< Align flags correctly. */
#endif
/** PATM flags (see PATMFL_*). */
uint64_t flags;
/**
* Lowest and highest patched GC instruction address. To optimize searches.
*/
RTRCPTR pInstrGCLowest;
RTRCPTR pInstrGCHighest;
/* Tree of fixup records for the patch. */
R3PTRTYPE(PAVLPVNODECORE) FixupTree;
uint32_t nrFixups;
/* Tree of jumps inside the generated patch code. */
uint32_t nrJumpRecs;
R3PTRTYPE(PAVLPVNODECORE) JumpTree;
/**
* Lookup trees for determining the corresponding guest address of an
* instruction in the patch block.
*/
R3PTRTYPE(PAVLU32NODECORE) Patch2GuestAddrTree;
R3PTRTYPE(PAVLU32NODECORE) Guest2PatchAddrTree;
uint32_t nrPatch2GuestRecs;
#if HC_ARCH_BITS == 64
uint32_t Alignment1;
#endif
/** Unused, but can't remove due to structure size dependencies in the saved state. */
PATMP2GLOOKUPREC_OBSOLETE unused;
/** Temporary information during patch creation. Don't waste hypervisor memory for this. */
R3PTRTYPE(PPATCHINFOTEMP) pTempInfo;
/** List of trampoline patches referencing this patch.
* Used when refreshing the patch. (Only for function duplicates) */
R3PTRTYPE(PTRAMPREC) pTrampolinePatchesHead;
/** Count the number of writes to the corresponding guest code. */
uint32_t cCodeWrites;
/** Some statistics to determine if we should keep this patch activated. */
uint32_t cTraps;
/** Count the number of invalid writes to pages monitored for the patch. */
uint32_t cInvalidWrites;
/** Index into the uPatchRun and uPatchTrap arrays (0..MAX_PATCHES-1) */
uint32_t uPatchIdx;
/** First opcode byte, that's overwritten when a patch is marked dirty. */
uint8_t bDirtyOpcode;
/** Align the structure size on a 8-byte boundary. */
uint8_t Alignment2[HC_ARCH_BITS == 64 ? 7 : 3];
} PATCHINFO, *PPATCHINFO;
#define PATCHCODE_PTR_GC(pPatch) (RTRCPTR) (pVM->patm.s.pPatchMemGC + (pPatch)->pPatchBlockOffset)
#define PATCHCODE_PTR_HC(pPatch) (uint8_t *)(pVM->patm.s.pPatchMemHC + (pPatch)->pPatchBlockOffset)
/**
* Lookup record for patches
*/
typedef struct PATMPATCHREC
{
/** The key is a GC virtual address. */
AVLOU32NODECORE Core;
/** The key is a patch offset. */
AVLOU32NODECORE CoreOffset;
/** The patch information. */
PATCHINFO patch;
} PATMPATCHREC, *PPATMPATCHREC;
/**
* Record for a trampoline patch.
*/
typedef struct TRAMPREC
{
/** Pointer to the next trampoline patch. */
struct TRAMPREC *pNext;
/** Pointer to the trampoline patch record. */
PPATMPATCHREC pPatchTrampoline;
} TRAMPREC;
/** Increment for allocating room for pointer array */
#define PATMPATCHPAGE_PREALLOC_INCREMENT 16
/**
* Lookup record for patch pages
*/
typedef struct PATMPATCHPAGE
{
/** The key is a GC virtual address. */
AVLOU32NODECORE Core;
/** Region to monitor. */
RTRCPTR pLowestAddrGC;
RTRCPTR pHighestAddrGC;
/** Number of patches for this page. */
uint32_t cCount;
/** Maximum nr of pointers in the array. */
uint32_t cMaxPatches;
/** Array of patch pointers for this page. */
R3PTRTYPE(PPATCHINFO *) papPatch;
} PATMPATCHPAGE, *PPATMPATCHPAGE;
#define PATM_PATCHREC_FROM_COREOFFSET(a) (PPATMPATCHREC)((uintptr_t)a - RT_UOFFSETOF(PATMPATCHREC, CoreOffset))
#define PATM_PATCHREC_FROM_PATCHINFO(a) (PPATMPATCHREC)((uintptr_t)a - RT_UOFFSETOF(PATMPATCHREC, patch))
/**
* AVL trees used by PATM.
*/
typedef struct PATMTREES
{
/**
* AVL tree with all patches (active or disabled) sorted by guest instruction address
*/
AVLOU32TREE PatchTree;
/**
* AVL tree with all patches sorted by patch address (offset actually)
*/
AVLOU32TREE PatchTreeByPatchAddr;
/**
* AVL tree with all pages which were (partly) patched
*/
AVLOU32TREE PatchTreeByPage;
uint32_t align[1];
} PATMTREES, *PPATMTREES;
/**
* PATM VM Instance data.
* Changes to this must checked against the padding of the patm union in VM!
*/
typedef struct PATM
{
/** Offset to the VM structure.
* See PATM2VM(). */
RTINT offVM;
/** Pointer to the patch memory area (GC) */
RCPTRTYPE(uint8_t *) pPatchMemGC;
/** Pointer to the patch memory area (HC) */
R3PTRTYPE(uint8_t *) pPatchMemHC;
/** Size of the patch memory area in bytes. */
uint32_t cbPatchMem;
/** Relative offset to the next free byte starting from the start of the region. */
uint32_t offPatchMem;
/** Flag whether PATM ran out of patch memory. */
bool fOutOfMemory;
/** Delta to the new relocated HMA area.
* Used only during PATMR3Relocate(). */
int32_t deltaReloc;
/** The ring-3 address of the PatchHlp segment (for PATMReadPatchCode). */
R3PTRTYPE(uint8_t *) pbPatchHelpersR3;
/** The raw-mode address of the PatchHlp segment. */
RCPTRTYPE(uint8_t *) pbPatchHelpersRC;
/** Size of the PatchHlp segment containing the callable helper code. */
uint32_t cbPatchHelpers;
/** GC PATM state pointer - HC pointer. */
R3PTRTYPE(PPATMGCSTATE) pGCStateHC;
/** GC PATM state pointer - RC pointer. */
RCPTRTYPE(PPATMGCSTATE) pGCStateGC;
/** PATM stack page for call instruction execution.
* 2 parts: one for our private stack and one to store the original return
* address. */
RCPTRTYPE(RTRCPTR *) pGCStackGC;
/** HC pointer of the PATM stack page. */
R3PTRTYPE(RTRCPTR *) pGCStackHC;
/** GC pointer to CPUMCTX structure. */
RCPTRTYPE(PCPUMCTX) pCPUMCtxGC;
/** GC statistics pointer. */
RCPTRTYPE(PSTAMRATIOU32) pStatsGC;
/** HC statistics pointer. */
R3PTRTYPE(PSTAMRATIOU32) pStatsHC;
/** Current free index value (uPatchRun/uPatchTrap arrays). */
uint32_t uCurrentPatchIdx;
/** Temporary counter for patch installation call depth. (in order not to go on forever) */
uint32_t ulCallDepth;
/** Number of page lookup records. */
uint32_t cPageRecords;
/** Lowest and highest patched GC instruction addresses. To optimize searches. */
RTRCPTR pPatchedInstrGCLowest;
RTRCPTR pPatchedInstrGCHighest;
/** Pointer to the patch tree for instructions replaced by 'int 3'. */
RCPTRTYPE(PPATMTREES) PatchLookupTreeGC;
R3PTRTYPE(PPATMTREES) PatchLookupTreeHC;
/** Global PATM lookup and call function (used by call patches). */
RTRCPTR pfnHelperCallGC;
/** Global PATM return function (used by ret patches). */
RTRCPTR pfnHelperRetGC;
/** Global PATM jump function (used by indirect jmp patches). */
RTRCPTR pfnHelperJumpGC;
/** Global PATM return function (used by iret patches). */
RTRCPTR pfnHelperIretGC;
/** Fake patch record for global functions. */
R3PTRTYPE(PPATMPATCHREC) pGlobalPatchRec;
/** Pointer to original sysenter handler */
RTRCPTR pfnSysEnterGC;
/** Pointer to sysenter handler trampoline */
RTRCPTR pfnSysEnterPatchGC;
/** Sysenter patch index (for stats only) */
uint32_t uSysEnterPatchIdx;
/** GC address of fault in monitored page (set by PATMGCMonitorPage, used by PATMR3HandleMonitoredPage)- */
RTRCPTR pvFaultMonitor;
/** Temporary information for pending MMIO patch. Set in GC or R0 context. */
struct
{
RTGCPHYS GCPhys;
RTRCPTR pCachedData;
RTRCPTR Alignment0; /**< Align the structure size on a 8-byte boundary. */
} mmio;
/** Temporary storage during load/save state */
struct
{
R3PTRTYPE(PSSMHANDLE) pSSM;
uint32_t cPatches;
#if HC_ARCH_BITS == 64
uint32_t Alignment0; /**< Align the structure size on a 8-byte boundary. */
#endif
} savedstate;
/** Debug module for the patch memory. */
RTDBGMOD hDbgModPatchMem;
/** Virtual page access handler type (patmVirtPageHandler,
* PATMGCMonitorPage). */
PGMVIRTHANDLERTYPE hMonitorPageType;
/** Align statistics on a 8 byte boundary. */
uint32_t u32Alignment1;
STAMCOUNTER StatNrOpcodeRead;
STAMCOUNTER StatDisabled;
STAMCOUNTER StatUnusable;
STAMCOUNTER StatEnabled;
STAMCOUNTER StatInstalled;
STAMCOUNTER StatInstalledFunctionPatches;
STAMCOUNTER StatInstalledTrampoline;
STAMCOUNTER StatInstalledJump;
STAMCOUNTER StatInt3Callable;
STAMCOUNTER StatInt3BlockRun;
STAMCOUNTER StatOverwritten;
STAMCOUNTER StatFixedConflicts;
STAMCOUNTER StatFlushed;
STAMCOUNTER StatPageBoundaryCrossed;
STAMCOUNTER StatMonitored;
STAMPROFILEADV StatHandleTrap;
STAMCOUNTER StatSwitchBack;
STAMCOUNTER StatSwitchBackFail;
STAMCOUNTER StatPATMMemoryUsed;
STAMCOUNTER StatDuplicateREQSuccess;
STAMCOUNTER StatDuplicateREQFailed;
STAMCOUNTER StatDuplicateUseExisting;
STAMCOUNTER StatFunctionFound;
STAMCOUNTER StatFunctionNotFound;
STAMPROFILEADV StatPatchWrite;
STAMPROFILEADV StatPatchWriteDetect;
STAMCOUNTER StatDirty;
STAMCOUNTER StatPushTrap;
STAMCOUNTER StatPatchWriteInterpreted;
STAMCOUNTER StatPatchWriteInterpretedFailed;
STAMCOUNTER StatSysEnter;
STAMCOUNTER StatSysExit;
STAMCOUNTER StatEmulIret;
STAMCOUNTER StatEmulIretFailed;
STAMCOUNTER StatInstrDirty;
STAMCOUNTER StatInstrDirtyGood;
STAMCOUNTER StatInstrDirtyBad;
STAMCOUNTER StatPatchPageInserted;
STAMCOUNTER StatPatchPageRemoved;
STAMCOUNTER StatPatchRefreshSuccess;
STAMCOUNTER StatPatchRefreshFailed;
STAMCOUNTER StatGenRet;
STAMCOUNTER StatGenRetReused;
STAMCOUNTER StatGenJump;
STAMCOUNTER StatGenCall;
STAMCOUNTER StatGenPopf;
STAMCOUNTER StatCheckPendingIRQ;
STAMCOUNTER StatFunctionLookupReplace;
STAMCOUNTER StatFunctionLookupInsert;
uint32_t StatU32FunctionMaxSlotsUsed;
uint32_t Alignment0; /**< Align the structure size on a 8-byte boundary. */
} PATM, *PPATM;
DECLCALLBACK(int) patmR3Save(PVM pVM, PSSMHANDLE pSSM);
DECLCALLBACK(int) patmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
#ifdef IN_RING3
RTRCPTR patmPatchGCPtr2GuestGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pPatchGC);
RTRCPTR patmGuestGCPtrToPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC);
RTRCPTR patmGuestGCPtrToClosestPatchGCPtr(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t*) pInstrGC);
#endif
void patmR3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC,
PATM_LOOKUP_TYPE enmType, bool fDirty = false);
int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch);
RTRCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch);
int patmR3RemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove);
/**
* Call for analysing the instructions following the privileged instr. for compliance with our heuristics
*
* @returns VBox status code.
* @param pVM The cross context VM structure.
* @param pCpu CPU disassembly state
* @param pInstrHC Guest context pointer to privileged instruction
* @param pCurInstrHC Guest context pointer to current instruction
* @param pCacheRec Cache record ptr
*
*/
typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PPATMP2GLOOKUPREC pCacheRec);
int patmR3InstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTRCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);
PPATMPATCHREC patmQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC);
const char *patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags);
PPATCHINFO patmFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncludeHints = false);
int patmR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);
int patmAddBranchToLookupCache(PVM pVM, RTRCPTR pJumpTableGC, RTRCPTR pBranchTarget, RTRCUINTPTR pRelBranchPatch);
R3PTRTYPE(uint8_t *) patmR3GCVirtToHCVirt(PVM pVM, PPATMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr);
RT_C_DECLS_BEGIN
DECLEXPORT(FNPGMRCVIRTPFHANDLER) patmRCVirtPagePfHandler;
RT_C_DECLS_END
/**
* Calculate the branch destination
*
* @returns branch destination or 0 if failed
* @param pCpu Disassembly state of instruction.
* @param pBranchInstrGC GC pointer of branch instruction
*/
DECLINLINE(RTRCPTR) PATMResolveBranch(PDISCPUSTATE pCpu, RTRCPTR pBranchInstrGC)
{
uint32_t disp;
if (pCpu->Param1.fUse & DISUSE_IMMEDIATE8_REL)
{
disp = (int32_t)(char)pCpu->Param1.uValue;
}
else
if (pCpu->Param1.fUse & DISUSE_IMMEDIATE16_REL)
{
disp = (int32_t)(uint16_t)pCpu->Param1.uValue;
}
else
if (pCpu->Param1.fUse & DISUSE_IMMEDIATE32_REL)
{
disp = (int32_t)pCpu->Param1.uValue;
}
else
{
Log(("We don't support far jumps here!! (%08X)\n", pCpu->Param1.fUse));
return 0;
}
#ifdef IN_RC
return (RTRCPTR)((uint8_t *)pBranchInstrGC + pCpu->cbInstr + disp);
#else
return pBranchInstrGC + pCpu->cbInstr + disp;
#endif
}
#ifdef LOG_ENABLED
DECLCALLBACK(int) patmR3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PPATMP2GLOOKUPREC pCacheRec);
int patmr3DisasmCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, PPATMP2GLOOKUPREC pCacheRec);
#endif
void patmR3DbgInit(PVM pVM);
void patmR3DbgTerm(PVM pVM);
void patmR3DbgReset(PVM pVM);
void patmR3DbgAddPatch(PVM pVM, PPATMPATCHREC pPatchRec);
PGM_ALL_CB2_PROTO(FNPGMVIRTHANDLER) patmVirtPageHandler;
#endif /* !VMM_INCLUDED_SRC_include_PATMInternal_h */
|