~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/VMM/VMMAll/PATMAll.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: PATMAll.cpp 35348 2010-12-27 16:35:23Z vboxsync $ */
 
2
/** @file
 
3
 * PATM - The Patch Manager, all contexts.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2007 Oracle Corporation
 
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 (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
/*******************************************************************************
 
19
*   Header Files                                                               *
 
20
*******************************************************************************/
 
21
#define LOG_GROUP LOG_GROUP_PATM
 
22
#include <VBox/vmm/patm.h>
 
23
#include <VBox/vmm/cpum.h>
 
24
#include <VBox/dis.h>
 
25
#include <VBox/disopcode.h>
 
26
#include <VBox/vmm/em.h>
 
27
#include <VBox/err.h>
 
28
#include <VBox/vmm/selm.h>
 
29
#include <VBox/vmm/mm.h>
 
30
#include "PATMInternal.h"
 
31
#include <VBox/vmm/vm.h>
 
32
#include <VBox/vmm/vmm.h>
 
33
#include "PATMA.h"
 
34
 
 
35
#include <VBox/log.h>
 
36
#include <iprt/assert.h>
 
37
 
 
38
 
 
39
/**
 
40
 * Load virtualized flags.
 
41
 *
 
42
 * This function is called from CPUMRawEnter(). It doesn't have to update the
 
43
 * IF and IOPL eflags bits, the caller will enforce those to set and 0 respectively.
 
44
 *
 
45
 * @param   pVM         VM handle.
 
46
 * @param   pCtxCore    The cpu context core.
 
47
 * @see     pg_raw
 
48
 */
 
49
VMMDECL(void) PATMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore)
 
50
{
 
51
    bool fPatchCode = PATMIsPatchGCAddr(pVM, pCtxCore->eip);
 
52
 
 
53
    /*
 
54
     * Currently we don't bother to check whether PATM is enabled or not.
 
55
     * For all cases where it isn't, IOPL will be safe and IF will be set.
 
56
     */
 
57
    register uint32_t efl = pCtxCore->eflags.u32;
 
58
    CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK;
 
59
    AssertMsg((efl & X86_EFL_IF) || PATMShouldUseRawMode(pVM, (RTRCPTR)pCtxCore->eip), ("X86_EFL_IF is clear and PATM is disabled! (eip=%RRv eflags=%08x fPATM=%d pPATMGC=%RRv-%RRv\n", pCtxCore->eip, pCtxCore->eflags.u32, PATMIsEnabled(pVM), pVM->patm.s.pPatchMemGC, pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem));
 
60
 
 
61
    AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || fPatchCode, ("fPIF=%d eip=%RRv\n", CTXSUFF(pVM->patm.s.pGCState)->fPIF, pCtxCore->eip));
 
62
 
 
63
    efl &= ~PATM_VIRTUAL_FLAGS_MASK;
 
64
    efl |= X86_EFL_IF;
 
65
    pCtxCore->eflags.u32 = efl;
 
66
 
 
67
#ifdef IN_RING3
 
68
#ifdef PATM_EMULATE_SYSENTER
 
69
    PCPUMCTX pCtx;
 
70
 
 
71
    /* Check if the sysenter handler has changed. */
 
72
    pCtx = CPUMQueryGuestCtxPtr(pVM);
 
73
    if (   pCtx->SysEnter.cs  != 0
 
74
        && pCtx->SysEnter.eip != 0
 
75
       )
 
76
    {
 
77
        if (pVM->patm.s.pfnSysEnterGC != (RTRCPTR)pCtx->SysEnter.eip)
 
78
        {
 
79
            pVM->patm.s.pfnSysEnterPatchGC = 0;
 
80
            pVM->patm.s.pfnSysEnterGC = 0;
 
81
 
 
82
            Log2(("PATMRawEnter: installing sysenter patch for %RRv\n", pCtx->SysEnter.eip));
 
83
            pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip);
 
84
            if (pVM->patm.s.pfnSysEnterPatchGC == 0)
 
85
            {
 
86
                rc = PATMR3InstallPatch(pVM, pCtx->SysEnter.eip, PATMFL_SYSENTER | PATMFL_CODE32);
 
87
                if (rc == VINF_SUCCESS)
 
88
                {
 
89
                    pVM->patm.s.pfnSysEnterPatchGC  = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip);
 
90
                    pVM->patm.s.pfnSysEnterGC       = (RTRCPTR)pCtx->SysEnter.eip;
 
91
                    Assert(pVM->patm.s.pfnSysEnterPatchGC);
 
92
                }
 
93
            }
 
