VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp@ 62481

Last change on this file since 62481 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 56.8 KB
Line 
1/* $Id: TRPMRCHandlers.cpp 62478 2016-07-22 18:29:06Z vboxsync $ */
2/** @file
3 * TRPM - Raw-mode Context Trap Handlers, CPP part
4 */
5
6/*
7 * Copyright (C) 2006-2016 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_TRPM
23#include <VBox/vmm/selm.h>
24#include <VBox/vmm/iom.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/pdmapi.h>
27#include <VBox/vmm/dbgf.h>
28#include <VBox/vmm/em.h>
29#include <VBox/vmm/gim.h>
30#ifdef VBOX_WITH_NEW_APIC
31# include <VBox/vmm/apic.h>
32#endif
33#include <VBox/vmm/csam.h>
34#include <VBox/vmm/patm.h>
35#include <VBox/vmm/mm.h>
36#include <VBox/vmm/cpum.h>
37#include "TRPMInternal.h"
38#include <VBox/vmm/vm.h>
39#include <VBox/vmm/vmm.h>
40#include <VBox/param.h>
41
42#include <VBox/err.h>
43#include <VBox/dis.h>
44#include <VBox/disopcode.h>
45#include <VBox/log.h>
46#include <VBox/vmm/tm.h>
47#include <iprt/asm.h>
48#include <iprt/asm-amd64-x86.h>
49#include <iprt/assert.h>
50#include <iprt/x86.h>
51
52
53/*********************************************************************************************************************************
54* Defined Constants And Macros *
55*********************************************************************************************************************************/
56/* still here. MODR/M byte parsing */
57#define X86_OPCODE_MODRM_MOD_MASK 0xc0
58#define X86_OPCODE_MODRM_REG_MASK 0x38
59#define X86_OPCODE_MODRM_RM_MASK 0x07
60
61/** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
62#define DTRACE_EXPERIMENT
63
64#if 1
65# define TRPM_ENTER_DBG_HOOK(a_iVector) do {} while (0)
66# define TRPM_EXIT_DBG_HOOK(a_iVector) do {} while (0)
67# define TRPM_ENTER_DBG_HOOK_HYPER(a_iVector) do {} while (0)
68# define TRPM_EXIT_DBG_HOOK_HYPER(a_iVector) do {} while (0)
69#else
70# define TRPM_ENTER_DBG_HOOK(a_iVector) \
71 uint32_t const fDbgEFlags1 = CPUMRawGetEFlags(pVCpu); \
72 if (!(fDbgEFlags1 & X86_EFL_IF)) Log(("%s: IF=0 ##\n", __FUNCTION__)); \
73 else do {} while (0)
74# define TRPM_EXIT_DBG_HOOK(a_iVector) \
75 do { \
76 uint32_t const fDbgEFlags2 = CPUMRawGetEFlags(pVCpu); \
77 if ((fDbgEFlags1 ^ fDbgEFlags2) & (X86_EFL_IF | X86_EFL_IOPL)) \
78 Log(("%s: IF=%d->%d IOPL=%d->%d !#\n", __FUNCTION__, \
79 !!(fDbgEFlags1 & X86_EFL_IF), !!(fDbgEFlags2 & X86_EFL_IF), \
80 X86_EFL_GET_IOPL(fDbgEFlags1), X86_EFL_GET_IOPL(fDbgEFlags2) )); \
81 else if (!(fDbgEFlags2 & X86_EFL_IF)) Log(("%s: IF=0 [ret] ##\n", __FUNCTION__)); \
82 } while (0)
83# define TRPM_ENTER_DBG_HOOK_HYPER(a_iVector) do {} while (0)
84# define TRPM_EXIT_DBG_HOOK_HYPER(a_iVector) do {} while (0)
85#endif
86
87
88/*********************************************************************************************************************************
89* Structures and Typedefs *
90*********************************************************************************************************************************/
91/** Pointer to a readonly hypervisor trap record. */
92typedef const struct TRPMGCHYPER *PCTRPMGCHYPER;
93
94/**
95 * A hypervisor trap record.
96 * This contains information about a handler for a instruction range.
97 *
98 * @remark This must match what TRPM_HANDLER outputs.
99 */
100typedef struct TRPMGCHYPER
101{
102 /** The start address. */
103 uintptr_t uStartEIP;
104 /** The end address. (exclusive)
105 * If NULL the it's only for the instruction at pvStartEIP. */
106 uintptr_t uEndEIP;
107 /**
108 * The handler.
109 *
110 * @returns VBox status code
111 * VINF_SUCCESS means we've handled the trap.
112 * Any other error code means returning to the host context.
113 * @param pVM The cross context VM structure.
114 * @param pRegFrame The register frame.
115 * @param uUser The user argument.
116 */
117 DECLRCCALLBACKMEMBER(int, pfnHandler, (PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser));
118 /** Whatever the handler desires to put here. */
119 uintptr_t uUser;
120} TRPMGCHYPER;
121
122
123/*********************************************************************************************************************************
124* Global Variables *
125*********************************************************************************************************************************/
126RT_C_DECLS_BEGIN
127/** Defined in VMMRC0.asm or VMMRC99.asm.
128 * @{ */
129extern const TRPMGCHYPER g_aTrap0bHandlers[1];
130extern const TRPMGCHYPER g_aTrap0bHandlersEnd[1];
131extern const TRPMGCHYPER g_aTrap0dHandlers[1];
132extern const TRPMGCHYPER g_aTrap0dHandlersEnd[1];
133extern const TRPMGCHYPER g_aTrap0eHandlers[1];
134extern const TRPMGCHYPER g_aTrap0eHandlersEnd[1];
135/** @} */
136RT_C_DECLS_END
137
138
139/*********************************************************************************************************************************
140* Internal Functions *
141*********************************************************************************************************************************/
142RT_C_DECLS_BEGIN /* addressed from asm (not called so no DECLASM). */
143DECLCALLBACK(int) trpmRCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser);
144RT_C_DECLS_END
145
146
147
148/**
149 * Exits the trap, called when exiting a trap handler.
150 *
151 * Will reset the trap if it's not a guest trap or the trap
152 * is already handled. Will process resume guest FFs.
153 *
154 * @returns rc, can be adjusted if its VINF_SUCCESS or something really bad
155 * happened.
156 * @param pVM The cross context VM structure.
157 * @param pVCpu The cross context virtual CPU structure.
158 * @param rc The VBox status code to return.
159 * @param pRegFrame Pointer to the register frame for the trap.
160 *
161 * @remarks This must not be used for hypervisor traps, only guest traps.
162 */
163static int trpmGCExitTrap(PVM pVM, PVMCPU pVCpu, int rc, PCPUMCTXCORE pRegFrame)
164{
165 uint32_t uOldActiveVector = pVCpu->trpm.s.uActiveVector;
166 NOREF(uOldActiveVector);
167
168 /* Reset trap? */
169 if ( rc != VINF_EM_RAW_GUEST_TRAP
170 && rc != VINF_EM_RAW_RING_SWITCH_INT)
171 pVCpu->trpm.s.uActiveVector = UINT32_MAX;
172
173#ifdef VBOX_HIGH_RES_TIMERS_HACK
174 /*
175 * We should poll the timers occasionally.
176 * We must *NOT* do this too frequently as it adds a significant overhead
177 * and it'll kill us if the trap load is high. (See @bugref{1354}.)
178 * (The heuristic is not very intelligent, we should really check trap
179 * frequency etc. here, but alas, we lack any such information atm.)
180 */
181 static unsigned s_iTimerPoll = 0;
182 if (rc == VINF_SUCCESS)
183 {
184 if (!(++s_iTimerPoll & 0xf))
185 {
186 TMTimerPollVoid(pVM, pVCpu);
187 Log2(("TMTimerPoll at %08RX32 - VM_FF_TM_VIRTUAL_SYNC=%d VM_FF_TM_VIRTUAL_SYNC=%d\n", pRegFrame->eip,
188 VM_FF_IS_PENDING(pVM, VM_FF_TM_VIRTUAL_SYNC), VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TIMER)));
189 }
190 }
191 else
192 s_iTimerPoll = 0;
193#endif
194
195 /* Clear pending inhibit interrupt state if required. (necessary for dispatching interrupts later on) */
196 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
197 {
198 Log2(("VM_FF_INHIBIT_INTERRUPTS at %08RX32 successor %RGv\n", pRegFrame->eip, EMGetInhibitInterruptsPC(pVCpu)));
199 if (pRegFrame->eip != EMGetInhibitInterruptsPC(pVCpu))
200 {
201 /** @note we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here if the eip is the same as the inhibited instr address.
202 * Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
203 * force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
204 * break the guest. Sounds very unlikely, but such timing sensitive problem are not as rare as you might think.
205 */
206 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
207 }
208 }
209
210 /*
211 * Pending resume-guest-FF?
212 * Or pending (A)PIC interrupt? Windows XP will crash if we delay APIC interrupts.
213 */
214 if ( rc == VINF_SUCCESS
215 && ( VM_FF_IS_PENDING(pVM, VM_FF_TM_VIRTUAL_SYNC | VM_FF_REQUEST | VM_FF_PGM_NO_MEMORY | VM_FF_PDM_DMA)
216 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TIMER | VMCPU_FF_TO_R3
217 | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
218 | VMCPU_FF_REQUEST | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
219 | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_IEM | VMCPU_FF_SELM_SYNC_GDT
220 | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT
221 | VMCPU_FF_IOM | VMCPU_FF_CPUM
222 )
223 )
224 )
225 {
226 /* The out of memory condition naturally outranks the others. */
227 if (RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)))
228 rc = VINF_EM_NO_MEMORY;
229 else
230 {
231#ifdef VBOX_WITH_NEW_APIC
232 /* APIC needs updating. */
233 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
234 APICUpdatePendingInterrupts(pVCpu);
235#endif
236 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_CPUM))
237 CPUMRCProcessForceFlag(pVCpu);
238
239 /* Pending Ring-3 action. */
240 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TO_R3 | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_IEM | VMCPU_FF_IOM))
241 {
242 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
243 rc = VINF_EM_RAW_TO_R3;
244 }
245 /* Pending timer action. */
246 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TIMER))
247 rc = VINF_EM_RAW_TIMER_PENDING;
248 /* The Virtual Sync clock has stopped. */
249 else if (VM_FF_IS_PENDING(pVM, VM_FF_TM_VIRTUAL_SYNC))
250 rc = VINF_EM_RAW_TO_R3;
251 /* DMA work pending? */
252 else if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
253 rc = VINF_EM_RAW_TO_R3;
254 /* Pending request packets might contain actions that need immediate
255 attention, such as pending hardware interrupts. */
256 else if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
257 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
258 rc = VINF_EM_PENDING_REQUEST;
259 /* Pending GDT/LDT/TSS sync. */
260 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_SELM_SYNC_TSS))
261 rc = VINF_SELM_SYNC_GDT;
262 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TRPM_SYNC_IDT))
263 rc = VINF_EM_RAW_TO_R3;
264 /* Possibly pending interrupt: dispatch it. */
265 else if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
266 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
267 && PATMAreInterruptsEnabledByCtx(pVM, CPUMCTX_FROM_CORE(pRegFrame))
268 )
269 {
270 uint8_t u8Interrupt;
271 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
272 Log(("trpmGCExitTrap: u8Interrupt=%d (%#x) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
273 if (RT_SUCCESS(rc))
274 {
275 rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)u8Interrupt, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_HARDWARE_INT, uOldActiveVector);
276 /* can't return if successful */
277 Assert(rc != VINF_SUCCESS);
278
279 /* Stop the profile counter that was started in TRPMRCHandlersA.asm */
280 Assert(uOldActiveVector <= 16);
281 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
282
283 /* Assert the trap and go to the recompiler to dispatch it. */
284 TRPMAssertTrap(pVCpu, u8Interrupt, TRPM_HARDWARE_INT);
285
286 STAM_PROFILE_ADV_START(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
287 rc = VINF_EM_RAW_INTERRUPT_PENDING;
288 }
289 else if ( rc == VERR_APIC_INTR_MASKED_BY_TPR /* Can happen if TPR is too high for the newly arrived interrupt. */
290 || rc == VERR_NO_DATA) /* Can happen if the APIC is disabled. */
291 {
292 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
293 rc = VINF_SUCCESS;
294 }
295 else
296 AssertFatalMsgRC(rc, ("PDMGetInterrupt failed. rc=%Rrc\n", rc));
297 }
298 /*
299 * Try sync CR3?
300 */
301 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
302 {
303#if 1
304 PGMRZDynMapReleaseAutoSet(pVCpu);
305 PGMRZDynMapStartAutoSet(pVCpu);
306 rc = PGMSyncCR3(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR3(pVCpu), CPUMGetGuestCR4(pVCpu), VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
307#else
308 rc = VINF_PGM_SYNC_CR3;
309#endif
310 }
311 }
312 }
313
314 /* Note! TRPMRCHandlersA.asm performs sanity checks in debug builds.*/
315 PGMRZDynMapReleaseAutoSet(pVCpu);
316 return rc;
317}
318
319
320/**
321 * \#DB (Debug event) handler.
322 *
323 * @returns VBox status code.
324 * VINF_SUCCESS means we completely handled this trap,
325 * other codes are passed execution to host context.
326 *
327 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
328 * @param pRegFrame Pointer to the register frame for the trap.
329 * @internal
330 */
331DECLASM(int) TRPMGCTrap01Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
332{
333 RTGCUINTREG uDr6 = ASMGetAndClearDR6();
334 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
335 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
336 LogFlow(("TRPMGC01: cs:eip=%04x:%08x uDr6=%RTreg EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, uDr6, CPUMRawGetEFlags(pVCpu)));
337 TRPM_ENTER_DBG_HOOK(1);
338
339 /*
340 * We currently don't make use of the X86_DR7_GD bit, but
341 * there might come a time when we do.
342 */
343 AssertReleaseMsgReturn((uDr6 & X86_DR6_BD) != X86_DR6_BD,
344 ("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n",
345 ASMGetDR7(), CPUMGetHyperDR7(pVCpu), uDr6),
346 VERR_NOT_IMPLEMENTED);
347 AssertReleaseMsg(!(uDr6 & X86_DR6_BT), ("X86_DR6_BT is impossible!\n"));
348
349 /*
350 * Now leave the rest to the DBGF.
351 */
352 PGMRZDynMapStartAutoSet(pVCpu);
353 int rc = DBGFRZTrap01Handler(pVM, pVCpu, pRegFrame, uDr6, false /*fAltStepping*/);
354 if (rc == VINF_EM_RAW_GUEST_TRAP)
355 {
356 CPUMSetGuestDR6(pVCpu, (CPUMGetGuestDR6(pVCpu) & ~X86_DR6_B_MASK) | uDr6);
357 if (CPUMGetGuestDR7(pVCpu) & X86_DR7_GD)
358 CPUMSetGuestDR7(pVCpu, CPUMGetGuestDR7(pVCpu) & ~X86_DR7_GD);
359 }
360 else if (rc == VINF_EM_DBG_STEPPED)
361 pRegFrame->eflags.Bits.u1TF = 0;
362
363 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
364 Log6(("TRPMGC01: %Rrc (%04x:%08x %RTreg EFlag=%#x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, uDr6, CPUMRawGetEFlags(pVCpu)));
365 TRPM_EXIT_DBG_HOOK(1);
366 return rc;
367}
368
369
370/**
371 * \#DB (Debug event) handler for the hypervisor code.
372 *
373 * This is mostly the same as TRPMGCTrap01Handler, but we skip the PGM auto
374 * mapping set as well as the default trap exit path since they are both really
375 * bad ideas in this context.
376 *
377 * @returns VBox status code.
378 * VINF_SUCCESS means we completely handled this trap,
379 * other codes are passed execution to host context.
380 *
381 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
382 * @param pRegFrame Pointer to the register frame for the trap.
383 * @internal
384 */
385DECLASM(int) TRPMGCHyperTrap01Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
386{
387 RTGCUINTREG uDr6 = ASMGetAndClearDR6();
388 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
389 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
390 TRPM_ENTER_DBG_HOOK_HYPER(1);
391 LogFlow(("TRPMGCHyper01: cs:eip=%04x:%08x uDr6=%RTreg\n", pRegFrame->cs.Sel, pRegFrame->eip, uDr6));
392
393 /*
394 * We currently don't make use of the X86_DR7_GD bit, but
395 * there might come a time when we do.
396 */
397 AssertReleaseMsgReturn((uDr6 & X86_DR6_BD) != X86_DR6_BD,
398 ("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n",
399 ASMGetDR7(), CPUMGetHyperDR7(pVCpu), uDr6),
400 VERR_NOT_IMPLEMENTED);
401 AssertReleaseMsg(!(uDr6 & X86_DR6_BT), ("X86_DR6_BT is impossible!\n"));
402
403 /*
404 * Now leave the rest to the DBGF.
405 */
406 int rc = DBGFRZTrap01Handler(pVM, pVCpu, pRegFrame, uDr6, false /*fAltStepping*/);
407 AssertStmt(rc != VINF_EM_RAW_GUEST_TRAP, rc = VERR_TRPM_IPE_1);
408 if (rc == VINF_EM_DBG_STEPPED)
409 pRegFrame->eflags.Bits.u1TF = 0;
410
411 Log6(("TRPMGCHyper01: %Rrc (%04x:%08x %RTreg)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, uDr6));
412 TRPM_EXIT_DBG_HOOK_HYPER(1);
413 return rc;
414}
415
416
417/**
418 * NMI handler, for when we are using NMIs to debug things.
419 *
420 * @returns VBox status code.
421 * VINF_SUCCESS means we completely handled this trap,
422 * other codes are passed execution to host context.
423 *
424 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
425 * @param pRegFrame Pointer to the register frame for the trap.
426 * @internal
427 * @remark This is not hooked up unless you're building with VBOX_WITH_NMI defined.
428 */
429DECLASM(int) TRPMGCTrap02Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
430{
431 LogFlow(("TRPMGCTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip));
432#if 0 /* Enable this iff you have a COM port and really want this debug info. */
433 RTLogComPrintf("TRPMGCTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip);
434#endif
435 NOREF(pTrpmCpu);
436 return VERR_TRPM_DONT_PANIC;
437}
438
439
440/**
441 * NMI handler, for when we are using NMIs to debug things.
442 *
443 * This is the handler we're most likely to hit when the NMI fires (it is
444 * unlikely that we'll be stuck in guest code).
445 *
446 * @returns VBox status code.
447 * VINF_SUCCESS means we completely handled this trap,
448 * other codes are passed execution to host context.
449 *
450 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
451 * @param pRegFrame Pointer to the register frame for the trap.
452 * @internal
453 * @remark This is not hooked up unless you're building with VBOX_WITH_NMI defined.
454 */
455DECLASM(int) TRPMGCHyperTrap02Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
456{
457 LogFlow(("TRPMGCHyperTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip));
458#if 0 /* Enable this iff you have a COM port and really want this debug info. */
459 RTLogComPrintf("TRPMGCHyperTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip);
460#endif
461 NOREF(pTrpmCpu);
462 return VERR_TRPM_DONT_PANIC;
463}
464
465
466/**
467 * \#BP (Breakpoint) handler.
468 *
469 * @returns VBox status code.
470 * VINF_SUCCESS means we completely handled this trap,
471 * other codes are passed execution to host context.
472 *
473 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
474 * @param pRegFrame Pointer to the register frame for the trap.
475 * @internal
476 */
477DECLASM(int) TRPMGCTrap03Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
478{
479 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
480 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
481 int rc;
482 LogFlow(("TRPMGC03: %04x:%08x EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
483 TRPM_ENTER_DBG_HOOK(3);
484 PGMRZDynMapStartAutoSet(pVCpu);
485
486 /*
487 * PATM is using INT3s, let them have a go first.
488 */
489 if ( ( (pRegFrame->ss.Sel & X86_SEL_RPL) == 1
490 || (EMIsRawRing1Enabled(pVM) && (pRegFrame->ss.Sel & X86_SEL_RPL) == 2) )
491 && !pRegFrame->eflags.Bits.u1VM)
492 {
493 rc = PATMRCHandleInt3PatchTrap(pVM, pRegFrame);
494 if ( rc == VINF_SUCCESS
495 || rc == VINF_EM_RESCHEDULE
496 || rc == VINF_EM_RAW_EMULATE_INSTR
497 || rc == VINF_PATM_PATCH_INT3
498 || rc == VINF_PATM_DUPLICATE_FUNCTION )
499 {
500 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
501 Log6(("TRPMGC03: %Rrc (%04x:%08x EFL=%x) (PATM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
502 TRPM_EXIT_DBG_HOOK(3);
503 return rc;
504 }
505 }
506 rc = DBGFRZTrap03Handler(pVM, pVCpu, pRegFrame);
507
508 /* anything we should do with this? Schedule it in GC? */
509 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
510 Log6(("TRPMGC03: %Rrc (%04x:%08x EFL=%x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
511 TRPM_EXIT_DBG_HOOK(3);
512 return rc;
513}
514
515
516/**
517 * \#BP (Breakpoint) handler.
518 *
519 * This is similar to TRPMGCTrap03Handler but we bits which are potentially
520 * harmful to us (common trap exit and the auto mapping set).
521 *
522 * @returns VBox status code.
523 * VINF_SUCCESS means we completely handled this trap,
524 * other codes are passed execution to host context.
525 *
526 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
527 * @param pRegFrame Pointer to the register frame for the trap.
528 * @internal
529 */
530DECLASM(int) TRPMGCHyperTrap03Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
531{
532 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
533 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
534 LogFlow(("TRPMGCHyper03: %04x:%08x EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
535 TRPM_ENTER_DBG_HOOK_HYPER(3);
536
537 /*
538 * Hand it over to DBGF.
539 */
540 int rc = DBGFRZTrap03Handler(pVM, pVCpu, pRegFrame);
541 AssertStmt(rc != VINF_EM_RAW_GUEST_TRAP, rc = VERR_TRPM_IPE_2);
542
543 Log6(("TRPMGCHyper03: %Rrc (%04x:%08x EFL=%x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
544 TRPM_EXIT_DBG_HOOK_HYPER(3);
545 return rc;
546}
547
548
549/**
550 * Trap handler for illegal opcode fault (\#UD).
551 *
552 * @returns VBox status code.
553 * VINF_SUCCESS means we completely handled this trap,
554 * other codes are passed execution to host context.
555 *
556 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
557 * @param pRegFrame Pointer to the register frame for the trap.
558 * @internal
559 */
560DECLASM(int) TRPMGCTrap06Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
561{
562 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
563 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
564 int rc;
565 LogFlow(("TRPMGC06: %04x:%08x EFL=%#x/%#x\n", pRegFrame->cs.Sel, pRegFrame->eip, pRegFrame->eflags.u32, CPUMRawGetEFlags(pVCpu)));
566 TRPM_ENTER_DBG_HOOK(6);
567 PGMRZDynMapStartAutoSet(pVCpu);
568
569 if (CPUMGetGuestCPL(pVCpu) <= (EMIsRawRing1Enabled(pVM) ? 1U : 0U))
570 {
571 /*
572 * Decode the instruction.
573 */
574 RTGCPTR PC;
575 rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs,
576 pRegFrame->rip, &PC);
577 if (RT_FAILURE(rc))
578 {
579 Log(("TRPMGCTrap06Handler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n", pRegFrame->cs.Sel, pRegFrame->eip, pRegFrame->ss.Sel & X86_SEL_RPL, rc));
580 rc = trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
581 Log6(("TRPMGC06: %Rrc (%04x:%08x EFL=%x) (SELM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
582 TRPM_EXIT_DBG_HOOK(6);
583 return rc;
584 }
585
586 DISCPUSTATE Cpu;
587 uint32_t cbOp;
588 rc = EMInterpretDisasOneEx(pVM, pVCpu, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
589 if (RT_FAILURE(rc))
590 {
591 rc = trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
592 Log6(("TRPMGC06: %Rrc (%04x:%08x EFL=%x) (EM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
593 TRPM_EXIT_DBG_HOOK(6);
594 return rc;
595 }
596
597 /*
598 * UD2 in a patch?
599 * Note! PATMGCHandleIllegalInstrTrap doesn't always return.
600 */
601 if ( Cpu.pCurInstr->uOpcode == OP_ILLUD2
602 && PATMIsPatchGCAddr(pVM, pRegFrame->eip))
603 {
604 LogFlow(("TRPMGCTrap06Handler: -> PATMRCHandleIllegalInstrTrap\n"));
605 rc = PATMRCHandleIllegalInstrTrap(pVM, pRegFrame);
606 /** @todo These tests are completely unnecessary, should just follow the
607 * flow and return at the end of the function. */
608 if ( rc == VINF_SUCCESS
609 || rc == VINF_EM_RAW_EMULATE_INSTR
610 || rc == VINF_PATM_DUPLICATE_FUNCTION
611 || rc == VINF_PATM_PENDING_IRQ_AFTER_IRET
612 || rc == VINF_EM_RESCHEDULE)
613 {
614 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
615 Log6(("TRPMGC06: %Rrc (%04x:%08x EFL=%x) (PATM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
616 TRPM_EXIT_DBG_HOOK(6);
617 return rc;
618 }
619 }
620 /*
621 * Speed up dtrace and don't entrust invalid lock sequences to the recompiler.
622 */
623 else if (Cpu.fPrefix & DISPREFIX_LOCK)
624 {
625 Log(("TRPMGCTrap06Handler: pc=%08x op=%d\n", pRegFrame->eip, Cpu.pCurInstr->uOpcode));
626#ifdef DTRACE_EXPERIMENT /** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
627 Assert(!PATMIsPatchGCAddr(pVM, pRegFrame->eip));
628 rc = TRPMForwardTrap(pVCpu, pRegFrame, X86_XCPT_UD, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, X86_XCPT_UD);
629 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
630#else
631 rc = VINF_EM_RAW_EMULATE_INSTR;
632#endif
633 }
634 /*
635 * Handle MONITOR - it causes an #UD exception instead of #GP when not executed in ring 0.
636 */
637 else if (Cpu.pCurInstr->uOpcode == OP_MONITOR)
638 {
639 LogFlow(("TRPMGCTrap06Handler: -> EMInterpretInstructionCPU\n"));
640 rc = VBOXSTRICTRC_TODO(EMInterpretInstructionDisasState(pVCpu, &Cpu, pRegFrame, PC, EMCODETYPE_SUPERVISOR));
641 }
642 else if (GIMShouldTrapXcptUD(pVCpu))
643 {
644 LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD\n"));
645 VBOXSTRICTRC rcStrict = GIMXcptUD(pVCpu, CPUMCTX_FROM_CORE(pRegFrame), &Cpu, NULL /* pcbInstr */);
646 if (rcStrict == VINF_SUCCESS)
647 {
648 /* The interrupt inhibition wrt to EIP will be handled by trpmGCExitTrap() below. */
649 pRegFrame->eip += Cpu.cbInstr;
650 Assert(Cpu.cbInstr);
651 }
652 else if (rcStrict == VINF_GIM_HYPERCALL_CONTINUING)
653 rc = VINF_SUCCESS;
654 else if (rcStrict == VINF_GIM_R3_HYPERCALL)
655 rc = VINF_GIM_R3_HYPERCALL;
656 else
657 {
658 Assert(RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
659 LogFlow(("TRPMGCTrap06Handler: GIMXcptUD returns %Rrc -> VINF_EM_RAW_EMULATE_INSTR\n", rc));
660 rc = VINF_EM_RAW_EMULATE_INSTR;
661 }
662 }
663 /* Never generate a raw trap here; it might be an instruction, that requires emulation. */
664 else
665 {
666 LogFlow(("TRPMGCTrap06Handler: -> VINF_EM_RAW_EMULATE_INSTR\n"));
667 rc = VINF_EM_RAW_EMULATE_INSTR;
668 }
669 }
670 else
671 {
672 LogFlow(("TRPMGCTrap06Handler: -> TRPMForwardTrap\n"));
673 rc = TRPMForwardTrap(pVCpu, pRegFrame, X86_XCPT_UD, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, X86_XCPT_UD);
674 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
675 }
676
677 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
678 Log6(("TRPMGC06: %Rrc (%04x:%08x EFL=%x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
679 TRPM_EXIT_DBG_HOOK(6);
680 return rc;
681}
682
683
684/**
685 * Trap handler for device not present fault (\#NM).
686 *
687 * Device not available, FP or (F)WAIT instruction.
688 *
689 * @returns VBox status code.
690 * VINF_SUCCESS means we completely handled this trap,
691 * other codes are passed execution to host context.
692 *
693 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
694 * @param pRegFrame Pointer to the register frame for the trap.
695 * @internal
696 */
697DECLASM(int) TRPMGCTrap07Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
698{
699 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
700 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
701 LogFlow(("TRPMGC07: %04x:%08x EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
702 TRPM_ENTER_DBG_HOOK(7);
703 PGMRZDynMapStartAutoSet(pVCpu);
704
705 int rc = CPUMHandleLazyFPU(pVCpu);
706 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
707 Log6(("TRPMGC07: %Rrc (%04x:%08x EFL=%x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
708 TRPM_EXIT_DBG_HOOK(7);
709 return rc;
710}
711
712
713/**
714 * \#NP ((segment) Not Present) handler.
715 *
716 * @returns VBox status code.
717 * VINF_SUCCESS means we completely handled this trap,
718 * other codes are passed execution to host context.
719 *
720 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
721 * @param pRegFrame Pointer to the register frame for the trap.
722 * @internal
723 */
724DECLASM(int) TRPMGCTrap0bHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
725{
726 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
727 LogFlow(("TRPMGC0b: %04x:%08x EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
728 TRPM_ENTER_DBG_HOOK(0xb);
729 PGMRZDynMapStartAutoSet(pVCpu);
730
731 /*
732 * Try to detect instruction by opcode which caused trap.
733 * XXX note: this code may cause \#PF (trap e) or \#GP (trap d) while
734 * accessing user code. need to handle it somehow in future!
735 */
736 RTGCPTR GCPtr;
737 if ( SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs,
738 (RTGCPTR)pRegFrame->eip, &GCPtr)
739 == VINF_SUCCESS)
740 {
741 uint8_t *pu8Code = (uint8_t *)(uintptr_t)GCPtr;
742
743 /*
744 * First skip possible instruction prefixes, such as:
745 * OS, AS
746 * CS:, DS:, ES:, SS:, FS:, GS:
747 * REPE, REPNE
748 *
749 * note: Currently we supports only up to 4 prefixes per opcode, more
750 * prefixes (normally not used anyway) will cause trap d in guest.
751 * note: Instruction length in IA-32 may be up to 15 bytes, we dont
752 * check this issue, its too hard.
753 */
754 for (unsigned i = 0; i < 4; i++)
755 {
756 if ( pu8Code[0] != 0xf2 /* REPNE/REPNZ */
757 && pu8Code[0] != 0xf3 /* REP/REPE/REPZ */
758 && pu8Code[0] != 0x2e /* CS: */
759 && pu8Code[0] != 0x36 /* SS: */
760 && pu8Code[0] != 0x3e /* DS: */
761 && pu8Code[0] != 0x26 /* ES: */
762 && pu8Code[0] != 0x64 /* FS: */
763 && pu8Code[0] != 0x65 /* GS: */
764 && pu8Code[0] != 0x66 /* OS */
765 && pu8Code[0] != 0x67 /* AS */
766 )
767 break;
768 pu8Code++;
769 }
770
771 /*
772 * Detect right switch using a callgate.
773 *
774 * We recognize the following causes for the trap 0b:
775 * CALL FAR, CALL FAR []
776 * JMP FAR, JMP FAR []
777 * IRET (may cause a task switch)
778 *
779 * Note: we can't detect whether the trap was caused by a call to a
780 * callgate descriptor or it is a real trap 0b due to a bad selector.
781 * In both situations we'll pass execution to our recompiler so we don't
782 * have to worry.
783 * If we wanted to do better detection, we have set GDT entries to callgate
784 * descriptors pointing to our own handlers.
785 */
786 /** @todo not sure about IRET, may generate Trap 0d (\#GP), NEED TO CHECK! */
787 if ( pu8Code[0] == 0x9a /* CALL FAR */
788 || ( pu8Code[0] == 0xff /* CALL FAR [] */
789 && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x18)
790 || pu8Code[0] == 0xea /* JMP FAR */
791 || ( pu8Code[0] == 0xff /* JMP FAR [] */
792 && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x28)
793 || pu8Code[0] == 0xcf /* IRET */
794 )
795 {
796 /*
797 * Got potential call to callgate.
798 * We simply return execution to the recompiler to do emulation
799 * starting from the instruction which caused the trap.
800 */
801 pTrpmCpu->uActiveVector = UINT32_MAX;
802 Log6(("TRPMGC0b: %Rrc (%04x:%08x EFL=%x) (CG)\n", VINF_EM_RAW_RING_SWITCH, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
803 TRPM_EXIT_DBG_HOOK(0xb);
804 PGMRZDynMapReleaseAutoSet(pVCpu);
805 return VINF_EM_RAW_RING_SWITCH;
806 }
807 }
808
809 /*
810 * Pass trap 0b as is to the recompiler in all other cases.
811 */
812 Log6(("TRPMGC0b: %Rrc (%04x:%08x EFL=%x)\n", VINF_EM_RAW_GUEST_TRAP, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
813 PGMRZDynMapReleaseAutoSet(pVCpu);
814 TRPM_EXIT_DBG_HOOK(0xb);
815 return VINF_EM_RAW_GUEST_TRAP;
816}
817
818
819/**
820 * \#GP (General Protection Fault) handler for Ring-0 privileged instructions.
821 *
822 * @returns VBox status code.
823 * VINF_SUCCESS means we completely handled this trap,
824 * other codes are passed execution to host context.
825 *
826 * @param pVM The cross context VM structure.
827 * @param pVCpu The cross context virtual CPU structure.
828 * @param pRegFrame Pointer to the register frame for the trap.
829 * @param pCpu The opcode info.
830 * @param PC The program counter corresponding to cs:eip in pRegFrame.
831 */
832static int trpmGCTrap0dHandlerRing0(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
833{
834 int rc;
835 TRPM_ENTER_DBG_HOOK(0xd);
836
837 /*
838 * Try handle it here, if not return to HC and emulate/interpret it there.
839 */
840 switch (pCpu->pCurInstr->uOpcode)
841 {
842 case OP_INT3:
843 /*
844 * Little hack to make the code below not fail
845 */
846 pCpu->Param1.fUse = DISUSE_IMMEDIATE8;
847 pCpu->Param1.uValue = 3;
848 /* fallthru */
849 case OP_INT:
850 {
851 Assert(pCpu->Param1.fUse & DISUSE_IMMEDIATE8);
852 Assert(!(PATMIsPatchGCAddr(pVM, PC)));
853 if (pCpu->Param1.uValue == 3)
854 {
855 /* Int 3 replacement patch? */
856 if (PATMRCHandleInt3PatchTrap(pVM, pRegFrame) == VINF_SUCCESS)
857 {
858 AssertFailed();
859 return trpmGCExitTrap(pVM, pVCpu, VINF_SUCCESS, pRegFrame);
860 }
861 }
862 rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)pCpu->Param1.uValue, pCpu->cbInstr, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT, 0xd);
863 if (RT_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
864 {
865 TRPM_EXIT_DBG_HOOK(0xd);
866 return trpmGCExitTrap(pVM, pVCpu, VINF_SUCCESS, pRegFrame);
867 }
868
869 pVCpu->trpm.s.uActiveVector = (pVCpu->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
870 pVCpu->trpm.s.enmActiveType = TRPM_SOFTWARE_INT;
871 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
872 }
873
874#ifdef PATM_EMULATE_SYSENTER
875 case OP_SYSEXIT:
876 case OP_SYSRET:
877 rc = PATMSysCall(pVM, CPUMCTX_FROM_CORE(pRegFrame), pCpu);
878 TRPM_EXIT_DBG_HOOK(0xd);
879 return trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
880#endif
881
882 case OP_HLT:
883 /* If it's in patch code, defer to ring-3. */
884 if (PATMIsPatchGCAddr(pVM, PC))
885 break;
886
887 pRegFrame->eip += pCpu->cbInstr;
888 TRPM_EXIT_DBG_HOOK(0xd);
889 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_HALT, pRegFrame);
890
891
892 /*
893 * These instructions are used by PATM and CASM for finding
894 * dangerous non-trapping instructions. Thus, since all
895 * scanning and patching is done in ring-3 we'll have to
896 * return to ring-3 on the first encounter of these instructions.
897 */
898 case OP_MOV_CR:
899 case OP_MOV_DR:
900 /* We can safely emulate control/debug register move instructions in patched code. */
901 if ( !PATMIsPatchGCAddr(pVM, PC)
902 && !CSAMIsKnownDangerousInstr(pVM, PC))
903 break;
904 case OP_INVLPG:
905 case OP_LLDT:
906 case OP_STI:
907 case OP_RDTSC: /* just in case */
908 case OP_RDPMC:
909 case OP_CLTS:
910 case OP_WBINVD: /* nop */
911 case OP_RDMSR:
912 case OP_WRMSR:
913 {
914 rc = VBOXSTRICTRC_TODO(EMInterpretInstructionDisasState(pVCpu, pCpu, pRegFrame, PC, EMCODETYPE_SUPERVISOR));
915 if (rc == VERR_EM_INTERPRETER)
916 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
917 TRPM_EXIT_DBG_HOOK(0xd);
918 return trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
919 }
920 }
921
922 TRPM_EXIT_DBG_HOOK(0xd);
923 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EXCEPTION_PRIVILEGED, pRegFrame);
924}
925
926
927/**
928 * \#GP (General Protection Fault) handler for Ring-3.
929 *
930 * @returns VBox status code.
931 * VINF_SUCCESS means we completely handled this trap,
932 * other codes are passed execution to host context.
933 *
934 * @param pVM The cross context VM structure.
935 * @param pVCpu The cross context virtual CPU structure.
936 * @param pRegFrame Pointer to the register frame for the trap.
937 * @param pCpu The opcode info.
938 * @param PC The program counter corresponding to cs:eip in pRegFrame.
939 */
940static int trpmGCTrap0dHandlerRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
941{
942 int rc;
943 Assert(!pRegFrame->eflags.Bits.u1VM);
944 TRPM_ENTER_DBG_HOOK(0xd);
945
946 switch (pCpu->pCurInstr->uOpcode)
947 {
948 /*
949 * INT3 and INT xx are ring-switching.
950 * (The shadow IDT will have set the entries to DPL=0, that's why we're here.)
951 */
952 case OP_INT3:
953 /*
954 * Little hack to make the code below not fail
955 */
956 pCpu->Param1.fUse = DISUSE_IMMEDIATE8;
957 pCpu->Param1.uValue = 3;
958 /* fall thru */
959 case OP_INT:
960 {
961 Assert(pCpu->Param1.fUse & DISUSE_IMMEDIATE8);
962 rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)pCpu->Param1.uValue, pCpu->cbInstr, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT, 0xd);
963 if (RT_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
964 {
965 TRPM_EXIT_DBG_HOOK(0xd);
966 return trpmGCExitTrap(pVM, pVCpu, VINF_SUCCESS, pRegFrame);
967 }
968
969 pVCpu->trpm.s.uActiveVector = (pVCpu->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
970 pVCpu->trpm.s.enmActiveType = TRPM_SOFTWARE_INT;
971 TRPM_EXIT_DBG_HOOK(0xd);
972 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
973 }
974
975 /*
976 * SYSCALL, SYSENTER, INTO and BOUND are also ring-switchers.
977 */
978 case OP_SYSCALL:
979 case OP_SYSENTER:
980#ifdef PATM_EMULATE_SYSENTER
981 rc = PATMSysCall(pVM, CPUMCTX_FROM_CORE(pRegFrame), pCpu);
982 if (rc == VINF_SUCCESS)
983 {
984 TRPM_EXIT_DBG_HOOK(0xd);
985 return trpmGCExitTrap(pVM, pVCpu, VINF_SUCCESS, pRegFrame);
986 }
987 /* else no break; */
988#endif
989 case OP_BOUND:
990 case OP_INTO:
991 pVCpu->trpm.s.uActiveVector = UINT32_MAX;
992 TRPM_EXIT_DBG_HOOK(0xd);
993 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_RING_SWITCH, pRegFrame);
994
995 /*
996 * Handle virtualized TSC & PMC reads, just in case.
997 */
998 case OP_RDTSC:
999 case OP_RDPMC:
1000 {
1001 rc = VBOXSTRICTRC_TODO(EMInterpretInstructionDisasState(pVCpu, pCpu, pRegFrame, PC, EMCODETYPE_SUPERVISOR));
1002 if (rc == VERR_EM_INTERPRETER)
1003 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
1004 TRPM_EXIT_DBG_HOOK(0xd);
1005 return trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
1006 }
1007
1008 /*
1009 * STI and CLI are I/O privileged, i.e. if IOPL
1010 */
1011 case OP_STI:
1012 case OP_CLI:
1013 {
1014 uint32_t efl = CPUMRawGetEFlags(pVCpu);
1015 uint32_t cpl = CPUMRCGetGuestCPL(pVCpu, pRegFrame);
1016 if (X86_EFL_GET_IOPL(efl) >= cpl)
1017 {
1018 LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> REM\n"));
1019 TRPM_EXIT_DBG_HOOK(0xd);
1020 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RESCHEDULE_REM, pRegFrame);
1021 }
1022 LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> #GP(0) iopl=%x, cpl=%x\n", X86_EFL_GET_IOPL(efl), cpl));
1023 break;
1024 }
1025 }
1026
1027 /*
1028 * A genuine guest fault.
1029 */
1030 TRPM_EXIT_DBG_HOOK(0xd);
1031 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
1032}
1033
1034
1035/**
1036 * Emulates RDTSC for the \#GP handler.
1037 *
1038 * @returns VINF_SUCCESS or VINF_EM_RAW_EMULATE_INSTR.
1039 *
1040 * @param pVM The cross context VM structure.
1041 * @param pVCpu The cross context virtual CPU structure.
1042 * @param pRegFrame Pointer to the register frame for the trap.
1043 * This will be updated on successful return.
1044 */
1045DECLINLINE(int) trpmGCTrap0dHandlerRdTsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
1046{
1047 STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRdTsc);
1048 TRPM_ENTER_DBG_HOOK(0xd);
1049
1050 if (CPUMGetGuestCR4(pVCpu) & X86_CR4_TSD)
1051 {
1052 TRPM_EXIT_DBG_HOOK(0xd);
1053 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame); /* will trap (optimize later). */
1054 }
1055
1056 uint64_t uTicks = TMCpuTickGet(pVCpu);
1057 pRegFrame->eax = uTicks;
1058 pRegFrame->edx = uTicks >> 32;
1059 pRegFrame->eip += 2;
1060 TRPM_EXIT_DBG_HOOK(0xd);
1061 return trpmGCExitTrap(pVM, pVCpu, VINF_SUCCESS, pRegFrame);
1062}
1063
1064
1065/**
1066 * \#GP (General Protection Fault) handler.
1067 *
1068 * @returns VBox status code.
1069 * VINF_SUCCESS means we completely handled this trap,
1070 * other codes are passed execution to host context.
1071 *
1072 * @param pVM The cross context VM structure.
1073 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
1074 * @param pRegFrame Pointer to the register frame for the trap.
1075 */
1076static int trpmGCTrap0dHandler(PVM pVM, PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
1077{
1078 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
1079 LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%08RX32 uErr=%RGv EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, pTrpmCpu->uActiveErrorCode, CPUMRawGetEFlags(pVCpu)));
1080 TRPM_ENTER_DBG_HOOK(0xd);
1081
1082 /*
1083 * Convert and validate CS.
1084 */
1085 STAM_PROFILE_START(&pVM->trpm.s.StatTrap0dDisasm, a);
1086 RTGCPTR PC;
1087 int rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs,
1088 pRegFrame->rip, &PC);
1089 if (RT_FAILURE(rc))
1090 {
1091 Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n",
1092 pRegFrame->cs.Sel, pRegFrame->eip, pRegFrame->ss.Sel & X86_SEL_RPL, rc));
1093 TRPM_EXIT_DBG_HOOK(0xd);
1094 STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
1095 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
1096 }
1097
1098 /*
1099 * Disassemble the instruction.
1100 */
1101 DISCPUSTATE Cpu;
1102 uint32_t cbOp;
1103 rc = EMInterpretDisasOneEx(pVM, pVCpu, PC, pRegFrame, &Cpu, &cbOp);
1104 if (RT_FAILURE(rc))
1105 {
1106 AssertMsgFailed(("DISCoreOneEx failed to PC=%RGv rc=%Rrc\n", PC, rc));
1107 TRPM_EXIT_DBG_HOOK(0xd);
1108 STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
1109 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
1110 }
1111 STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
1112
1113 /*
1114 * Optimize RDTSC traps.
1115 * Some guests (like Solaris) are using RDTSC all over the place and
1116 * will end up trapping a *lot* because of that.
1117 *
1118 * Note: it's no longer safe to access the instruction opcode directly due to possible stale code TLB entries
1119 */
1120 if (Cpu.pCurInstr->uOpcode == OP_RDTSC)
1121 return trpmGCTrap0dHandlerRdTsc(pVM, pVCpu, pRegFrame);
1122
1123 /*
1124 * Deal with I/O port access.
1125 */
1126 if ( pVCpu->trpm.s.uActiveErrorCode == 0
1127 && (Cpu.pCurInstr->fOpType & DISOPTYPE_PORTIO))
1128 {
1129 VBOXSTRICTRC rcStrict = IOMRCIOPortHandler(pVM, pVCpu, pRegFrame, &Cpu);
1130 TRPM_EXIT_DBG_HOOK(0xd);
1131 return trpmGCExitTrap(pVM, pVCpu, VBOXSTRICTRC_TODO(rcStrict), pRegFrame);
1132 }
1133
1134 /*
1135 * Deal with Ring-0 (privileged instructions)
1136 */
1137 if ( (pRegFrame->ss.Sel & X86_SEL_RPL) <= 1
1138 && !pRegFrame->eflags.Bits.u1VM)
1139 return trpmGCTrap0dHandlerRing0(pVM, pVCpu, pRegFrame, &Cpu, PC);
1140
1141 /*
1142 * Deal with Ring-3 GPs.
1143 */
1144 if (!pRegFrame->eflags.Bits.u1VM)
1145 return trpmGCTrap0dHandlerRing3(pVM, pVCpu, pRegFrame, &Cpu, PC);
1146
1147 /*
1148 * Deal with v86 code.
1149 *
1150 * We always set IOPL to zero which makes e.g. pushf fault in V86
1151 * mode. The guest might use IOPL=3 and therefore not expect a #GP.
1152 * Simply fall back to the recompiler to emulate this instruction if
1153 * that's the case. To get the correct we must use CPUMRawGetEFlags.
1154 */
1155 X86EFLAGS eflags;
1156 eflags.u32 = CPUMRawGetEFlags(pVCpu); /* Get the correct value. */
1157 Log3(("TRPM #GP V86: cs:eip=%04x:%08x IOPL=%d efl=%08x\n", pRegFrame->cs.Sel, pRegFrame->eip, eflags.Bits.u2IOPL, eflags.u));
1158 if (eflags.Bits.u2IOPL != 3)
1159 {
1160 Assert(EMIsRawRing1Enabled(pVM) || eflags.Bits.u2IOPL == 0);
1161
1162 rc = TRPMForwardTrap(pVCpu, pRegFrame, 0xD, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP, 0xd);
1163 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
1164 TRPM_EXIT_DBG_HOOK(0xd);
1165 return trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
1166 }
1167 TRPM_EXIT_DBG_HOOK(0xd);
1168 return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
1169}
1170
1171
1172/**
1173 * \#GP (General Protection Fault) handler.
1174 *
1175 * @returns VBox status code.
1176 * VINF_SUCCESS means we completely handled this trap,
1177 * other codes are passed execution to host context.
1178 *
1179 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
1180 * @param pRegFrame Pointer to the register frame for the trap.
1181 * @internal
1182 */
1183DECLASM(int) TRPMGCTrap0dHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
1184{
1185 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
1186 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
1187 LogFlow(("TRPMGC0d: %04x:%08x err=%x EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode, CPUMRawGetEFlags(pVCpu)));
1188 TRPM_ENTER_DBG_HOOK(0xd);
1189
1190 PGMRZDynMapStartAutoSet(pVCpu);
1191 int rc = trpmGCTrap0dHandler(pVM, pTrpmCpu, pRegFrame);
1192 switch (rc)
1193 {
1194 case VINF_EM_RAW_GUEST_TRAP:
1195 case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
1196 if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
1197 rc = VINF_PATM_PATCH_TRAP_GP;
1198 break;
1199
1200 case VINF_EM_RAW_INTERRUPT_PENDING:
1201 Assert(TRPMHasTrap(pVCpu));
1202 /* no break; */
1203 case VINF_PGM_SYNC_CR3:
1204 case VINF_EM_RAW_EMULATE_INSTR:
1205 case VINF_IOM_R3_IOPORT_READ:
1206 case VINF_IOM_R3_IOPORT_WRITE:
1207 case VINF_IOM_R3_IOPORT_COMMIT_WRITE:
1208 case VINF_IOM_R3_MMIO_WRITE:
1209 case VINF_IOM_R3_MMIO_COMMIT_WRITE:
1210 case VINF_IOM_R3_MMIO_READ:
1211 case VINF_IOM_R3_MMIO_READ_WRITE:
1212 case VINF_CPUM_R3_MSR_READ:
1213 case VINF_CPUM_R3_MSR_WRITE:
1214 case VINF_PATM_PATCH_INT3:
1215 case VINF_EM_NO_MEMORY:
1216 case VINF_EM_RAW_TO_R3:
1217 case VINF_EM_RAW_TIMER_PENDING:
1218 case VINF_EM_PENDING_REQUEST:
1219 case VINF_EM_HALT:
1220 case VINF_SELM_SYNC_GDT:
1221 case VINF_SUCCESS:
1222 break;
1223
1224 default:
1225 AssertMsg(PATMIsPatchGCAddr(pVM, pRegFrame->eip) == false, ("return code %d\n", rc));
1226 break;
1227 }
1228 Log6(("TRPMGC0d: %Rrc (%04x:%08x EFL=%x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
1229 TRPM_EXIT_DBG_HOOK(0xd);
1230 return rc;
1231}
1232
1233
1234/**
1235 * \#PF (Page Fault) handler.
1236 *
1237 * Calls PGM which does the actual handling.
1238 *
1239 *
1240 * @returns VBox status code.
1241 * VINF_SUCCESS means we completely handled this trap,
1242 * other codes are passed execution to host context.
1243 *
1244 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
1245 * @param pRegFrame Pointer to the register frame for the trap.
1246 * @internal
1247 */
1248DECLASM(int) TRPMGCTrap0eHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
1249{
1250 PVM pVM = TRPMCPU_2_VM(pTrpmCpu);
1251 PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu);
1252 LogFlow(("TRPMGC0e: %04x:%08x err=%x cr2=%08x EFL=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode, (uint32_t)pVCpu->trpm.s.uActiveCR2, CPUMRawGetEFlags(pVCpu)));
1253 TRPM_ENTER_DBG_HOOK(0xe);
1254
1255 /*
1256 * This is all PGM stuff.
1257 */
1258 PGMRZDynMapStartAutoSet(pVCpu);
1259 int rc = PGMTrap0eHandler(pVCpu, pVCpu->trpm.s.uActiveErrorCode, pRegFrame, (RTGCPTR)pVCpu->trpm.s.uActiveCR2);
1260 switch (rc)
1261 {
1262 case VINF_EM_RAW_EMULATE_INSTR:
1263 case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
1264 case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
1265 case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
1266 case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
1267 if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
1268 rc = VINF_PATCH_EMULATE_INSTR;
1269 break;
1270
1271 case VINF_EM_RAW_GUEST_TRAP:
1272 if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
1273 {
1274 PGMRZDynMapReleaseAutoSet(pVCpu);
1275 TRPM_EXIT_DBG_HOOK(0xe);
1276 return VINF_PATM_PATCH_TRAP_PF;
1277 }
1278
1279 rc = TRPMForwardTrap(pVCpu, pRegFrame, 0xE, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP, 0xe);
1280 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
1281 break;
1282
1283 case VINF_EM_RAW_INTERRUPT_PENDING:
1284 Assert(TRPMHasTrap(pVCpu));
1285 /* no break; */
1286 case VINF_IOM_R3_MMIO_READ:
1287 case VINF_IOM_R3_MMIO_WRITE:
1288 case VINF_IOM_R3_MMIO_COMMIT_WRITE:
1289 case VINF_IOM_R3_MMIO_READ_WRITE:
1290 case VINF_PATM_HC_MMIO_PATCH_READ:
1291 case VINF_PATM_HC_MMIO_PATCH_WRITE:
1292 case VINF_SUCCESS:
1293 case VINF_EM_RAW_TO_R3:
1294 case VINF_EM_PENDING_REQUEST:
1295 case VINF_EM_RAW_TIMER_PENDING:
1296 case VINF_EM_NO_MEMORY:
1297 case VINF_CSAM_PENDING_ACTION:
1298 case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
1299 break;
1300
1301 default:
1302 AssertMsg(PATMIsPatchGCAddr(pVM, pRegFrame->eip) == false, ("Patch address for return code %d. eip=%08x\n", rc, pRegFrame->eip));
1303 break;
1304 }
1305 rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame);
1306 Log6(("TRPMGC0e: %Rrc (%04x:%08x EFL=%x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, CPUMRawGetEFlags(pVCpu)));
1307 TRPM_EXIT_DBG_HOOK(0xe);
1308 return rc;
1309}
1310
1311
1312/**
1313 * Scans for the EIP in the specified array of trap handlers.
1314 *
1315 * If we don't fine the EIP, we'll panic.
1316 *
1317 * @returns VBox status code.
1318 *
1319 * @param pVM The cross context VM structure.
1320 * @param pRegFrame Pointer to the register frame for the trap.
1321 * @param paHandlers The array of trap handler records.
1322 * @param pEndRecord The end record (exclusive).
1323 */
1324static int trpmGCHyperGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, PCTRPMGCHYPER paHandlers, PCTRPMGCHYPER pEndRecord)
1325{
1326 uintptr_t uEip = (uintptr_t)pRegFrame->eip;
1327 Assert(paHandlers <= pEndRecord);
1328
1329 Log(("trpmGCHyperGeneric: uEip=%x %p-%p\n", uEip, paHandlers, pEndRecord));
1330
1331#if 0 /// @todo later
1332 /*
1333 * Start by doing a kind of binary search.
1334 */
1335 unsigned iStart = 0;
1336 unsigned iEnd = pEndRecord - paHandlers;
1337 unsigned i = iEnd / 2;
1338#endif
1339
1340 /*
1341 * Do a linear search now (in case the array wasn't properly sorted).
1342 */
1343 for (PCTRPMGCHYPER pCur = paHandlers; pCur < pEndRecord; pCur++)
1344 {
1345 if ( pCur->uStartEIP <= uEip
1346 && (pCur->uEndEIP ? pCur->uEndEIP > uEip : pCur->uStartEIP == uEip))
1347 return pCur->pfnHandler(pVM, pRegFrame, pCur->uUser);
1348 }
1349
1350 return VERR_TRPM_DONT_PANIC;
1351}
1352
1353
1354/**
1355 * Hypervisor \#NP ((segment) Not Present) handler.
1356 *
1357 * Scans for the EIP in the registered trap handlers.
1358 *
1359 * @returns VBox status code.
1360 * VINF_SUCCESS means we completely handled this trap,
1361 * other codes are passed back to host context.
1362 *
1363 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
1364 * @param pRegFrame Pointer to the register frame for the trap.
1365 * @internal
1366 */
1367DECLASM(int) TRPMGCHyperTrap0bHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
1368{
1369 return trpmGCHyperGeneric(TRPMCPU_2_VM(pTrpmCpu), pRegFrame, g_aTrap0bHandlers, g_aTrap0bHandlersEnd);
1370}
1371
1372
1373/**
1374 * Hypervisor \#GP (General Protection Fault) handler.
1375 *
1376 * Scans for the EIP in the registered trap handlers.
1377 *
1378 * @returns VBox status code.
1379 * VINF_SUCCESS means we completely handled this trap,
1380 * other codes are passed back to host context.
1381 *
1382 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
1383 * @param pRegFrame Pointer to the register frame for the trap.
1384 * @internal
1385 */
1386DECLASM(int) TRPMGCHyperTrap0dHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
1387{
1388 return trpmGCHyperGeneric(TRPMCPU_2_VM(pTrpmCpu), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
1389}
1390
1391
1392/**
1393 * Hypervisor \#PF (Page Fault) handler.
1394 *
1395 * Scans for the EIP in the registered trap handlers.
1396 *
1397 * @returns VBox status code.
1398 * VINF_SUCCESS means we completely handled this trap,
1399 * other codes are passed back to host context.
1400 *
1401 * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
1402 * @param pRegFrame Pointer to the register frame for the trap.
1403 * @internal
1404 */
1405DECLASM(int) TRPMGCHyperTrap0eHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
1406{
1407 return trpmGCHyperGeneric(TRPMCPU_2_VM(pTrpmCpu), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
1408}
1409
1410
1411/**
1412 * Deal with hypervisor traps occurring when resuming execution on a trap.
1413 *
1414 * There is a little problem with recursive RC (hypervisor) traps. We deal with
1415 * this by not allowing recursion without it being the subject of a guru
1416 * meditation. (We used to / tried to handle this but there isn't any reason
1417 * for it.)
1418 *
1419 * So, do NOT use this for handling RC traps!
1420 *
1421 * @returns VBox status code. (Anything but VINF_SUCCESS will cause guru.)
1422 * @param pVM The cross context VM structure.
1423 * @param pRegFrame Register frame.
1424 * @param uUser User arg.
1425 */
1426DECLCALLBACK(int) trpmRCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
1427{
1428 Log(("********************************************************\n"));
1429 Log(("trpmRCTrapInGeneric: eip=%RX32 uUser=%#x\n", pRegFrame->eip, uUser));
1430 Log(("********************************************************\n"));
1431
1432 /*
1433 * This used to be kind of complicated, but since we stopped storing
1434 * the register frame on the stack and instead storing it directly
1435 * in the CPUMCPU::Guest structure, we just have to figure out which
1436 * status to hand on to the host and let the recompiler/IEM do its
1437 * job.
1438 */
1439 switch (uUser)
1440 {
1441 case TRPM_TRAP_IN_MOV_GS:
1442 case TRPM_TRAP_IN_MOV_FS:
1443 case TRPM_TRAP_IN_MOV_ES:
1444 case TRPM_TRAP_IN_MOV_DS:
1445 TRPMGCHyperReturnToHost(pVM, VINF_EM_RAW_STALE_SELECTOR);
1446 break;
1447
1448 case TRPM_TRAP_IN_IRET:
1449 case TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86:
1450 TRPMGCHyperReturnToHost(pVM, VINF_EM_RAW_IRET_TRAP);
1451 break;
1452
1453 default:
1454 AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
1455 return VERR_TRPM_BAD_TRAP_IN_OP;
1456 }
1457
1458 AssertMsgFailed(("Impossible!\n"));
1459 return VERR_TRPM_IPE_3;
1460}
1461
1462
1463/**
1464 * Generic hyper trap handler that sets the EIP to @a uUser.
1465 *
1466 * @returns VBox status code. (Anything but VINF_SUCCESS will cause guru.)
1467 * @param pVM The cross context VM structure.
1468 * @param pRegFrame Pointer to the register frame (within VM)
1469 * @param uUser The user arg, which should be the new EIP address.
1470 */
1471extern "C" DECLCALLBACK(int) TRPMRCTrapHyperHandlerSetEIP(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
1472{
1473 AssertReturn(MMHyperIsInsideArea(pVM, uUser), VERR_TRPM_IPE_3);
1474 pRegFrame->eip = uUser;
1475 return VINF_SUCCESS;
1476}
1477
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette