~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/VMM/PATM/PATMInternal.h

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: PATMInternal.h 4071 2007-08-07 17:07:59Z vboxsync $ */
 
2
/** @file
 
3
 * PATM - Internal header file.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2007 innotek GmbH
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License as published by the Free Software Foundation,
 
13
 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
 
14
 * distribution. VirtualBox OSE is distributed in the hope that it will
 
15
 * be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
#ifndef ___PATMInternal_h
 
19
#define ___PATMInternal_h
 
20
 
 
21
#include <VBox/cdefs.h>
 
22
#include <VBox/types.h>
 
23
#include <VBox/patm.h>
 
24
#include <VBox/stam.h>
 
25
#include <VBox/dis.h>
 
26
#include <iprt/avl.h>
 
27
#include <iprt/param.h>
 
28
#include <VBox/log.h>
 
29
 
 
30
#if !defined(IN_PATM_R3) && !defined(IN_PATM_R0) && !defined(IN_PATM_GC)
 
31
# error "Not in PATM! This is an internal header!"
 
32
#endif
 
33
 
 
34
 
 
35
#define PATM_SSM_VERSION                    53
 
36
 
 
37
/* Enable for call patching. */
 
38
#define PATM_ENABLE_CALL
 
39
#define PATCH_MEMORY_SIZE                  (2*1024*1024)
 
40
#define MAX_PATCH_SIZE                     (1024*4)
 
41
 
 
42
/*
 
43
 * Internal patch type flags (starts at BIT(11))
 
44
 */
 
45
 
 
46
#define PATMFL_CHECK_SIZE                   BIT64(11)
 
47
#define PATMFL_FOUND_PATCHEND               BIT64(12)
 
48
#define PATMFL_SINGLE_INSTRUCTION           BIT64(13)
 
49
#define PATMFL_SYSENTER_XP                  BIT64(14)
 
50
#define PATMFL_JUMP_CONFLICT                BIT64(15)
 
51
#define PATMFL_READ_ORIGINAL_BYTES          BIT64(16) /** opcode might have already been patched */
 
52
#define PATMFL_INT3_REPLACEMENT             BIT64(17)
 
53
#define PATMFL_SUPPORT_CALLS                BIT64(18)
 
54
#define PATMFL_SUPPORT_INDIRECT_CALLS       BIT64(19)
 
55
#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT BIT64(20) /** internal flag to avoid duplicate entrypoints */
 
56
#define PATMFL_INHIBIT_IRQS                 BIT64(21) /** temporary internal flag */
 
57
#define PATMFL_GENERATE_JUMPTOGUEST         BIT64(22) /** temporary internal flag */
 
58
#define PATMFL_RECOMPILE_NEXT               BIT64(23) /** for recompilation of the next instruction */
 
59
#define PATMFL_CODE_MONITORED               BIT64(24) /** code pages of guest monitored for self-modifying code. */
 
60
#define PATMFL_CALLABLE_AS_FUNCTION         BIT64(25) /** cli and pushf blocks can be used as callable functions. */
 
61
#define PATMFL_GLOBAL_FUNCTIONS             BIT64(26) /** fake patch for global patm functions. */
 
62
#define PATMFL_TRAMPOLINE                   BIT64(27) /** trampoline patch that clears PATM_INTERRUPTFLAG and jumps to patch destination */
 
63
#define PATMFL_GENERATE_SETPIF              BIT64(28) /** generate set PIF for the next instruction */
 
64
#define PATMFL_INSTR_HINT                   BIT64(29) /** Generate patch, but don't activate it. */
 
65
#define PATMFL_PATCHED_GUEST_CODE           BIT64(30) /** Patched guest code. */
 
66
#define PATMFL_MUST_INSTALL_PATCHJMP        BIT64(31) /** Need to patch guest code in order to activate patch. */
 
67
#define PATMFL_INT3_REPLACEMENT_BLOCK       BIT64(32) /** int 3 replacement block */
 
68
#define PATMFL_EXTERNAL_JUMP_INSIDE         BIT64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */
 
69
 
 
70
#define SIZEOF_NEARJUMP8                   2 //opcode byte + 1 byte relative offset
 
71
#define SIZEOF_NEARJUMP16                  3 //opcode byte + 2 byte relative offset
 
72
#define SIZEOF_NEARJUMP32                  5 //opcode byte + 4 byte relative offset
 
73
#define SIZEOF_NEAR_COND_JUMP32            6 //0xF + opcode byte + 4 byte relative offset
 
74
 
 
75
#define MAX_INSTR_SIZE                     16
 