94
            else
 
95
                pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip;
 
96
        }
 
97
    }
 
98
    else
 
99
    {
 
100
        pVM->patm.s.pfnSysEnterPatchGC = 0;
 
101
        pVM->patm.s.pfnSysEnterGC = 0;
 
102
    }
 
103
#endif
 
104
#endif
 
105
}
 
106
 
 
107
 
 
108
/**
 
109
 * Restores virtualized flags.
 
110
 *
 
111
 * This function is called from CPUMRawLeave(). It will update the eflags register.
 
112
 *
 
113
 ** @note Only here we are allowed to switch back to guest code (without a special reason such as a trap in patch code)!!
 
114
 *
 
115
 * @param   pVM         VM handle.
 
116
 * @param   pCtxCore    The cpu context core.
 
117
 * @param   rawRC       Raw mode return code
 
118
 * @see     @ref pg_raw
 
119
 */
 
120
VMMDECL(void) PATMRawLeave(PVM pVM, PCPUMCTXCORE pCtxCore, int rawRC)
 
121
{
 
122
    bool fPatchCode = PATMIsPatchGCAddr(pVM, pCtxCore->eip);
 
123
    /*
 
124
     * We will only be called if PATMRawEnter was previously called.
 
125
     */
 
126
    register uint32_t efl = pCtxCore->eflags.u32;
 
127
    efl = (efl & ~PATM_VIRTUAL_FLAGS_MASK) | (CTXSUFF(pVM->patm.s.pGCState)->uVMFlags & PATM_VIRTUAL_FLAGS_MASK);
 
128
    pCtxCore->eflags.u32 = efl;
 
129
    CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = X86_EFL_IF;
 
130
 
 
131
    AssertReleaseMsg((efl & X86_EFL_IF) || fPatchCode || rawRC == VINF_PATM_PENDING_IRQ_AFTER_IRET || RT_FAILURE(rawRC), ("Inconsistent state at %RRv rc=%Rrc\n", pCtxCore->eip, rawRC));
 
132
    AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || fPatchCode || RT_FAILURE(rawRC), ("fPIF=%d eip=%RRv rc=%Rrc\n", CTXSUFF(pVM->patm.s.pGCState)->fPIF, pCtxCore->eip, rawRC));
 
133
 
 
134
#ifdef IN_RING3
 
135
    if (    (efl & X86_EFL_IF)
 
136
        &&  fPatchCode
 
137
       )
 
138
    {
 
139
        if (    rawRC < VINF_PATM_LEAVEGC_FIRST
 
140
            ||  rawRC > VINF_PATM_LEAVEGC_LAST)
 
141
        {
 
142
            /*
 
143
             * Golden rules:
 
144
             * - Don't interrupt special patch streams that replace special instructions
 
145
             * - Don't break instruction fusing (sti, pop ss, mov ss)
 
146
             * - Don't go back to an instruction that has been overwritten by a patch jump
 
147
             * - Don't interrupt an idt handler on entry (1st instruction); technically incorrect
 
148
             *
 
149
             */
 
150
            if (CTXSUFF(pVM->patm.s.pGCState)->fPIF == 1)            /* consistent patch instruction state */
 
151
            {
 
152
                PATMTRANSSTATE  enmState;
 
153
                RTRCPTR         pOrgInstrGC = PATMR3PatchToGCPtr(pVM, pCtxCore->eip, &enmState);
 
154
 
 
155
                AssertRelease(pOrgInstrGC);
 
156
 
 
157
                Assert(enmState != PATMTRANS_OVERWRITTEN);
 
158
                if (enmState == PATMTRANS_SAFE)
 
159
                {
 
160
                    Assert(!PATMFindActivePatchByEntrypoint(pVM, pOrgInstrGC));
 
161
                    Log(("Switchback from %RRv to %RRv (Psp=%x)\n", pCtxCore->eip, pOrgInstrGC, CTXSUFF(pVM->patm.s.pGCState)->Psp));
 
162
                    STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBack);
 
163
                    pCtxCore->eip = pOrgInstrGC;
 
164
                    fPatchCode = false; /* to reset the stack ptr */
 
165
 
 
166
                    CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts = 0;   /* reset this pointer; safe otherwise the state would be PATMTRANS_INHIBITIRQ */
 
167
                }
 
168
                else
 
169
                {
 
170
                    LogFlow(("Patch address %RRv can't be interrupted (state=%d)!\n",  pCtxCore->eip, enmState));
 
171
                    STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBackFail);
 
172
                }
 
173
            }
 
