VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMGC/TRPMGCHandlers.cpp@ 1359

Last change on this file since 1359 was 1359, checked in by vboxsync, 18 years ago

SELM function changes for v86 mode code.
CPL check fixes for V86 mode code.

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

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