76
 
 
77
//Patch states
 
78
#define PATCH_REFUSED                     1
 
79
#define PATCH_DISABLED                    2
 
80
#define PATCH_ENABLED                     4
 
81
#define PATCH_UNUSABLE                    8
 
82
#define PATCH_DIRTY                       16
 
83
#define PATCH_DISABLE_PENDING             32
 
84
 
 
85
 
 
86
#define MAX_PATCH_TRAPS                    4
 
87
#define PATM_MAX_CALL_DEPTH                32
 
88
/* Maximum nr of writes before a patch is marked dirty. (disabled) */
 
89
#define PATM_MAX_CODE_WRITES               32
 
90
/* Maximum nr of invalid writes before a patch is disabled. */
 
91
#define PATM_MAX_INVALID_WRITES            16384
 
92
 
 
93
#define FIXUP_ABSOLUTE                     0
 
94
#define FIXUP_REL_JMPTOPATCH               1
 
95
#define FIXUP_REL_JMPTOGUEST               2
 
96
 
 
97
#define PATM_ILLEGAL_DESTINATION           0xDEADBEEF
 
98
 
 
99
/** Size of the instruction that's used for requests from patch code (currently only call) */
 
100
#define PATM_ILLEGAL_INSTR_SIZE            2
 
101
 
 
102
 
 
103
/** No statistics counter index allocated just yet */
 
104
#define PATM_STAT_INDEX_NONE                (uint32_t)-1
 
105
/** Dummy counter to handle overflows */
 
106
#define PATM_STAT_INDEX_DUMMY               0
 
107
#define PATM_STAT_INDEX_IS_VALID(a)         (a != PATM_STAT_INDEX_DUMMY && a != PATM_STAT_INDEX_NONE)
 
108
 
 
109
#ifdef VBOX_WITH_STATISTICS
 
110
#define PATM_STAT_RUN_INC(pPatch)                                             \
 
111
        if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx))                \
 
112
            CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32A++;
 
113
#define PATM_STAT_FAULT_INC(pPatch)                                           \
 
114
        if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx))                \
 
115
            CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32B++;
 
116
#else
 
117
#define PATM_STAT_RUN_INC(pPatch)           do { } while (0)
 
118
#define PATM_STAT_FAULT_INC(pPatch)         do { } while (0)
 
119
#endif
 
120
 
 
121
/** Maximum number of stat counters. */
 
122
#define PATM_STAT_MAX_COUNTERS              1024
 
123
/** Size of memory allocated for patch statistics. */
 
124
#define PATM_STAT_MEMSIZE                   (PATM_STAT_MAX_COUNTERS*sizeof(STAMRATIOU32))
 
125
 
 
126
 
 
127
typedef struct
 
128
{
 
129
    /** The key is a HC virtual address. */
 
130
    AVLPVNODECORE   Core;
 
131
 
 
132
    uint32_t        uType;
 
133
    HCPTRTYPE(uint8_t *) pRelocPos;
 
134
    RTGCPTR         pSource;
 
135
    RTGCPTR         pDest;
 
136
} RELOCREC, *PRELOCREC;
 
137
 
 
138
typedef struct
 
139
{
 
140
    HCPTRTYPE(uint8_t *) pPatchLocStartHC;
 
141
    HCPTRTYPE(uint8_t *) pPatchLocEndHC;
 
142
    GCPTRTYPE(uint8_t *) pGuestLoc;
 
143
    uint32_t             opsize;
 
144
} P2GLOOKUPREC, *PP2GLOOKUPREC;
 
145
 
 
146
typedef struct
 
147
{
 
148
    /** The key is a pointer to a JUMPREC structure. */
 
149
    AVLPVNODECORE   Core;
 
150
 
 
151
    HCPTRTYPE(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
 */
 
160
typedef 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
 */
 
169
typedef 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
 */
 
184
typedef 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
 */
 
196
typedef struct
 
197
{
 
198
    /* Temporary tree for storing the addresses of illegal instructions. */
 
199
    HCPTRTYPE(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
    HCPTRTYPE(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
 
 
218
typedef 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
    HCPTRTYPE(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
    HCPTRTYPE(PAVLPVNODECORE) FixupTree;
 
251
    int32_t         nrFixups;
 
252
 
 
253
    /* Tree of jumps inside the generated patch code. */
 
254
    int32_t         nrJumpRecs;
 
255
    HCPTRTYPE(PAVLPVNODECORE) JumpTree;
 
256
 
 
257
    /**
 
258
     * Lookup trees for determining the corresponding guest address of an
 
259
     * instruction in the patch block.
 
260
     */
 
261
    HCPTRTYPE(PAVLU32NODECORE) Patch2GuestAddrTree;
 
262
    HCPTRTYPE(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
    HCPTRTYPE(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
 */
 
297
typedef 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
 */
 
313
typedef 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
    HCPTRTYPE(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
 
 
331
typedef 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
 */
 
355
typedef struct PATM
 
356
{
 
357
    /** Offset to the VM structure.
 
358
     * See PATM2VM(). */
 
359
    RTINT                   offVM;
 
360
 
 
361
    GCPTRTYPE(uint8_t *)    pPatchMemGC;
 
362
    HCPTRTYPE(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
    HCPTRTYPE(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
    HCPTRTYPE(RTGCPTR *)    pGCStackHC;
 
376
 
 
377
    /** GC pointer to CPUMCTX structure. */
 
378
    GCPTRTYPE(PCPUMCTX)     pCPUMCtxGC;
 
379
 
 
380
    /* GC statistics pointers */
 
381
    GCPTRTYPE(PSTAMRATIOU32) pStatsGC;
 
382
    HCPTRTYPE(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
    HCPTRTYPE(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
    HCPTRTYPE(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
        HCPTRTYPE(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
 */
 
510
DECLCALLBACK(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
 */
 
521
DECLCALLBACK(int) patmr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
 
522
 
 
523
#ifdef IN_RING3
 
524
RTGCPTR patmPatchGCPtr2GuestGCPtr(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t *) pPatchGC);
 
525
RTGCPTR patmGuestGCPtrToPatchGCPtr(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t*) pInstrGC);
 
526
#endif
 
527
 
 
528
/* Add a patch to guest lookup record
 
529
 *
 
530
 * @param   pVM             The VM to operate on.
 
531
 * @param   pPatch          Patch structure ptr
 
532
 * @param   pPatchInstrHC   Guest context pointer to patch block
 
533
 * @param   pInstrGC        Guest context pointer to privileged instruction
 
534
 * @param   enmType         Lookup type
 
535
 * @param   fDirty          Dirty flag
 
536
 *
 
537
 */
 
538
void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTGCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty=false);
 
539
 
 
540
/**
 
541
 * Insert page records for all guest pages that contain instructions that were recompiled for this patch
 
542
 *
 
543
 * @returns VBox status code.
 
544
 * @param   pVM         The VM to operate on.
 
545
 * @param   pPatch      Patch record
 
546
 */
 
547
int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch);
 
548
 
 
549
/**
 
550
 * Remove page records for all guest pages that contain instructions that were recompiled for this patch
 
551
 *
 
552
 * @returns VBox status code.
 
553
 * @param   pVM         The VM to operate on.
 
554
 * @param   pPatch      Patch record
 
555
 */
 
556
int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch);
 
557
 
 
558
/**
 
559
 * Returns the GC address of the corresponding patch statistics counter
 
560
 *
 
561
 * @returns Stat address
 
562
 * @param   pVM         The VM to operate on.
 
563
 * @param   pPatch      Patch structure
 
564
 */
 
565
RTGCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch);
 
566
 
 
567
/**
 
568
 * Remove patch for privileged instruction at specified location
 
569
 *
 
570
 * @returns VBox status code.
 
571
 * @param   pVM             The VM to operate on.
 
572
 * @param   pPatchRec       Patch record
 
573
 * @param   fForceRemove    Remove *all* patches
 
574
 */
 
575
int PATMRemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove);
 
576
 
 
577
/**
 
578
 * Call for analysing the instructions following the privileged instr. for compliance with our heuristics
 
579
 *
 
580
 * @returns VBox status code.
 
581
 * @param   pVM         The VM to operate on.
 
582
 * @param   pCpu        CPU disassembly state
 
583
 * @param   pInstrHC    Guest context pointer to privileged instruction
 
584
 * @param   pCurInstrHC Guest context pointer to current instruction
 
585
 * @param   pUserData   User pointer
 
586
 *
 
587
 */
 
588
typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
 
589
 
 
590
/**
 
591
 * Install guest OS specific patch
 
592
 *
 
593
 * @returns VBox status code.
 
594
 * @param   pVM         The VM to operate on
 
595
 * @param   pCpu        Disassembly state of instruction.
 
596
 * @param   pInstrGC    GC Instruction pointer for instruction
 
597
 * @param   pInstrHC    GC Instruction pointer for instruction
 
598
 * @param   pPatchRec   Patch structure
 
599
 *
 
600
 */
 
601
int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);
 
602
 
 
603
/**
 
604
 * Convert guest context address to host context pointer
 
605
 *
 
606
 * @returns VBox status code.
 
607
 * @param   pVM         The VM to operate on.
 
608
 * @param   pPatch      Patch block structure pointer
 
609
 * @param   pGCPtr      Guest context pointer
 
610
 *
 
611
 * @returns             Host context pointer or NULL in case of an error
 
612
 *
 
613
 */
 
614
HCPTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t *) pGCPtr);
 
615
 
 
616
 
 
617
/**
 
618
 * Check if the instruction is patched as a duplicated function
 
619
 *
 
620
 * @returns patch record
 
621
 * @param   pVM         The VM to operate on.
 
622
 * @param   pInstrGC    Guest context point to the instruction
 
623
 *
 
624
 */
 
625
PATMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTGCPTR pInstrGC);
 
626
 
 
627
 
 
628
/**
 
629
 * Empty the specified tree (PV tree, MMR3 heap)
 
630
 *
 
631
 * @param   pVM             The VM to operate on.
 
632
 * @param   ppTree          Tree to empty
 
633
 */
 
634
void patmEmptyTree(PVM pVM, PPAVLPVNODECORE ppTree);
 
635
 
 
636
 
 
637
/**
 
638
 * Empty the specified tree (U32 tree, MMR3 heap)
 
639
 *
 
640
 * @param   pVM             The VM to operate on.
 
641
 * @param   ppTree          Tree to empty
 
642
 */
 
643
void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree);
 
644
 
 
645
 
 
646
/**
 
647
 * Return the name of the patched instruction
 
648
 *
 
649
 * @returns instruction name
 
650
 *
 
651
 * @param   opcode      DIS instruction opcode
 
652
 * @param   fPatchFlags Patch flags
 
653
 */
 
654
PATMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags);
 
655
 
 
656
 
 
657
/**
 
658
 * Read callback for disassembly function; supports reading bytes that cross a page boundary
 
659
 *
 
660
 * @returns VBox status code.
 
661
 * @param   pSrc        GC source pointer
 
662
 * @param   pDest       HC destination pointer
 
663
 * @param   size        Number of bytes to read
 
664
 * @param   dwUserdata  Callback specific user data (pCpu)
 
665
 *
 
666
 */
 
667
int32_t patmReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, RTHCUINTPTR dwUserdata);
 
668
 
 
669
 
 
670
#ifndef IN_GC
 
671
 
 
672
#define PATMREAD_RAWCODE        1  /* read code as-is */
 
673
#define PATMREAD_ORGCODE        2  /* read original guest opcode bytes; not the patched bytes */
 
674
#define PATMREAD_NOCHECK        4  /* don't check for patch conflicts */
 
675
 
 
676
/*
 
677
 * Private structure used during disassembly
 
678
 */
 
679
typedef struct
 
680
{
 
681
    PVM           pVM;
 
682
    PPATCHINFO    pPatchInfo;
 
683
    HCPTRTYPE(uint8_t *) pInstrHC;
 
684
    RTGCPTR       pInstrGC;
 
685
    uint32_t      fReadFlags;
 
686
} PATMDISASM, *PPATMDISASM;
 
687
 
 
688
inline bool PATMR3DISInstr(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTGCPTR InstrGC,
 
689
                           uint8_t *InstrHC, uint32_t *pOpsize, char *pszOutput,
 
690
                           uint32_t fReadFlags = PATMREAD_ORGCODE)
 
691
{
 
692
    PATMDISASM disinfo;
 
693
    disinfo.pVM    = pVM;
 
694
    disinfo.pPatchInfo = pPatch;
 
695
    disinfo.pInstrHC = InstrHC;
 
696
    disinfo.pInstrGC = InstrGC;
 
697
    disinfo.fReadFlags = fReadFlags;
 
698
    (pCpu)->pfnReadBytes  = patmReadBytes;
 
699
    (pCpu)->dwUserData[0] = (RTHCUINTPTR)&disinfo;
 
700
    return DISInstr(pCpu, InstrGC, 0, pOpsize, pszOutput);
 
701
}
 
702
#endif /* !IN_GC */
 
703
 
 
704
__BEGIN_DECLS
 
705
/**
 
706
 * #PF Virtual Handler callback for Guest access a page monitored by PATM
 
707
 *
 
708
 * @returns VBox status code (appropritate for trap handling and GC return).
 
709
 * @param   pVM         VM Handle.
 
710
 * @param   uErrorCode   CPU Error code.
 
711
 * @param   pRegFrame   Trap register frame.
 
712
 * @param   pvFault     The fault address (cr2).
 
713
 * @param   pvRange     The base address of the handled virtual range.
 
714
 * @param   offRange    The offset of the access into this range.
 
715
 *                      (If it's a EIP range this's the EIP, if not it's pvFault.)
 
716
 */
 
717
PATMGCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, void *pvRange, uintptr_t offRange);
 
718
 
 
719
/**
 
720
 * Find patch for privileged instruction at specified location
 
721
 *
 
722
 * @returns Patch structure pointer if found; else NULL
 
723
 * @param   pVM           The VM to operate on.
 
724
 * @param   pInstr        Guest context point to instruction that might lie within 5 bytes of an existing patch jump
 
725
 * @param   fIncludeHints Include hinted patches or not
 
726
 *
 
727
 */
 
728
PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTGCPTR pInstrGC, bool fIncludeHints=false);
 
729
 
 
730
/**
 
731
 * Patch cli/sti pushf/popf instruction block at specified location
 
732
 *
 
733
 * @returns VBox status code.
 
734
 * @param   pVM         The VM to operate on.
 
735
 * @param   pInstrGC    Guest context point to privileged instruction
 
736
 * @param   pInstrHC    Host context point to privileged instruction
 
737
 * @param   uOpcode     Instruction opcodee
 
738
 * @param   uOpSize     Size of starting instruction
 
739
 * @param   pPatchRec   Patch record
 
740
 *
 
741
 * @note    returns failure if patching is not allowed or possible
 
742
 *
 
743
 */
 
744
PATMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTGCPTR pInstrGC, HCPTRTYPE(uint8_t *) pInstrHC,
 
745
                                 uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec);
 
