summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/PATM/PATMInternal.h
blob: 2d855e9203ff327245fe0a14c83309ace74fb547 (plain)
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
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
/* $Id: PATMInternal.h 28800 2010-04-27 08:22:32Z vboxsync $ */
/** @file
 * PATM - Internal header file.
 */

/*
 * Copyright (C) 2006-2007 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 ___PATMInternal_h
#define ___PATMInternal_h

#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/patm.h>
#include <VBox/stam.h>
#include <VBox/dis.h>
#include <VBox/pgm.h>
#include <iprt/avl.h>
#include <iprt/param.h>
#include <VBox/log.h>



#ifdef PATM_WITH_NEW_SSM
# define PATM_SSM_VERSION                    54
/* Last version to use SSMR3Put/GetMem */
# define PATM_SSM_VERSION_GETPUTMEM          53
#else
# define PATM_SSM_VERSION                    55
# define PATM_SSM_VERSION_FIXUP_HACK         54
# define PATM_SSM_VERSION_FIXUP_HACK         54
# define PATM_SSM_VERSION_VER16              53
#endif

/* 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_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

#define FIXUP_ABSOLUTE                     0
#define FIXUP_REL_JMPTOPATCH               1
#define FIXUP_REL_JMPTOGUEST               2

#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;

typedef struct
{
    R3PTRTYPE(uint8_t *) pPatchLocStartHC;
    R3PTRTYPE(uint8_t *) pPatchLocEndHC;
    RCPTRTYPE(uint8_t *) pGuestLoc;
    uint32_t             opsize;
} P2GLOOKUPREC, *PP2GLOOKUPREC;

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
{
    PATM_LOOKUP_PATCH2GUEST,    /* patch to guest */
    PATM_LOOKUP_BOTHDIR         /* guest to patch + patch to guest */
} PATM_LOOKUP_TYPE;

/**
 * Patch to guest address lookup record
 */
typedef struct RECPATCHTOGUEST
{
    /** The key is an offset inside the patch memory block. */
    AVLU32NODECORE   Core;

    RTRCPTR          pOrgInstrGC;
    PATM_LOOKUP_TYPE enmType;
    bool             fDirty;
    bool             fJumpTarget;
    uint8_t          u8DirtyOpcode;  /* original opcode before writing 0xCC there to mark it dirty */
} 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 disassmebly log. */
    RTRCPTR                   pLastDisasmInstrGC;

    /** Keeping track of multiple ret instructions. */
    RTRCPTR                 pPatchRetInstrGC;
    uint32_t                    uPatchRetParam1;
} PATCHINFOTEMP, *PPATCHINFOTEMP;

typedef struct _PATCHINFO
{
    uint32_t        uState;
    uint32_t        uOldState;
    DISCPUMODE      uOpMode;

    RCPTRTYPE(uint8_t *)  pPrivInstrGC;    //GC pointer of privileged instruction
    R3PTRTYPE(uint8_t *)  pPrivInstrHC;    //HC pointer of privileged instruction
    uint8_t         aPrivInstr[MAX_INSTR_SIZE];
    uint32_t        cbPrivInstr;
    uint32_t        opcode;      //opcode for priv instr (OP_*)
    uint32_t        cbPatchJump; //patch jump size

    /* Only valid for PATMFL_JUMP_CONFLICT patches */
    RTRCPTR       pPatchJumpDestGC;

    RTGCUINTPTR32   pPatchBlockOffset;
    uint32_t        cbPatchBlockSize;
    uint32_t        uCurPatchOffset;
#if HC_ARCH_BITS == 64
    uint32_t        Alignment0;         /**< Align flags correctly. */
#endif

    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;
    int32_t         nrFixups;

    /* Tree of jumps inside the generated patch code. */
    int32_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

    // Cache record for PATMGCVirtToHCVirt
    P2GLOOKUPREC    cacheRec;

    /* Temporary information during patch creation. Don't waste hypervisor memory for this. */
    R3PTRTYPE(PPATCHINFOTEMP) pTempInfo;

    /* Count the number of writes to the corresponding guest code. */
    uint32_t        cCodeWrites;

    /* Count the number of invalid writes to pages monitored for the patch. */
    //some statistics to determine if we should keep this patch activated
    uint32_t        cTraps;

    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;
    uint8_t         Alignment2[7];      /**< Align the structure size on a 8-byte boundrary. */
} 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;

    PATCHINFO  patch;
} PATMPATCHREC, *PPATMPATCHREC;