174
            else
 
175
            {
 
176
                LogFlow(("Patch address %RRv can't be interrupted (fPIF=%d)!\n",  pCtxCore->eip, CTXSUFF(pVM->patm.s.pGCState)->fPIF));
 
177
                STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBackFail);
 
178
            }
 
179
        }
 
180
    }
 
181
#else /* !IN_RING3 */
 
182
    AssertMsgFailed(("!IN_RING3"));
 
183
#endif  /* !IN_RING3 */
 
184
 
 
185
    if (!fPatchCode)
 
186
    {
 
187
        if (CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts == (RTRCPTR)pCtxCore->eip)
 
188
        {
 
189
            EMSetInhibitInterruptsPC(VMMGetCpu0(pVM), pCtxCore->eip);
 
190
        }
 
191
        CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts = 0;
 
192
 
 
193
        /* Reset the stack pointer to the top of the stack. */
 
194
#ifdef DEBUG
 
195
        if (CTXSUFF(pVM->patm.s.pGCState)->Psp != PATM_STACK_SIZE)
 
196
        {
 
197
            LogFlow(("PATMRawLeave: Reset PATM stack (Psp = %x)\n", CTXSUFF(pVM->patm.s.pGCState)->Psp));
 
198
        }
 
199
#endif
 
200
        CTXSUFF(pVM->patm.s.pGCState)->Psp = PATM_STACK_SIZE;
 
201
    }
 
202
}
 
203
 
 
204
/**
 
205
 * Get the EFLAGS.
 
206
 * This is a worker for CPUMRawGetEFlags().
 
207
 *
 
208
 * @returns The eflags.
 
209
 * @param   pVM         The VM handle.
 
210
 * @param   pCtxCore    The context core.
 
211
 */
 
212
VMMDECL(uint32_t) PATMRawGetEFlags(PVM pVM, PCCPUMCTXCORE pCtxCore)
 
213
{
 
214
    uint32_t efl = pCtxCore->eflags.u32;
 
215
    efl &= ~PATM_VIRTUAL_FLAGS_MASK;
 
216
    efl |= pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & PATM_VIRTUAL_FLAGS_MASK;
 
217
    return efl;
 
218
}
 
219
 
 
220
/**
 
221
 * Updates the EFLAGS.
 
222
 * This is a worker for CPUMRawSetEFlags().
 
223
 *
 
224
 * @param   pVM         The VM handle.
 
225
 * @param   pCtxCore    The context core.
 
226
 * @param   efl         The new EFLAGS value.
 
227
 */
 
228
VMMDECL(void) PATMRawSetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore, uint32_t efl)
 