746
 
 
747
 
 
748
/**
 
749
 * Replace an instruction with a breakpoint (0xCC), that is handled dynamically in the guest context.
 
750
 *
 
751
 * @returns VBox status code.
 
752
 * @param   pVM         The VM to operate on.
 
753
 * @param   pInstrGC    Guest context point to privileged instruction
 
754
 * @param   pInstrHC    Host context point to privileged instruction
 
755
 * @param   pCpu        Disassembly CPU structure ptr
 
756
 * @param   pPatch      Patch record
 
757
 *
 
758
 * @note    returns failure if patching is not allowed or possible
 
759
 *
 
760
 */
 
761
PATMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTGCPTR pInstrGC, HCPTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);
 
762
 
 
763
/**
 
764
 * Mark patch as dirty
 
765
 *
 
766
 * @returns VBox status code.
 
767
 * @param   pVM         The VM to operate on.
 
768
 * @param   pPatch      Patch record
 
769
 *
 
770
 * @note    returns failure if patching is not allowed or possible
 
771
 *
 
772
 */
 
773
PATMR3DECL(int) PATMR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch);
 
774
 
 
775
/**
 
776
 * Calculate the branch destination
 
777
 *
 
778
 * @returns branch destination or 0 if failed
 
779
 * @param   pCpu            Disassembly state of instruction.
 
780
 * @param   pBranchInstrGC  GC pointer of branch instruction
 
781
 */
 