/** 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 *) aPatch;
} PATMPATCHPAGE, *PPATMPATCHPAGE;

#define PATM_PATCHREC_FROM_COREOFFSET(a)  (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, CoreOffset))
#define PATM_PATCHREC_FROM_PATCHINFO(a)   (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, patch))

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;

    RCPTRTYPE(uint8_t *)    pPatchMemGC;
    R3PTRTYPE(uint8_t *)    pPatchMemHC;
    uint32_t                cbPatchMem;
    uint32_t                offPatchMem;
    bool                    fOutOfMemory;

    int32_t                 deltaReloc;

    /* GC PATM state pointers */
    R3PTRTYPE(PPATMGCSTATE) pGCStateHC;
    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;
    R3PTRTYPE(RTRCPTR *)    pGCStackHC;

    /** GC pointer to CPUMCTX structure. */
    RCPTRTYPE(PCPUMCTX)     pCPUMCtxGC;

    /* GC statistics pointers */
    RCPTRTYPE(PSTAMRATIOU32) pStatsGC;
    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 boundrary. */
    } 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 boundrary. */
#endif
    } savedstate;

    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 boundrary. */
} PATM, *PPATM;



DECLCALLBACK(int) patmVirtPageHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);

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

/* Add a patch to guest lookup record
 *
 * @param   pVM             The VM to operate on.
 * @param   pPatch          Patch structure ptr
 * @param   pPatchInstrHC   Guest context pointer to patch block
 * @param   pInstrGC        Guest context pointer to privileged instruction
 * @param   enmType         Lookup type
 * @param   fDirty          Dirty flag
 *
 */
void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTRCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty=false);

/**
 * Insert page records for all guest pages that contain instructions that were recompiled for this patch
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch record
 */
int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch);

/**
 * Remove page records for all guest pages that contain instructions that were recompiled for this patch
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch record
 */
int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch);

/**
 * Returns the GC address of the corresponding patch statistics counter
 *
 * @returns Stat address
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch structure
 */
RTRCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch);

/**
 * Remove patch for privileged instruction at specified location
 *
 * @returns VBox status code.
 * @param   pVM             The VM to operate on.
 * @param   pPatchRec       Patch record
 * @param   fForceRemove    Remove *all* patches
 */
int PATMRemovePatch(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 VM to operate on.
 * @param   pCpu        CPU disassembly state
 * @param   pInstrHC    Guest context pointer to privileged instruction
 * @param   pCurInstrHC Guest context pointer to current instruction
 * @param   pUserData   User pointer
 *
 */
typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);

/**
 * Install guest OS specific patch
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on
 * @param   pCpu        Disassembly state of instruction.
 * @param   pInstrGC    GC Instruction pointer for instruction
 * @param   pInstrHC    GC Instruction pointer for instruction
 * @param   pPatchRec   Patch structure
 *
 */
int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTRCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);

/**
 * Convert guest context address to host context pointer
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch block structure pointer
 * @param   pGCPtr      Guest context pointer
 *
 * @returns             Host context pointer or NULL in case of an error
 *
 */
R3PTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATCHINFO pPatch, RCPTRTYPE(uint8_t *) pGCPtr);


/**
 * Check if the instruction is patched as a duplicated function
 *
 * @returns patch record
 * @param   pVM         The VM to operate on.
 * @param   pInstrGC    Guest context point to the instruction
 *
 */
VMMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC);


/**
 * Empty the specified tree (PV tree, MMR3 heap)
 *
 * @param   pVM             The VM to operate on.
 * @param   ppTree          Tree to empty
 */
void patmEmptyTree(PVM pVM, PPAVLPVNODECORE ppTree);


/**
 * Empty the specified tree (U32 tree, MMR3 heap)
 *
 * @param   pVM             The VM to operate on.
 * @param   ppTree          Tree to empty
 */
void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree);


/**
 * Return the name of the patched instruction
 *
 * @returns instruction name
 *
 * @param   opcode      DIS instruction opcode
 * @param   fPatchFlags Patch flags
 */
VMMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags);


/**
 * Read callback for disassembly function; supports reading bytes that cross a page boundary
 *
 * @returns VBox status code.
 * @param   pSrc        GC source pointer
 * @param   pDest       HC destination pointer
 * @param   size        Number of bytes to read
 * @param   pvUserdata  Callback specific user data (pCpu)
 *
 */
int patmReadBytes(RTUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata);


#ifndef IN_RC

#define PATMREAD_RAWCODE        1  /* read code as-is */
#define PATMREAD_ORGCODE        2  /* read original guest opcode bytes; not the patched bytes */
#define PATMREAD_NOCHECK        4  /* don't check for patch conflicts */

/*
 * Private structure used during disassembly
 */
typedef struct
{
    PVM           pVM;
    PPATCHINFO    pPatchInfo;
    R3PTRTYPE(uint8_t *) pInstrHC;
    RTRCPTR       pInstrGC;
    uint32_t      fReadFlags;
} PATMDISASM, *PPATMDISASM;

inline bool PATMR3DISInstr(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTRCPTR InstrGC,
                           uint8_t *InstrHC, uint32_t *pOpsize, char *pszOutput,
                           uint32_t fReadFlags = PATMREAD_ORGCODE)
{
    PATMDISASM disinfo;
    disinfo.pVM         = pVM;
    disinfo.pPatchInfo  = pPatch;
    disinfo.pInstrHC    = InstrHC;
    disinfo.pInstrGC    = InstrGC;
    disinfo.fReadFlags  = fReadFlags;
    (pCpu)->pfnReadBytes = patmReadBytes;
    (pCpu)->apvUserData[0] = &disinfo;
    return RT_SUCCESS(DISInstr(pCpu, InstrGC, 0, pOpsize, pszOutput));
}
#endif /* !IN_RC */

RT_C_DECLS_BEGIN
/**
 * #PF Virtual Handler callback for Guest access a page monitored by PATM
 *
 * @returns VBox status code (appropritate for trap handling and GC return).
 * @param   pVM         VM Handle.
 * @param   uErrorCode   CPU Error code.
 * @param   pRegFrame   Trap register frame.
 * @param   pvFault     The fault address (cr2).
 * @param   pvRange     The base address of the handled virtual range.
 * @param   offRange    The offset of the access into this range.
 *                      (If it's a EIP range this's the EIP, if not it's pvFault.)
 */
VMMRCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);

/**
 * Find patch for privileged instruction at specified location
 *
 * @returns Patch structure pointer if found; else NULL
 * @param   pVM           The VM to operate on.
 * @param   pInstr        Guest context point to instruction that might lie within 5 bytes of an existing patch jump
 * @param   fIncludeHints Include hinted patches or not
 *
 */
PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTRCPTR pInstrGC, bool fIncludeHints=false);

/**
 * Patch cli/sti pushf/popf instruction block at specified location
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pInstrGC    Guest context point to privileged instruction
 * @param   pInstrHC    Host context point to privileged instruction
 * @param   uOpcode     Instruction opcodee
 * @param   uOpSize     Size of starting instruction
 * @param   pPatchRec   Patch record
 *
 * @note    returns failure if patching is not allowed or possible
 *
 */
VMMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC,
                                 uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec);


/**
 * Replace an instruction with a breakpoint (0xCC), that is handled dynamically in the guest context.
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pInstrGC    Guest context point to privileged instruction
 * @param   pInstrHC    Host context point to privileged instruction
 * @param   pCpu        Disassembly CPU structure ptr
 * @param   pPatch      Patch record
 *
 * @note    returns failure if patching is not allowed or possible
 *
 */
VMMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTRCPTR pInstrGC, R3PTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);

/**
 * Mark patch as dirty
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch record
 *
 * @note    returns failure if patching is not allowed or possible
 *
 */
VMMR3DECL(int) PATMR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch);

/**
 * Calculate the branch destination
 *
 * @returns branch destination or 0 if failed
 * @param   pCpu            Disassembly state of instruction.
 * @param   pBranchInstrGC  GC pointer of branch instruction
 */
inline RTRCPTR PATMResolveBranch(PDISCPUSTATE pCpu, RTRCPTR pBranchInstrGC)
{
    uint32_t disp;
    if (pCpu->param1.flags & USE_IMMEDIATE8_REL)
    {
        disp = (int32_t)(char)pCpu->param1.parval;
    }
    else
    if (pCpu->param1.flags & USE_IMMEDIATE16_REL)
    {
        disp = (int32_t)(uint16_t)pCpu->param1.parval;
    }
    else
    if (pCpu->param1.flags & USE_IMMEDIATE32_REL)
    {
        disp = (int32_t)pCpu->param1.parval;
    }
    else
    {
        Log(("We don't support far jumps here!! (%08X)\n", pCpu->param1.flags));
        return 0;
    }
#ifdef IN_RC
    return (RTRCPTR)((uint8_t *)pBranchInstrGC + pCpu->opsize + disp);
#else
    return pBranchInstrGC + pCpu->opsize + disp;
#endif
}

RT_C_DECLS_END

#ifdef LOG_ENABLED
int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
int patmr3DisasmCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, void *pUserData);
#endif

#endif