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

« back to all changes in this revision

Viewing changes to src/VBox/VMM/VMMGC/TRPMGCHandlers.cpp

  • 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: TRPMGCHandlers.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
 
2
/** @file
 
3
 * TRPM - Guest Context Trap Handlers, CPP part
 
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
 
 
19
/*******************************************************************************
 
20
*   Header Files                                                               *
 
21
*******************************************************************************/
 
22
#define LOG_GROUP LOG_GROUP_TRPM
 
23
#include <VBox/selm.h>
 
24
#include <VBox/iom.h>
 
25
#include <VBox/pgm.h>
 
26
#include <VBox/pdm.h>
 
27
#include <VBox/dbgf.h>
 
28
#include <VBox/em.h>
 
29
#include <VBox/csam.h>
 
30
#include <VBox/patm.h>
 
31
#include <VBox/mm.h>
 
32
#include <VBox/cpum.h>
 
33
#include "TRPMInternal.h"
 
34
#include <VBox/vm.h>
 
35
#include <VBox/param.h>
 
36
 
 
37
#include <VBox/err.h>
 
38
#include <VBox/dis.h>
 
39
#include <VBox/disopcode.h>
 
40
#include <VBox/x86.h>
 
41
#include <VBox/log.h>
 
42
#include <VBox/tm.h>
 
43
#include <iprt/asm.h>
 
44
#include <iprt/assert.h>
 
45
 
 
46
/* still here. MODR/M byte parsing */
 
47
#define X86_OPCODE_MODRM_MOD_MASK       0xc0
 
48
#define X86_OPCODE_MODRM_REG_MASK       0x38
 
49
#define X86_OPCODE_MODRM_RM_MASK        0x07
 
50
 
 
51
/** Pointer to a readonly hypervisor trap record. */
 
52
typedef const struct TRPMGCHYPER *PCTRPMGCHYPER;
 
53
 
 
54
/**
 
55
 * A hypervisor trap record.
 
56
 * This contains information about a handler for a instruction range.
 
57
 *
 
58
 * @remark This must match what TRPM_HANDLER outputs.
 
59
 */
 
60
typedef struct TRPMGCHYPER
 
61
{
 
62
    /** The start address. */
 
63
    uintptr_t uStartEIP;
 
64
    /** The end address. (exclusive)
 
65
     * If NULL the it's only for the instruction at pvStartEIP. */
 
66
    uintptr_t uEndEIP;
 
67
    /**
 
68
     * The handler.
 
69
     *
 
70
     * @returns VBox status code
 
71
     *          VINF_SUCCESS means we've handled the trap.
 
72
     *          Any other error code means returning to the host context.
 
73
     * @param   pVM             The VM handle.
 
74
     * @param   pRegFrame       The register frame.
 
75
     * @param   uUser           The user argument.
 
76
     */
 
77
    DECLCALLBACKMEMBER(int, pfnHandler)(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser);
 
78
    /** Whatever the handler desires to put here. */
 
79
    uintptr_t uUser;
 
80
} TRPMGCHYPER;
 
81
 
 
82
 
 
83
/*******************************************************************************
 
84
*   Global Variables                                                           *
 
85
*******************************************************************************/
 
86
__BEGIN_DECLS
 
87
/** Defined in VMMGC0.asm or VMMGC99.asm.
 
88
 * @{ */
 
89
extern const TRPMGCHYPER g_aTrap0bHandlers[1];
 
90
extern const TRPMGCHYPER g_aTrap0bHandlersEnd[1];
 
91
extern const TRPMGCHYPER g_aTrap0dHandlers[1];
 
92
extern const TRPMGCHYPER g_aTrap0dHandlersEnd[1];
 
93
extern const TRPMGCHYPER g_aTrap0eHandlers[1];
 
94
extern const TRPMGCHYPER g_aTrap0eHandlersEnd[1];
 
95
/** @} */
 
96
__END_DECLS
 
97
 
 
98
 
 
99
/*******************************************************************************
 
100
*   Internal Functions                                                         *
 
101
*******************************************************************************/
 
102
__BEGIN_DECLS /* addressed from asm (not called so no DECLASM). */
 
103
DECLCALLBACK(int) trpmGCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser);
 
104
__END_DECLS
 
105
 
 
106
 
 
107
 
 
108
/**
 
109
 * Exits the trap, called when exiting a trap handler.
 
110
 *
 
111
 * Will reset the trap if it's not a guest trap or the trap
 
112
 * is already handled. Will process resume guest FFs.
 
113
 *
 
114
 * @returns rc.
 
115
 * @param   pVM         VM handle.
 
116
 * @param   rc          The VBox status code to return.
 
117
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
118
 */
 
119
static int trpmGCExitTrap(PVM pVM, int rc, PCPUMCTXCORE pRegFrame)
 