782
inline RTGCPTR PATMResolveBranch(PDISCPUSTATE pCpu, RTGCPTR pBranchInstrGC)
 
783
{
 
784
    uint32_t disp;
 
785
    if (pCpu->param1.flags & USE_IMMEDIATE8_REL)
 
786
    {
 
787
        disp = (int32_t)(char)pCpu->param1.parval;
 
788
    }
 
789
    else
 
790
    if (pCpu->param1.flags & USE_IMMEDIATE16_REL)
 
791
    {
 
792
        disp = (int32_t)(uint16_t)pCpu->param1.parval;
 
793
    }
 
794
    else
 
795
    if (pCpu->param1.flags & USE_IMMEDIATE32_REL)
 
796
    {
 
797
        disp = (int32_t)pCpu->param1.parval;
 
798
    }
 
799
    else
 
800
    {
 
801
        Log(("We don't support far jumps here!! (%08X)\n", pCpu->param1.flags));
 
802
        return 0;
 
803
    }
 
804
#ifdef IN_GC
 
805
    return (RTGCPTR)((uint8_t *)pBranchInstrGC + pCpu->opsize + disp);
 
806
#else
 
807
    return pBranchInstrGC + pCpu->opsize + disp;
 
808
#endif
 
809
}
 
810
 
 
811
__END_DECLS
 
812
 
 
813
#ifdef DEBUG
 
814
int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
 
815
int patmr3DisasmCodeStream(PVM pVM, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, void *pUserData);
 
816
#endif
 
817
 
 
818
#endif