229
{
 
230
    pVM->patm.s.CTXSUFF(pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK;
 
231
    efl &= ~PATM_VIRTUAL_FLAGS_MASK;
 
232
    efl |= X86_EFL_IF;
 
233
    pCtxCore->eflags.u32 = efl;
 
234
}
 
235
 
 
236
/**
 
237
 * Check if we must use raw mode (patch code being executed)
 
238
 *
 
239
 * @param   pVM         VM handle.
 
240
 * @param   pAddrGC     Guest context address
 
241
 */
 
242
VMMDECL(bool) PATMShouldUseRawMode(PVM pVM, RTRCPTR pAddrGC)
 
243
{
 
244
    return (    PATMIsEnabled(pVM)
 
245
            && ((pAddrGC >= (RTRCPTR)pVM->patm.s.pPatchMemGC && pAddrGC < (RTRCPTR)((RTRCUINTPTR)pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem)))) ? true : false;
 
246
}
 
247
 
 
248
/**
 
249
 * Returns the guest context pointer and size of the GC context structure
 
250
 *
 
251
 * @returns VBox status code.
 
252
 * @param   pVM         The VM to operate on.
 
253
 */
 
254
VMMDECL(RCPTRTYPE(PPATMGCSTATE)) PATMQueryGCState(PVM pVM)
 
255
{
 
256
    return pVM->patm.s.pGCStateGC;
 
257
}
 
258
 
 
259
/**
 
260
 * Checks whether the GC address is part of our patch region
 
261
 *
 
262
 * @returns VBox status code.
 
263
 * @param   pVM         The VM to operate on.
 
264
 * @param   pAddrGC     Guest context address
 
265
 */
 
266
VMMDECL(bool) PATMIsPatchGCAddr(PVM pVM, RTRCUINTPTR pAddrGC)
 
267
{
 
268
    return (PATMIsEnabled(pVM) && pAddrGC - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem) ? true : false;
 
269
}
 
270
 
 
271
/**
 
272
 * Set parameters for pending MMIO patch operation
 
273
 *
 
274
 * @returns VBox status code.
 
275
 * @param   pDevIns         Device instance.
 
276
 * @param   GCPhys          MMIO physical address
 
277
 * @param   pCachedData     GC pointer to cached data
 
278
 */
 
279
VMMDECL(int) PATMSetMMIOPatchInfo(PVM pVM, RTGCPHYS GCPhys, RTRCPTR pCachedData)
 
280
{
 
281
    pVM->patm.s.mmio.GCPhys = GCPhys;
 
282
    pVM->patm.s.mmio.pCachedData = (RTRCPTR)pCachedData;
 
283
 
 
284
    return VINF_SUCCESS;
 
285
}
 
286
 
 
287
/**
 
288
 * Checks if the interrupt flag is enabled or not.
 
289
 *
 
290
 * @returns true if it's enabled.
 
291
 * @returns false if it's disabled.
 
292
 *
 
293
 * @param   pVM         The VM handle.
 
294
 */
 
295
VMMDECL(bool) PATMAreInterruptsEnabled(PVM pVM)
 
296
{
 
297
    PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu(pVM));
 
298
 
 
299
    return PATMAreInterruptsEnabledByCtxCore(pVM, CPUMCTX2CORE(pCtx));
 
300
}
 
301
 
 
302
/**
 
303
 * Checks if the interrupt flag is enabled or not.
 
304
 *
 
305
 * @returns true if it's enabled.
 
306
 * @returns false if it's disabled.
 
307
 *
 
308
 * @param   pVM         The VM handle.
 
309
 * @param   pCtxCore    CPU context
 
310
 */
 
311
VMMDECL(bool) PATMAreInterruptsEnabledByCtxCore(PVM pVM, PCPUMCTXCORE pCtxCore)
 
312
{
 
313
    if (PATMIsEnabled(pVM))
 
314
    {
 
315
        if (PATMIsPatchGCAddr(pVM, pCtxCore->eip))
 
316
            return false;
 
317
    }
 
318
    return !!(pCtxCore->eflags.u32 & X86_EFL_IF);
 
319
}
 
320
 
 
321
/**
 
322
 * Check if the instruction is patched as a duplicated function
 
323
 *
 
324
 * @returns patch record
 
325
 * @param   pVM         The VM to operate on.
 
326
 * @param   pInstrGC    Guest context point to the instruction
 
327
 *
 
328
 */
 
329
VMMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC)
 
330
{
 
331
    PPATMPATCHREC pRec;
 
332
 
 
333
    AssertCompile(sizeof(AVLOU32KEY) == sizeof(pInstrGC));
 
334
    pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)pInstrGC);
 
335
    if (    pRec
 
336
        && (pRec->patch.uState == PATCH_ENABLED)
 
337
        && (pRec->patch.flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_CALLABLE_AS_FUNCTION))
 
338
       )
 
339
        return pRec;
 
340
    return 0;
 
341
}
 
342
 
 
343
/**
 
344
 * Checks if the int 3 was caused by a patched instruction
 
345
 *
 
346
 * @returns VBox status
 
347
 *
 
348
 * @param   pVM         The VM handle.
 
349
 * @param   pInstrGC    Instruction pointer
 
350
 * @param   pOpcode     Original instruction opcode (out, optional)
 
351
 * @param   pSize       Original instruction size (out, optional)
 
352
 */
 
353
VMMDECL(bool) PATMIsInt3Patch(PVM pVM, RTRCPTR pInstrGC, uint32_t *pOpcode, uint32_t *pSize)
 
354
{
 
355
    PPATMPATCHREC pRec;
 
356
 
 
357
    pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)pInstrGC);
 
358
    if (    pRec
 
359
        && (pRec->patch.uState == PATCH_ENABLED)
 
360
        && (pRec->patch.flags & (PATMFL_INT3_REPLACEMENT|PATMFL_INT3_REPLACEMENT_BLOCK))
 
361
       )
 