120
{
 
121
    uint32_t uOldActiveVector = pVM->trpm.s.uActiveVector;
 
122
    NOREF(uOldActiveVector);
 
123
 
 
124
    /* Reset trap? */
 
125
    if (    rc != VINF_EM_RAW_GUEST_TRAP
 
126
        &&  rc != VINF_EM_RAW_RING_SWITCH_INT)
 
127
        pVM->trpm.s.uActiveVector = ~0;
 
128
 
 
129
#ifdef VBOX_HIGH_RES_TIMERS_HACK
 
130
    /*
 
131
     * Occationally we should poll timers.
 
132
     * We must *NOT* do this too frequently as it adds a significant overhead
 
133
     * and it'll kill us if the trap load is high. (See #1354.)
 
134
     * (The heuristic is not very intelligent, we should really check trap
 
135
     * frequency etc. here, but alas, we lack any such information atm.)
 
136
     */
 
137
    static unsigned s_iTimerPoll = 0;
 
138
    if (rc == VINF_SUCCESS)
 
139
    {
 
140
        if (!(++s_iTimerPoll & 0xf))
 
141
        {
 
142
            uint64_t cTicks = TMTimerPoll(pVM); NOREF(cTicks);
 
143
            Log2(("TMTimerPoll at %VGv returned %RX64 (VM_FF_TIMER=%d)\n", pRegFrame->eip, cTicks, VM_FF_ISPENDING(pVM, VM_FF_TIMER)));
 
144
        }
 
145
    }
 
146
    else
 
147
        s_iTimerPoll = 0;
 
148
#endif
 
149
 
 
150
    /* Clear pending inhibit interrupt state if required. (necessary for dispatching interrupts later on) */
 
151
    if (VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
 
152
    {
 
153
        Log2(("VM_FF_INHIBIT_INTERRUPTS at %VGv successor %VGv\n", pRegFrame->eip, EMGetInhibitInterruptsPC(pVM)));
 
154
        if (pRegFrame->eip != EMGetInhibitInterruptsPC(pVM))
 
155
        {
 
156
            /** @note we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here if the eip is the same as the inhibited instr address.
 
157
             *  Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
 
158
             *  force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
 
159
             *  break the guest. Sounds very unlikely, but such timing sensitive problem are not as rare as you might think.
 
160
             */
 
161
            VM_FF_CLEAR(pVM, VM_FF_INHIBIT_INTERRUPTS);
 
162
        }
 
163
    }
 
164
 
 
165
    /*
 
166
     * Pending resume-guest-FF?
 
167
     * Or pending (A)PIC interrupt? Windows XP will crash if we delay APIC interrupts.
 
168
     */
 
169
    if (    rc == VINF_SUCCESS
 
170
        &&  VM_FF_ISPENDING(pVM, VM_FF_TO_R3 | VM_FF_TIMER | VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL | VM_FF_REQUEST))
 
171
    {
 
172
        /* Pending Ring-3 action. */
 
173
        if (VM_FF_ISPENDING(pVM, VM_FF_TO_R3))
 
174
        {
 
175
            VM_FF_CLEAR(pVM, VM_FF_TO_R3);
 
176
            rc = VINF_EM_RAW_TO_R3;
 
177
        }
 
178
        /* Pending timer action. */
 
179
        else if (VM_FF_ISPENDING(pVM, VM_FF_TIMER))
 
180
            rc = VINF_EM_RAW_TIMER_PENDING;
 
181
        /* Pending interrupt: dispatch it. */
 
182
        else if (    VM_FF_ISPENDING(pVM, VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC)
 
183
                 && !VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS)
 
184
                 &&  PATMAreInterruptsEnabledByCtxCore(pVM, pRegFrame)
 
185
           )
 
186
        {
 
187
            uint8_t u8Interrupt;
 
188
            rc = PDMGetInterrupt(pVM, &u8Interrupt);
 
189
            Log(("trpmGCExitTrap: u8Interrupt=%d (%#x) rc=%Vrc\n", u8Interrupt, u8Interrupt, rc));
 
190
            AssertFatalMsgRC(rc, ("PDMGetInterrupt failed with %Vrc\n", rc));
 
191
            rc = TRPMForwardTrap(pVM, pRegFrame, (uint32_t)u8Interrupt, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_HARDWARE_INT);
 
192
            /* can't return if successful */
 
193
            Assert(rc != VINF_SUCCESS);
 
194
 
 
195
            /* Stop the profile counter that was started in TRPMGCHandlersA.asm */
 
196
            Assert(uOldActiveVector <= 16);
 
197
            STAM_PROFILE_ADV_STOP(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
 
198
 
 
199
            /* Assert the trap and go to the recompiler to dispatch it. */
 
200
            TRPMAssertTrap(pVM, u8Interrupt, TRPM_HARDWARE_INT);
 
201
 
 
202
            STAM_PROFILE_ADV_START(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
 
203
            rc = VINF_EM_RAW_INTERRUPT_PENDING;
 
204
        }
 
205
        /*
 
206
         * Try sync CR3?
 
207
         * This ASSUMES that the MOV CRx, x emulation doesn't return with VINF_PGM_SYNC_CR3. (a bit hackish)
 
208
         */
 
209
        else if (VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL))
 
210
#if 1
 
211
            rc = PGMSyncCR3(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR3(pVM), CPUMGetGuestCR4(pVM), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3));
 
212
#else
 
213
            rc = VINF_PGM_SYNC_CR3;
 
214
#endif
 
215
        /* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
 
216
        else if (VM_FF_ISPENDING(pVM, VM_FF_REQUEST))
 
217
            rc = VINF_EM_PENDING_REQUEST;
 
218
    }
 
219
 
 
220
    AssertMsg(     rc != VINF_SUCCESS
 
221
              ||   (   pRegFrame->eflags.Bits.u1IF
 
222
                    && ( pRegFrame->eflags.Bits.u2IOPL < (unsigned)(pRegFrame->ss & X86_SEL_RPL) || pRegFrame->eflags.Bits.u1VM))
 
223
              , ("rc = %VGv\neflags=%RX32 ss=%RTsel IOPL=%d\n", rc, pRegFrame->eflags.u32, pRegFrame->ss, pRegFrame->eflags.Bits.u2IOPL));
 
224
    return rc;
 
225
}
 
226
 
 
227
 
 
228
/**
 
229
 * \#DB (Debug event) handler.
 
230
 *
 
231
 * @returns VBox status code.
 
232
 *          VINF_SUCCESS means we completely handled this trap,
 
233
 *          other codes are passed execution to host context.
 
234
 *
 
235
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
236
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
237
 * @internal
 
238
 */
 
239
DECLASM(int) TRPMGCTrap01Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
240
{
 
241
    RTGCUINTREG uDr6 = ASMGetAndClearDR6();
 
242
    PVM pVM = TRPM2VM(pTrpm);
 
243
    LogFlow(("TRPMGCTrap01Handler: cs:eip=%04x:%08x uDr6=%RTreg\n", pRegFrame->cs, pRegFrame->eip, uDr6));
 
244
 
 
245
    /*
 
246
     * We currently don't make sure of the X86_DR7_GD bit, but
 
247
     * there might come a time when we do.
 
248
     */
 
249
    if ((uDr6 & X86_DR6_BD) == X86_DR6_BD)
 
250
    {
 
251
        AssertReleaseMsgFailed(("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n",
 
252
                                ASMGetDR7(), CPUMGetHyperDR7(pVM), uDr6));
 
253
        return VERR_NOT_IMPLEMENTED;
 
254
    }
 
255
 
 
256
    AssertReleaseMsg(!(uDr6 & X86_DR6_BT), ("X86_DR6_BT is impossible!\n"));
 
257
 
 
258
    /*
 
259
     * Now leave the rest to the DBGF.
 
260
     */
 
261
    int rc = DBGFGCTrap01Handler(pVM, pRegFrame, uDr6);
 
262
    if (rc == VINF_EM_RAW_GUEST_TRAP)
 
263
        CPUMSetGuestDR6(pVM, uDr6);
 
264
 
 
265
    return trpmGCExitTrap(pVM, rc, pRegFrame);
 
266
}
 
267
 
 
268
 
 
269
 
 
270
/**
 
271
 * NMI handler, for when we are using NMIs to debug things.
 
272
 *
 
273
 * @returns VBox status code.
 
274
 *          VINF_SUCCESS means we completely handled this trap,
 
275
 *          other codes are passed execution to host context.
 
276
 *
 
277
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
278
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
279
 * @internal
 
280
 * @remark  This is not hooked up unless you're building with VBOX_WITH_NMI defined.
 
281
 */
 
282
DECLASM(int) TRPMGCTrap02Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
283
{
 
284
    LogFlow(("TRPMGCTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
 
285
    RTLogComPrintf("TRPMGCTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip);
 
286
    return VERR_TRPM_DONT_PANIC;
 
287
}
 
288
 
 
289
 
 
290
/**
 
291
 * \#BP (Breakpoint) handler.
 
292
 *
 
293
 * @returns VBox status code.
 
294
 *          VINF_SUCCESS means we completely handled this trap,
 
295
 *          other codes are passed execution to host context.
 
296
 *
 
297
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
298
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
299
 * @internal
 
300
 */
 
301
DECLASM(int) TRPMGCTrap03Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
302
{
 
303
    LogFlow(("TRPMGCTrap03Handler: cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
 
304
    PVM pVM = TRPM2VM(pTrpm);
 
305
    int rc;
 
306
 
 
307
    /*
 
308
     * Both PATM are using INT3s, let them have a go first.
 
309
     */
 
310
    if (    (pRegFrame->ss & X86_SEL_RPL) == 1
 
311
        &&  !pRegFrame->eflags.Bits.u1VM)
 
312
    {
 
313
        rc = PATMHandleInt3PatchTrap(pVM, pRegFrame);
 
314
        if (rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_PATCH_INT3 || rc == VINF_PATM_DUPLICATE_FUNCTION)
 
315
            return trpmGCExitTrap(pVM, rc, pRegFrame);
 
316
    }
 
317
    rc = DBGFGCTrap03Handler(pVM, pRegFrame);
 
318
    /* anything we should do with this? Schedule it in GC? */
 
319
    return trpmGCExitTrap(pVM, rc, pRegFrame);
 
320
}
 
321
 
 
322
 
 
323
/**
 
324
 * Trap handler for illegal opcode fault (\#UD).
 
325
 *
 
326
 * @returns VBox status code.
 
327
 *          VINF_SUCCESS means we completely handled this trap,
 
328
 *          other codes are passed execution to host context.
 
329
 *
 
330
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
331
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
332
 * @internal
 
333
 */
 
334
DECLASM(int) TRPMGCTrap06Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
335
{
 
336
    PVM pVM = TRPM2VM(pTrpm);
 
337
    int rc;
 
338
 
 
339
    LogFlow(("TRPMGCTrap06Handler %VGv eflags=%x\n", pRegFrame->eip, pRegFrame->eflags.u32));
 
340
 
 
341
    if (CPUMGetGuestCPL(pVM, pRegFrame) == 0)
 
342
    {
 
343
        /*
 
344
         * Decode the instruction.
 
345
         */
 
346
        RTGCPTR PC;
 
347
        rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
 
348
        if (VBOX_FAILURE(rc))
 
349
        {
 
350
            Log(("TRPMGCTrap06Handler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n", pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
 
351
            return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
 
352
        }
 
353
 
 
354
        DISCPUSTATE Cpu;
 
355
        uint32_t    cbOp;
 
356
        rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
 
357
        if (VBOX_FAILURE(rc))
 
358
            return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
 
359
 
 
360
        if (    PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip)
 
361
            &&  Cpu.pCurInstr->opcode == OP_ILLUD2)
 
362
        {
 
363
            rc = PATMGCHandleIllegalInstrTrap(pVM, pRegFrame);
 
364
            if (rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_DUPLICATE_FUNCTION || rc == VINF_PATM_PENDING_IRQ_AFTER_IRET || rc == VINF_EM_RESCHEDULE)
 
365
                return trpmGCExitTrap(pVM, rc, pRegFrame);
 
366
        }
 
367
        else
 
368
        /** Note: monitor causes an #UD exception instead of #GP when not executed in ring 0. */
 
369
        if (Cpu.pCurInstr->opcode == OP_MONITOR)
 
370
        {
 
371
            uint32_t cbIgnored;
 
372
            rc = EMInterpretInstructionCPU(pVM, &Cpu, pRegFrame, PC, &cbIgnored);
 
373
            if (RT_LIKELY(VBOX_SUCCESS(rc)))
 
374
                pRegFrame->eip += Cpu.opsize;
 
375
        }
 
376
        else
 
377
            /* Never generate a raw trap here; it might be an instruction, that requires emulation. */
 
378
            rc = VINF_EM_RAW_EMULATE_INSTR;
 
379
    }
 
380
    else
 
381
    {
 
382
        rc = TRPMForwardTrap(pVM, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP);
 
383
        Assert(rc == VINF_EM_RAW_GUEST_TRAP);
 
384
    }
 
385
 
 
386
    return trpmGCExitTrap(pVM, rc, pRegFrame);
 
387
}
 
388
 
 
389
 
 
390
/**
 
391
 * Trap handler for device not present fault (\#NM).
 
392
 *
 
393
 * Device not available, FP or (F)WAIT instruction.
 
394
 *
 
395
 * @returns VBox status code.
 
396
 *          VINF_SUCCESS means we completely handled this trap,
 
397
 *          other codes are passed execution to host context.
 
398
 *
 
399
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
400
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
401
 * @internal
 
402
 */
 
403
DECLASM(int) TRPMGCTrap07Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
404
{
 
405
    PVM pVM = TRPM2VM(pTrpm);
 
406
 
 
407
    LogFlow(("TRPMTrap07HandlerGC: eip=%VGv\n", pRegFrame->eip));
 
408
    return CPUMHandleLazyFPU(pVM);
 
409
}
 
410
 
 
411
 
 
412
/**
 
413
 * \#NP ((segment) Not Present) handler.
 
414
 *
 
415
 * @returns VBox status code.
 
416
 *          VINF_SUCCESS means we completely handled this trap,
 
417
 *          other codes are passed execution to host context.
 
418
 *
 
419
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
420
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
421
 * @internal
 
422
 */
 
423
DECLASM(int) TRPMGCTrap0bHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
424
{
 
425
    LogFlow(("TRPMGCTrap0bHandler: eip=%VGv\n", pRegFrame->eip));
 
426
    PVM pVM = TRPM2VM(pTrpm);
 
427
 
 
428
    /*
 
429
     * Try to detect instruction by opcode which caused trap.
 
430
     * XXX note: this code may cause \#PF (trap e) or \#GP (trap d) while
 
431
     * accessing user code. need to handle it somehow in future!
 
432
     */
 
433
    uint8_t *pu8Code;
 
434
    if (SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, (PRTGCPTR)&pu8Code) == VINF_SUCCESS)
 
435
    {
 
436
        /*
 
437
         * First skip possible instruction prefixes, such as:
 
438
         *      OS, AS
 
439
         *      CS:, DS:, ES:, SS:, FS:, GS:
 
440
         *      REPE, REPNE
 
441
         *
 
442
         * note: Currently we supports only up to 4 prefixes per opcode, more
 
443
         *       prefixes (normally not used anyway) will cause trap d in guest.
 
444
         * note: Instruction length in IA-32 may be up to 15 bytes, we dont
 
445
         *       check this issue, its too hard.
 
446
         */
 
447
        for (unsigned i = 0; i < 4; i++)
 
448
        {
 
449
            if (    pu8Code[0] != 0xf2     /* REPNE/REPNZ */
 
450
                &&  pu8Code[0] != 0xf3     /* REP/REPE/REPZ */
 
451
                &&  pu8Code[0] != 0x2e     /* CS: */
 
452
                &&  pu8Code[0] != 0x36     /* SS: */
 
453
                &&  pu8Code[0] != 0x3e     /* DS: */
 
454
                &&  pu8Code[0] != 0x26     /* ES: */
 
455
                &&  pu8Code[0] != 0x64     /* FS: */
 
456
                &&  pu8Code[0] != 0x65     /* GS: */
 
457
                &&  pu8Code[0] != 0x66     /* OS */
 
458
                &&  pu8Code[0] != 0x67     /* AS */
 
459
               )
 
460
                break;
 
461
            pu8Code++;
 
462
        }
 
463
 
 
464
        /*
 
465
         * Detect right switch using a callgate.
 
466
         *
 
467
         * We recognize the following causes for the trap 0b:
 
468
         *      CALL FAR, CALL FAR []
 
469
         *      JMP FAR, JMP FAR []
 
470
         *      IRET (may cause a task switch)
 
471
         *
 
472
         * Note: we can't detect whether the trap was caused by a call to a
 
473
         *       callgate descriptor or it is a real trap 0b due to a bad selector.
 
474
         *       In both situations we'll pass execution to our recompiler so we don't
 
475
         *       have to worry.
 
476
         *       If we wanted to do better detection, we have set GDT entries to callgate
 
477
         *       descriptors pointing to our own handlers.
 
478
         */
 
479
        /** @todo not sure about IRET, may generate Trap 0d (\#GP), NEED TO CHECK! */
 
480
        if (    pu8Code[0] == 0x9a       /* CALL FAR */
 
481
            ||  (    pu8Code[0] == 0xff  /* CALL FAR [] */
 
482
                 && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x18)
 
483
            ||  pu8Code[0] == 0xea       /* JMP FAR */
 
484
            ||  (    pu8Code[0] == 0xff  /* JMP FAR [] */
 
485
                 && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x28)
 
486
            ||  pu8Code[0] == 0xcf       /* IRET */
 
487
           )
 
488
        {
 
489
            /*
 
490
             * Got potential call to callgate.
 
491
             * We simply return execution to the recompiler to do emulation
 
492
             * starting from the instruction which caused the trap.
 
493
             */
 
494
            pTrpm->uActiveVector = ~0;
 
495
            return VINF_EM_RAW_RING_SWITCH;
 
496
        }
 
497
    }
 
498
 
 
499
    /*
 
500
     * Pass trap 0b as is to the recompiler in all other cases.
 
501
     */
 
502
    return VINF_EM_RAW_GUEST_TRAP;
 
503
}
 
504
 
 
505
 
 
506
/**
 
507
 * \#GP (General Protection Fault) handler for Ring-0 privileged instructions.
 
508
 *
 
509
 * @returns VBox status code.
 
510
 *          VINF_SUCCESS means we completely handled this trap,
 
511
 *          other codes are passed execution to host context.
 
512
 *
 
513
 * @param   pVM         The VM handle.
 
514
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
515
 * @param   pCpu        The opcode info.
 
516
 * @param   PC          The program counter corresponding to cs:eip in pRegFrame.
 
517
 */
 
518
static int trpmGCTrap0dHandlerRing0(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
 
519
{
 
520
    int rc;
 
521
 
 
522
    /*
 
523
     * Try handle it here, if not return to HC and emulate/interpret it there.
 
524
     */
 
525
    switch (pCpu->pCurInstr->opcode)
 
526
    {
 
527
        case OP_INT3:
 
528
            /*
 
529
             * Little hack to make the code below not fail
 
530
             */
 
531
            pCpu->param1.flags  = USE_IMMEDIATE8;
 
532
            pCpu->param1.parval = 3;
 
533
            /* fallthru */
 
534
        case OP_INT:
 
535
        {
 
536
            Assert(pCpu->param1.flags & USE_IMMEDIATE8);
 
537
            Assert(!(PATMIsPatchGCAddr(pVM, PC)));
 
538
            if (pCpu->param1.parval == 3)
 
539
            {
 
540
                /* Int 3 replacement patch? */
 
541
                if (PATMHandleInt3PatchTrap(pVM, pRegFrame) == VINF_SUCCESS)
 
542
                {
 
543
                    AssertFailed();
 
544
                    return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
 
545
                }
 
546
            }
 
547
            rc = TRPMForwardTrap(pVM, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT);
 
548
            if (VBOX_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
 
549
                return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
 
550
 
 
551
            pVM->trpm.s.uActiveVector = (pVM->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
 
552
            pVM->trpm.s.enmActiveType = TRPM_SOFTWARE_INT;
 
553
            return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
 
554
        }
 
555
 
 
556
#ifdef PATM_EMULATE_SYSENTER
 
557
        case OP_SYSEXIT:
 
558
        case OP_SYSRET:
 
559
            rc = PATMSysCall(pVM, pRegFrame, pCpu);
 
560
            return trpmGCExitTrap(pVM, rc, pRegFrame);
 
561
#endif
 
562
 
 
563
        case OP_HLT:
 
564
            /* If it's in patch code, defer to ring-3. */
 
565
            if (PATMIsPatchGCAddr(pVM, PC))
 
566
                break;
 
567
 
 
568
            pRegFrame->eip += pCpu->opsize;
 
569
            return trpmGCExitTrap(pVM, VINF_EM_HALT, pRegFrame);
 
570
 
 
571
 
 
572
        /*
 
573
         * These instructions are used by PATM and CASM for finding
 
574
         * dangerous non-trapping instructions. Thus, since all
 
575
         * scanning and patching is done in ring-3 we'll have to
 
576
         * return to ring-3 on the first encounter of these instructions.
 
577
         */
 
578
        case OP_MOV_CR:
 
579
        case OP_MOV_DR:
 
580
            /* We can safely emulate control/debug register move instructions in patched code. */
 
581
            if (    !PATMIsPatchGCAddr(pVM, PC)
 
582
                &&  !CSAMIsKnownDangerousInstr(pVM, PC))
 
583
                break;
 
584
        case OP_INVLPG:
 
585
        case OP_LLDT:
 
586
        case OP_STI:
 
587
        case OP_RDTSC:
 
588
        case OP_CLTS:
 
589
        {
 
590
            uint32_t cbIgnored;
 
591
            rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, PC, &cbIgnored);
 
592
            if (VBOX_SUCCESS(rc))
 
593
                pRegFrame->eip += pCpu->opsize;
 
594
            else if (rc == VERR_EM_INTERPRETER)
 
595
                rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
 
596
            return trpmGCExitTrap(pVM, rc, pRegFrame);
 
597
        }
 
598
    }
 
599
 
 
600
    return trpmGCExitTrap(pVM, VINF_EM_RAW_EXCEPTION_PRIVILEGED, pRegFrame);
 
601
}
 
602
 
 
603
 
 
604
/**
 
605
 * \#GP (General Protection Fault) handler for Ring-3.
 
606
 *
 
607
 * @returns VBox status code.
 
608
 *          VINF_SUCCESS means we completely handled this trap,
 
609
 *          other codes are passed execution to host context.
 
610
 *
 
611
 * @param   pVM         The VM handle.
 
612
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
613
 * @param   pCpu        The opcode info.
 
614
 * @param   PC          The program counter corresponding to cs:eip in pRegFrame.
 
615
 */
 
616
static int trpmGCTrap0dHandlerRing3(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
 
617
{
 
618
    int rc;
 
619
 
 
620
    Assert(!pRegFrame->eflags.Bits.u1VM);
 
621
 
 
622
    switch (pCpu->pCurInstr->opcode)
 
623
    {
 
624
        /*
 
625
         * STI and CLI are I/O privileged, i.e. if IOPL
 
626
         */
 
627
        case OP_STI:
 
628
        case OP_CLI:
 
629
        {
 
630
            uint32_t efl = CPUMRawGetEFlags(pVM, pRegFrame);
 
631
            if (X86_EFL_GET_IOPL(efl) >= (unsigned)(pRegFrame->ss & X86_SEL_RPL))
 
632
            {
 
633
                LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> REM\n"));
 
634
                return trpmGCExitTrap(pVM, VINF_EM_RESCHEDULE_REM, pRegFrame);
 
635
            }
 
636
            LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> #GP(0)\n"));
 
637
            break;
 
638
        }
 
639
 
 
640
        /*
 
641
         * INT3 and INT xx are ring-switching.
 
642
         * (The shadow IDT will have set the entries to DPL=0, that's why we're here.)
 
643
         */
 
644
        case OP_INT3:
 
645
            /*
 
646
             * Little hack to make the code below not fail
 
647
             */
 
648
            pCpu->param1.flags  = USE_IMMEDIATE8;
 
649
            pCpu->param1.parval = 3;
 
650
            /* fall thru */
 
651
        case OP_INT:
 
652
        {
 
653
            Assert(pCpu->param1.flags & USE_IMMEDIATE8);
 
654
            rc = TRPMForwardTrap(pVM, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT);
 
655
            if (VBOX_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
 
656
                return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
 
657
 
 
658
            pVM->trpm.s.uActiveVector = (pVM->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
 
659
            pVM->trpm.s.enmActiveType = TRPM_SOFTWARE_INT;
 
660
            return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
 
661
        }
 
662
 
 
663
        /*
 
664
         * SYSCALL, SYSENTER, INTO and BOUND are also ring-switchers.
 
665
         */
 
666
        case OP_SYSCALL:
 
667
        case OP_SYSENTER:
 
668
#ifdef PATM_EMULATE_SYSENTER
 
669
            rc = PATMSysCall(pVM, pRegFrame, pCpu);
 
670
            if (rc == VINF_SUCCESS)
 
671
                return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
 
672
            /* else no break; */
 
673
#endif
 
674
        case OP_BOUND:
 
675
        case OP_INTO:
 
676
            pVM->trpm.s.uActiveVector = ~0;
 
677
            return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH, pRegFrame);
 
678
 
 
679
        /*
 
680
         * Handle virtualized TSC reads.
 
681
         */
 
682
        case OP_RDTSC:
 
683
        {
 
684
            uint32_t cbIgnored;
 
685
            rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, PC, &cbIgnored);
 
686
            if (VBOX_SUCCESS(rc))
 
687
                pRegFrame->eip += pCpu->opsize;
 
688
            else if (rc == VERR_EM_INTERPRETER)
 
689
                rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
 
690
            return trpmGCExitTrap(pVM, rc, pRegFrame);
 
691
        }
 
692
    }
 
693
 
 
694
    /*
 
695
     * A genuine guest fault.
 
696
     */
 
697
    return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
 
698
}
 
699
 
 
700
 
 
701
/**
 
702
 * \#GP (General Protection Fault) handler.
 
703
 *
 
704
 * @returns VBox status code.
 
705
 *          VINF_SUCCESS means we completely handled this trap,
 
706
 *          other codes are passed execution to host context.
 
707
 *
 
708
 * @param   pVM         The VM handle.
 
709
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
710
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
711
 */
 
712
static int trpmGCTrap0dHandler(PVM pVM, PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
713
{
 
714
    LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%VGv uErr=%RX32\n", pRegFrame->ss, pRegFrame->eip, pTrpm->uActiveErrorCode));
 
715
 
 
716
#if 0 /* not right for iret. Shouldn't really be needed as SELMValidateAndConvertCSAddr deals with invalid cs. */
 
717
    /*
 
718
     * Filter out selector problems first as these may mean that the
 
719
     * instruction isn't safe to read. If we're here because CS is NIL
 
720
     * the flattening of cs:eip will deal with that.
 
721
     */
 
722
    if (    !(pTrpm->uActiveErrorCode & (X86_TRAP_ERR_IDT | X86_TRAP_ERR_EXTERNAL))
 
723
        &&  (pTrpm->uActiveErrorCode & X86_TRAP_ERR_SEL_MASK))
 
724
    {
 
725
        /* It's a guest trap. */
 
726
        return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
 
727
    }
 
728
#endif
 
729
 
 
730
    STAM_PROFILE_ADV_START(&pVM->trpm.s.StatTrap0dDisasm, a);
 
731
    /*
 
732
     * Decode the instruction.
 
733
     */
 
734
    RTGCPTR PC;
 
735
    int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
 
736
    if (VBOX_FAILURE(rc))
 
737
    {
 
738
        Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
 
739
             pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
 
740
        STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
 
741
        return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
 
742
    }
 
743
 
 
744
    DISCPUSTATE Cpu;
 
745
    uint32_t    cbOp;
 
746
    rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
 
747
    if (VBOX_FAILURE(rc))
 
748
    {
 
749
        STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
 
750
        return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
 
751
    }
 
752
    STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
 
753
 
 
754
    /*
 
755
     * Deal with I/O port access.
 
756
     */
 
757
    if (    pVM->trpm.s.uActiveErrorCode == 0
 
758
        &&  (Cpu.pCurInstr->optype & OPTYPE_PORTIO))
 
759
    {
 
760
        rc = EMInterpretPortIO(pVM, pRegFrame, &Cpu, cbOp);
 
761
        return trpmGCExitTrap(pVM, rc, pRegFrame);
 
762
    }
 
763
 
 
764
 
 
765
    /*
 
766
     * Deal with Ring-0 (privileged instructions)
 
767
     */
 
768
    if (    (pRegFrame->ss & X86_SEL_RPL) <= 1
 
769
        &&  !pRegFrame->eflags.Bits.u1VM)
 
770
        return trpmGCTrap0dHandlerRing0(pVM, pRegFrame, &Cpu, PC);
 
771
 
 
772
    /*
 
773
     * Deal with Ring-3 GPs.
 
774
     */
 
775
    if (!pRegFrame->eflags.Bits.u1VM)
 
776
        return trpmGCTrap0dHandlerRing3(pVM, pRegFrame, &Cpu, PC);
 
777
 
 
778
    /*
 
779
     * Deal with v86 code.
 
780
     */
 
781
 
 
782
    /* We always set IOPL to zero which makes e.g. pushf fault in V86 mode. The guest might use IOPL=3 and therefor not expect a #GP.
 
783
     * Simply fall back to the recompiler to emulate this instruction.
 
784
     */
 
785
    /* Retrieve the eflags including the virtualized bits. */
 
786
    /** @note hackish as the cpumctxcore structure doesn't contain the right value */
 
787
    X86EFLAGS eflags;
 
788
    eflags.u32 = CPUMRawGetEFlags(pVM, pRegFrame);
 
789
    if (eflags.Bits.u2IOPL != 3)
 
790
    {
 
791
        Assert(eflags.Bits.u2IOPL == 0);
 
792
 
 
793
        int rc = TRPMForwardTrap(pVM, pRegFrame, 0xD, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP);
 
794
        Assert(rc == VINF_EM_RAW_GUEST_TRAP);
 
795
        return trpmGCExitTrap(pVM, rc, pRegFrame);
 
796
    }
 
797
    return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
 
798
}
 
799
 
 
800
 
 
801
/**
 
802
 * \#GP (General Protection Fault) handler.
 
803
 *
 
804
 * @returns VBox status code.
 
805
 *          VINF_SUCCESS means we completely handled this trap,
 
806
 *          other codes are passed execution to host context.
 
807
 *
 
808
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
809
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
810
 * @internal
 
811
 */
 
812
DECLASM(int) TRPMGCTrap0dHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
813
{
 
814
    LogFlow(("TRPMGCTrap0dHandler: eip=%RGv\n", pRegFrame->eip));
 
815
    PVM pVM = TRPM2VM(pTrpm);
 
816
 
 
817
    int rc = trpmGCTrap0dHandler(pVM, pTrpm, pRegFrame);
 
818
    switch (rc)
 
819
    {
 
820
        case VINF_EM_RAW_GUEST_TRAP:
 
821
        case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
 
822
            if (PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
 
823
                rc = VINF_PATM_PATCH_TRAP_GP;
 
824
            break;
 
825
 
 
826
        case VINF_EM_RAW_INTERRUPT_PENDING:
 
827
            Assert(TRPMHasTrap(pVM));
 
828
            /* no break; */
 
829
        case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
 
830
        case VINF_IOM_HC_IOPORT_READ:
 
831
        case VINF_IOM_HC_IOPORT_WRITE:
 
832
        case VINF_IOM_HC_MMIO_WRITE:
 
833
        case VINF_IOM_HC_MMIO_READ:
 
834
        case VINF_IOM_HC_MMIO_READ_WRITE:
 
835
        case VINF_PATM_PATCH_INT3:
 
836
        case VINF_EM_RAW_TO_R3:
 
837
        case VINF_EM_RAW_TIMER_PENDING:
 
838
        case VINF_EM_PENDING_REQUEST:
 
839
        case VINF_EM_HALT:
 
840
        case VINF_SUCCESS:
 
841
            break;
 
842
 
 
843
        default:
 
844
            AssertMsg(PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip) == false, ("return code %d\n", rc));
 
845
            break;
 
846
        }
 
847
    return rc;
 
848
}
 
849
 
 
850
/**
 
851
 * \#PF (Page Fault) handler.
 
852
 *
 
853
 * Calls PGM which does the actual handling.
 
854
 *
 
855
 *
 
856
 * @returns VBox status code.
 
857
 *          VINF_SUCCESS means we completely handled this trap,
 
858
 *          other codes are passed execution to host context.
 
859
 *
 
860
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
861
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
862
 * @internal
 
863
 */
 
864
DECLASM(int) TRPMGCTrap0eHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
865
{
 
866
    LogBird(("TRPMGCTrap0eHandler: eip=%RGv\n", pRegFrame->eip));
 
867
    PVM pVM = TRPM2VM(pTrpm);
 
868
 
 
869
    /*
 
870
     * This is all PGM stuff.
 
871
     */
 
872
    int rc = PGMTrap0eHandler(pVM, pTrpm->uActiveErrorCode, pRegFrame, (RTGCPTR)pTrpm->uActiveCR2);
 
873
 
 
874
    switch (rc)
 
875
    {
 
876
    case VINF_EM_RAW_EMULATE_INSTR:
 
877
    case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT:
 
878
    case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
 
879
    case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
 
880
    case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
 
881
    case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
 
882
        if (PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
 
883
            rc = VINF_PATCH_EMULATE_INSTR;
 
884
        break;
 
885
 
 
886
    case VINF_EM_RAW_GUEST_TRAP:
 
887
        if (PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
 
888
            return VINF_PATM_PATCH_TRAP_PF;
 
889
 
 
890
        rc = TRPMForwardTrap(pVM, pRegFrame, 0xE, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP);
 
891
        Assert(rc == VINF_EM_RAW_GUEST_TRAP);
 
892
        break;
 
893
 
 
894
    case VINF_EM_RAW_INTERRUPT_PENDING:
 
895
        Assert(TRPMHasTrap(pVM));
 
896
        /* no break; */
 
897
    case VINF_IOM_HC_MMIO_READ:
 
898
    case VINF_IOM_HC_MMIO_WRITE:
 
899
    case VINF_IOM_HC_MMIO_READ_WRITE:
 
900
    case VINF_PATM_HC_MMIO_PATCH_READ:
 
901
    case VINF_PATM_HC_MMIO_PATCH_WRITE:
 
902
    case VINF_SUCCESS:
 
903
    case VINF_EM_RAW_TO_R3:
 
904
    case VINF_EM_PENDING_REQUEST:
 
905
    case VINF_EM_RAW_TIMER_PENDING:
 
906
    case VINF_CSAM_PENDING_ACTION:
 
907
    case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
 
908
        break;
 
909
 
 
910
    default:
 
911
        AssertMsg(PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip) == false, ("Patch address for return code %d. eip=%08x\n", rc, pRegFrame->eip));
 
912
        break;
 
913
    }
 
914
    return trpmGCExitTrap(pVM, rc, pRegFrame);
 
915
}
 
916
 
 
917
 
 
918
/**
 
919
 * Scans for the EIP in the specified array of trap handlers.
 
920
 *
 
921
 * If we don't fine the EIP, we'll panic.
 
922
 *
 
923
 * @returns VBox status code.
 
924
 *
 
925
 * @param   pVM         The VM handle.
 
926
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
927
 * @param   paHandlers  The array of trap handler records.
 
928
 * @param   pEndRecord  The end record (exclusive).
 
929
 */
 
930
static int trpmGCHyperGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, PCTRPMGCHYPER paHandlers, PCTRPMGCHYPER pEndRecord)
 
931
{
 
932
    uintptr_t uEip  = (uintptr_t)pRegFrame->eip;
 
933
    Assert(paHandlers <= pEndRecord);
 
934
 
 
935
    Log(("trpmGCHyperGeneric: uEip=%x %p-%p\n", uEip, paHandlers, pEndRecord));
 
936
 
 
937
#if 0 /// @todo later
 
938
    /*
 
939
     * Start by doing a kind of binary search.
 
940
     */
 
941
    unsigned iStart = 0;
 
942
    unsigned iEnd   = pEndRecord - paHandlers;
 
943
    unsigned i      = iEnd / 2;
 
944
#endif
 
945
 
 
946
    /*
 
947
     * Do a linear search now (in case the array wasn't properly sorted).
 
948
     */
 
949
    for (PCTRPMGCHYPER pCur = paHandlers; pCur < pEndRecord; pCur++)
 
950
    {
 
951
        if (    pCur->uStartEIP <= uEip
 
952
            &&  (pCur->uEndEIP ? pCur->uEndEIP > uEip : pCur->uStartEIP == uEip))
 
953
            return pCur->pfnHandler(pVM, pRegFrame, pCur->uUser);
 
954
    }
 
955
 
 
956
    return VERR_TRPM_DONT_PANIC;
 
957
}
 
958
 
 
959
 
 
960
/**
 
961
 * Hypervisor \#NP ((segment) Not Present) handler.
 
962
 *
 
963
 * Scans for the EIP in the registered trap handlers.
 
964
 *
 
965
 * @returns VBox status code.
 
966
 *          VINF_SUCCESS means we completely handled this trap,
 
967
 *          other codes are passed back to host context.
 
968
 *
 
969
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
970
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
971
 * @internal
 
972
 */
 
973
DECLASM(int) TRPMGCHyperTrap0bHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
974
{
 
975
    return trpmGCHyperGeneric(TRPM2VM(pTrpm), pRegFrame, g_aTrap0bHandlers, g_aTrap0bHandlersEnd);
 
976
}
 
977
 
 
978
 
 
979
/**
 
980
 * Hypervisor \#GP (General Protection Fault) handler.
 
981
 *
 
982
 * Scans for the EIP in the registered trap handlers.
 
983
 *
 
984
 * @returns VBox status code.
 
985
 *          VINF_SUCCESS means we completely handled this trap,
 
986
 *          other codes are passed back to host context.
 
987
 *
 
988
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
989
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
990
 * @internal
 
991
 */
 
992
DECLASM(int) TRPMGCHyperTrap0dHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
993
{
 
994
    return trpmGCHyperGeneric(TRPM2VM(pTrpm), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
 
995
}
 
996
 
 
997
 
 
998
/**
 
999
 * Hypervisor \#PF (Page Fault) handler.
 
1000
 *
 
1001
 * Scans for the EIP in the registered trap handlers.
 
1002
 *
 
1003
 * @returns VBox status code.
 
1004
 *          VINF_SUCCESS means we completely handled this trap,
 
1005
 *          other codes are passed back to host context.
 
1006
 *
 
1007
 * @param   pTrpm       Pointer to TRPM data (within VM).
 
1008
 * @param   pRegFrame   Pointer to the register frame for the trap.
 
1009
 * @internal
 
1010
 */
 
1011
DECLASM(int) TRPMGCHyperTrap0eHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
 
1012
{
 
1013
    return trpmGCHyperGeneric(TRPM2VM(pTrpm), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
 
1014
}
 
1015
 
 
1016
 
 
1017
/**
 
1018
 * Deal with hypervisor traps occuring when resuming execution on a trap.
 
1019
 *
 
1020
 * @returns VBox status code.
 
1021
 * @param   pVM         The VM handle.
 
1022
 * @param   pRegFrame   Register frame.
 
1023
 * @param   uUser       User arg.
 
1024
 */
 
1025
DECLCALLBACK(int) trpmGCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
 
1026
{
 
1027
    Log(("********************************************************\n"));
 
1028
    Log(("trpmGCTrapInGeneric: eip=%RX32 uUser=%#x\n", pRegFrame->eip, uUser));
 
1029
    Log(("********************************************************\n"));
 
1030
 
 
1031
    if (uUser & TRPM_TRAP_IN_HYPER)
 
1032
    {
 
1033
        /*
 
1034
         * Check that there is still some stack left, if not we'll flag
 
1035
         * a guru meditation (the alternative is a triple fault).
 
1036
         */
 
1037
        RTGCUINTPTR cbStackUsed = (RTGCUINTPTR)VMMGetStackGC(pVM) - pRegFrame->esp;
 
1038
        if (cbStackUsed > VMM_STACK_SIZE - _1K)
 
1039
        {
 
1040
            LogRel(("trpmGCTrapInGeneric: ran out of stack: esp=#x cbStackUsed=%#x\n", pRegFrame->esp, cbStackUsed));
 
1041
            return VERR_TRPM_DONT_PANIC;
 
1042
        }
 
1043
 
 
1044
        /*
 
1045
         * Just zero the register containing the selector in question.
 
1046
         * We'll deal with the actual stale or troublesome selector value in
 
1047
         * the outermost trap frame.
 
1048
         */
 
1049
        switch (uUser & TRPM_TRAP_IN_OP_MASK)
 
1050
        {
 
1051
            case TRPM_TRAP_IN_MOV_GS:
 
1052
                pRegFrame->eax = 0;
 
1053
                pRegFrame->gs = 0; /* prevent recursive trouble. */
 
1054
                break;
 
1055
            case TRPM_TRAP_IN_MOV_FS:
 
1056
                pRegFrame->eax = 0;
 
1057
                pRegFrame->fs = 0; /* prevent recursive trouble. */
 
1058
                return VINF_SUCCESS;
 
1059
 
 
1060
            default:
 
1061
                AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
 
1062
                return VERR_INTERNAL_ERROR;
 
1063
        }
 
1064
    }
 
1065
    else
 
1066
    {
 
1067
        /*
 
1068
         * Reconstruct the guest context and switch to the recompiler.
 
1069
         * We ASSUME we're only at
 
1070
         */
 
1071
        CPUMCTXCORE  CtxCore = *pRegFrame;
 
1072
        uint32_t    *pEsp = (uint32_t *)pRegFrame->esp;
 
1073
        int          rc;
 
1074
 
 
1075
        switch (uUser)
 
1076
        {
 
1077
            /*
 
1078
             * This will only occur when resuming guest code in a trap handler!
 
1079
             */
 
1080
            /* @note ASSUMES esp points to the temporary guest CPUMCTXCORE!!! */
 
1081
            case TRPM_TRAP_IN_MOV_GS:
 
1082
            case TRPM_TRAP_IN_MOV_FS:
 
1083
            case TRPM_TRAP_IN_MOV_ES:
 
1084
            case TRPM_TRAP_IN_MOV_DS:
 
1085
            {
 
1086
                PCPUMCTXCORE pTempGuestCtx = (PCPUMCTXCORE)pEsp;
 
1087
 
 
1088
                /* Just copy the whole thing; several selector registers, eip (etc) and eax are not yet in pRegFrame. */
 
1089
                CtxCore = *pTempGuestCtx;
 
1090
                rc = VINF_EM_RAW_STALE_SELECTOR;
 
1091
                break;
 
1092
            }
 
1093
 
 
1094
            /*
 
1095
             * This will only occur when resuming guest code!
 
1096
             */
 
1097
            case TRPM_TRAP_IN_IRET:
 
1098
                CtxCore.eip = *pEsp++;
 
1099
                CtxCore.cs = (RTSEL)*pEsp++;
 
1100
                CtxCore.eflags.u32 = *pEsp++;
 
1101
                CtxCore.esp = *pEsp++;
 
1102
                CtxCore.ss = (RTSEL)*pEsp++;
 
1103
                rc = VINF_EM_RAW_IRET_TRAP;
 
1104
                break;
 
1105
 
 
1106
            /*
 
1107
             * This will only occur when resuming V86 guest code!
 
1108
             */
 
1109
            case TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86:
 
1110
                CtxCore.eip = *pEsp++;
 
1111
                CtxCore.cs = (RTSEL)*pEsp++;
 
1112
                CtxCore.eflags.u32 = *pEsp++;
 
1113
                CtxCore.esp = *pEsp++;
 
1114
                CtxCore.ss = (RTSEL)*pEsp++;
 
1115
                CtxCore.es = (RTSEL)*pEsp++;
 
1116
                CtxCore.ds = (RTSEL)*pEsp++;
 
1117
                CtxCore.fs = (RTSEL)*pEsp++;
 
1118
                CtxCore.gs = (RTSEL)*pEsp++;
 
1119
                rc = VINF_EM_RAW_IRET_TRAP;
 
1120
                break;
 
1121
 
 
1122
            default:
 
1123
                AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
 
1124
                return VERR_INTERNAL_ERROR;
 
1125
        }
 
1126
 
 
1127
 
 
1128
        CPUMSetGuestCtxCore(pVM, &CtxCore);
 
1129
        TRPMGCHyperReturnToHost(pVM, rc);
 
1130
    }
 
1131
 
 
1132
    AssertMsgFailed(("Impossible!\n"));
 
1133
    return VERR_INTERNAL_ERROR;
 
1134
}
 
1135