362
    {
 
363
        if (pOpcode) *pOpcode = pRec->patch.opcode;
 
364
        if (pSize)   *pSize   = pRec->patch.cbPrivInstr;
 
365
        return true;
 
366
    }
 
367
    return false;
 
368
}
 
369
 
 
370
/**
 
371
 * Emulate sysenter, sysexit and syscall instructions
 
372
 *
 
373
 * @returns VBox status
 
374
 *
 
375
 * @param   pVM         The VM handle.
 
376
 * @param   pCtxCore    The relevant core context.
 
377
 * @param   pCpu        Disassembly context
 
378
 */
 
379
VMMDECL(int) PATMSysCall(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
 
380
{
 
381
    PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu0(pVM));
 
382
 
 
383
    if (pCpu->pCurInstr->opcode == OP_SYSENTER)
 
384
    {
 
385
        if (    pCtx->SysEnter.cs == 0
 
386
            ||  pRegFrame->eflags.Bits.u1VM
 
387
            ||  (pRegFrame->cs & X86_SEL_RPL) != 3
 
388
            ||  pVM->patm.s.pfnSysEnterPatchGC == 0
 
389
            ||  pVM->patm.s.pfnSysEnterGC != (RTRCPTR)(RTRCUINTPTR)pCtx->SysEnter.eip
 
390
            ||  !(PATMRawGetEFlags(pVM, pRegFrame) & X86_EFL_IF))
 
391
            goto end;
 
392
 
 
393
        Log2(("PATMSysCall: sysenter from %RRv to %RRv\n", pRegFrame->eip, pVM->patm.s.pfnSysEnterPatchGC));
 
394
        /** @todo the base and limit are forced to 0 & 4G-1 resp. We assume the selector is wide open here. */
 
395
        /** @note The Intel manual suggests that the OS is responsible for this. */
 
396
        pRegFrame->cs          = (pCtx->SysEnter.cs & ~X86_SEL_RPL) | 1;
 
397
        pRegFrame->eip         = /** @todo ugly conversion! */(uint32_t)pVM->patm.s.pfnSysEnterPatchGC;
 
398
        pRegFrame->ss          = pRegFrame->cs + 8;     /* SysEnter.cs + 8 */
 
399
        pRegFrame->esp         = pCtx->SysEnter.esp;
 
400
        pRegFrame->eflags.u32 &= ~(X86_EFL_VM|X86_EFL_RF);
 
401
        pRegFrame->eflags.u32 |= X86_EFL_IF;
 
402
 
 
403
        /* Turn off interrupts. */
 
404
        pVM->patm.s.CTXSUFF(pGCState)->uVMFlags &= ~X86_EFL_IF;
 
405
 
 
406
        STAM_COUNTER_INC(&pVM->patm.s.StatSysEnter);
 
407
 
 
408
        return VINF_SUCCESS;
 
409
    }
 
410
    else
 
411
    if (pCpu->pCurInstr->opcode == OP_SYSEXIT)
 
412
    {
 
413
        if (    pCtx->SysEnter.cs == 0
 
414
            ||  (pRegFrame->cs & X86_SEL_RPL) != 1
 
415
            ||  pRegFrame->eflags.Bits.u1VM
 
416
            ||  !(PATMRawGetEFlags(pVM, pRegFrame) & X86_EFL_IF))
 
417
            goto end;
 
418
 
 
419
        Log2(("PATMSysCall: sysexit from %RRv to %RRv\n", pRegFrame->eip, pRegFrame->edx));
 
420
 
 
421
        pRegFrame->cs          = ((pCtx->SysEnter.cs + 16) & ~X86_SEL_RPL) | 3;
 
422
        pRegFrame->eip         = pRegFrame->edx;
 
423
        pRegFrame->ss          = pRegFrame->cs + 8;  /* SysEnter.cs + 24 */
 
424
        pRegFrame->esp         = pRegFrame->ecx;
 
425
 
 
426
        STAM_COUNTER_INC(&pVM->patm.s.StatSysExit);
 
427
 
 
428
        return VINF_SUCCESS;
 
429
    }
 
430
    else
 
431
    if (pCpu->pCurInstr->opcode == OP_SYSCALL)
 
432
    {
 
433
        /** @todo implement syscall */
 
434
    }
 
435
    else
 
436
    if (pCpu->pCurInstr->opcode == OP_SYSRET)
 
437
    {
 
438
        /** @todo implement sysret */
 
439
    }
 
440
 
 
441
end:
 
442
    return VINF_EM_RAW_RING_SWITCH;
 
443
}
 
444
 
 
445
/**
 
446
 * Adds branch pair to the lookup cache of the particular branch instruction
 
447
 *
 
448
 * @returns VBox status
 
449
 * @param   pVM                 The VM to operate on.
 
450
 * @param   pJumpTableGC        Pointer to branch instruction lookup cache
 
451
 * @param   pBranchTarget       Original branch target
 
452
 * @param   pRelBranchPatch     Relative duplicated function address
 
453
 */
 
454
VMMDECL(int) PATMAddBranchToLookupCache(PVM pVM, RTRCPTR pJumpTableGC, RTRCPTR pBranchTarget, RTRCUINTPTR pRelBranchPatch)
 
455
{
 
456
    PPATCHJUMPTABLE pJumpTable;
 
457
 
 
458
    Log(("PATMAddBranchToLookupCache: Adding (%RRv->%RRv (%RRv)) to table %RRv\n", pBranchTarget, pRelBranchPatch + pVM->patm.s.pPatchMemGC, pRelBranchPatch, pJumpTableGC));
 
459
 
 
460
    AssertReturn(PATMIsPatchGCAddr(pVM, (RTRCUINTPTR)pJumpTableGC), VERR_INVALID_PARAMETER);
 
461
 
 
462
#ifdef IN_RC
 
463
    pJumpTable = (PPATCHJUMPTABLE) pJumpTableGC;
 
464
#else
 
465
    pJumpTable = (PPATCHJUMPTABLE) (pJumpTableGC - pVM->patm.s.pPatchMemGC + pVM->patm.s.pPatchMemHC);
 
466
#endif
 
467
    Log(("Nr addresses = %d, insert pos = %d\n", pJumpTable->cAddresses, pJumpTable->ulInsertPos));
 
468
    if (pJumpTable->cAddresses < pJumpTable->nrSlots)
 
469
    {
 
470
        uint32_t i;
 
471
 
 
472
        for (i=0;i<pJumpTable->nrSlots;i++)
 
473
        {
 
474
            if (pJumpTable->Slot[i].pInstrGC == 0)
 
475
            {
 
476
                pJumpTable->Slot[i].pInstrGC    = pBranchTarget;
 
477
                /* Relative address - eases relocation */
 
478
                pJumpTable->Slot[i].pRelPatchGC = pRelBranchPatch;
 
479
                pJumpTable->cAddresses++;
 
480
                break;
 
481
            }
 
482
        }
 
483
        AssertReturn(i < pJumpTable->nrSlots, VERR_INTERNAL_ERROR);
 
484
#ifdef VBOX_WITH_STATISTICS
 
485
        STAM_COUNTER_INC(&pVM->patm.s.StatFunctionLookupInsert);
 
486
        if (pVM->patm.s.StatU32FunctionMaxSlotsUsed < i)
 
487
            pVM->patm.s.StatU32FunctionMaxSlotsUsed = i + 1;
 
488
#endif
 
489
    }
 
490
    else
 
491
    {
 
492
        /* Replace an old entry. */
 
493
        /** @todo replacement strategy isn't really bright. change to something better if required. */
 
494
        Assert(pJumpTable->ulInsertPos < pJumpTable->nrSlots);
 
495
        Assert((pJumpTable->nrSlots & 1) == 0);
 
496
 
 
497
        pJumpTable->ulInsertPos &= (pJumpTable->nrSlots-1);
 
498
        pJumpTable->Slot[pJumpTable->ulInsertPos].pInstrGC    = pBranchTarget;
 
499
        /* Relative address - eases relocation */
 
500
        pJumpTable->Slot[pJumpTable->ulInsertPos].pRelPatchGC = pRelBranchPatch;
 
501
 
 
502
        pJumpTable->ulInsertPos = (pJumpTable->ulInsertPos+1) & (pJumpTable->nrSlots-1);
 
503
 
 
504
        STAM_COUNTER_INC(&pVM->patm.s.StatFunctionLookupReplace);
 
505
    }
 
506
 
 
507
    return VINF_SUCCESS;
 
508
}
 
509
 
 
510
 
 
511
#if defined(VBOX_WITH_STATISTICS) || defined(LOG_ENABLED)
 
512
/**
 
513
 * Return the name of the patched instruction
 
514
 *
 
515
 * @returns instruction name
 
516
 *
 
517
 * @param   opcode      DIS instruction opcode
 
518
 * @param   fPatchFlags Patch flags
 
519
 */
 
520
VMMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags)
 
521
{
 
522
    const char *pszInstr = NULL;
 
523
 
 
524
    switch (opcode)
 
525
    {
 
526
    case OP_CLI:
 
527
        pszInstr = "cli";
 
528
        break;
 
529
    case OP_PUSHF:
 
530
        pszInstr = "pushf";
 
531
        break;
 
532
    case OP_POPF:
 
533
        pszInstr = "popf";
 
534
        break;
 
535
    case OP_STR:
 
536
        pszInstr = "str";
 
537
        break;
 
538
    case OP_LSL:
 
539
        pszInstr = "lsl";
 
540
        break;
 
541
    case OP_LAR:
 
542
        pszInstr = "lar";
 
543
        break;
 
544
    case OP_SGDT:
 
545
        pszInstr = "sgdt";
 
546
        break;
 
547
    case OP_SLDT:
 
548
        pszInstr = "sldt";
 
549
        break;
 
550
    case OP_SIDT:
 
551
        pszInstr = "sidt";
 
552
        break;
 
553
    case OP_SMSW:
 
554
        pszInstr = "smsw";
 
555
        break;
 
556
    case OP_VERW:
 
557
        pszInstr = "verw";
 
558
        break;
 
559
    case OP_VERR:
 
560
        pszInstr = "verr";
 
561
        break;
 
562
    case OP_CPUID:
 
563
        pszInstr = "cpuid";
 
564
        break;
 
565
    case OP_JMP:
 
566
        pszInstr = "jmp";
 
567
        break;
 
568
    case OP_JO:
 
569
        pszInstr = "jo";
 
570
        break;
 
571
    case OP_JNO:
 
572
        pszInstr = "jno";
 
573
        break;
 
574
    case OP_JC:
 
575
        pszInstr = "jc";
 
576
        break;
 
577
    case OP_JNC:
 
578
        pszInstr = "jnc";
 
579
        break;
 
580
    case OP_JE:
 
581
        pszInstr = "je";
 
582
        break;
 
583
    case OP_JNE:
 
584
        pszInstr = "jne";
 
585
        break;
 
586
    case OP_JBE:
 
587
        pszInstr = "jbe";
 
588
        break;
 
589
    case OP_JNBE:
 
590
        pszInstr = "jnbe";
 
591
        break;
 
592
    case OP_JS:
 
593
        pszInstr = "js";
 
594
        break;
 
595
    case OP_JNS:
 
596
        pszInstr = "jns";
 
597
        break;
 
598
    case OP_JP:
 
599
        pszInstr = "jp";
 
600
        break;
 
601
    case OP_JNP:
 
602
        pszInstr = "jnp";
 
603
        break;
 
604
    case OP_JL:
 
605
        pszInstr = "jl";
 
606
        break;
 
607
    case OP_JNL:
 
608
        pszInstr = "jnl";
 
609
        break;
 
610
    case OP_JLE:
 
611
        pszInstr = "jle";
 
612
        break;
 
613
    case OP_JNLE:
 
614
        pszInstr = "jnle";
 
615
        break;
 
616
    case OP_JECXZ:
 
617
        pszInstr = "jecxz";
 
618
        break;
 
619
    case OP_LOOP:
 
620
        pszInstr = "loop";
 
621
        break;
 
622
    case OP_LOOPNE:
 
623
        pszInstr = "loopne";
 
624
        break;
 
625
    case OP_LOOPE:
 
626
        pszInstr = "loope";
 
627
        break;
 
628
    case OP_MOV:
 
629
        if (fPatchFlags & PATMFL_IDTHANDLER)
 
630
        {
 
631
            pszInstr = "mov (Int/Trap Handler)";
 
632
        }
 
633
        break;
 
634
    case OP_SYSENTER:
 
635
        pszInstr = "sysenter";
 
636
        break;
 
637
    case OP_PUSH:
 
638
        pszInstr = "push (cs)";
 
639
        break;
 
640
    case OP_CALL:
 
641
        pszInstr = "call";
 
642
        break;
 
643
    case OP_IRET:
 
644
        pszInstr = "iret";
 
645
        break;
 
646
    }
 
647
    return pszInstr;
 
648
}
 
649
#endif