VirtualBox

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

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

Fixed broken return path in generic trap handler for v86 code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 38.0 KB
Line 
1/* $Id: TRPMGCHandlers.cpp 1089 2007-02-28 08:42:35Z 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 {
315 rc = PATMHandleInt3PatchTrap(pVM, pRegFrame);
316 if (rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_PATCH_INT3 || rc == VINF_PATM_DUPLICATE_FUNCTION)
317 return trpmGCExitTrap(pVM, rc, pRegFrame);
318 }
319 rc = DBGFGCTrap03Handler(pVM, pRegFrame);
320 /* anything we should do with this? Schedule it in GC? */
321 return trpmGCExitTrap(pVM, rc, pRegFrame);
322}
323
324
325/**
326 * Trap handler for illegal opcode fault (\#UD).
327 *
328 * @returns VBox status code.
329 * VINF_SUCCESS means we completely handled this trap,
330 * other codes are passed execution to host context.
331 *
332 * @param pTrpm Pointer to TRPM data (within VM).
333 * @param pRegFrame Pointer to the register frame for the trap.
334 * @internal
335 */
336DECLASM(int) TRPMGCTrap06Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
337{
338 PVM pVM = TRPM2VM(pTrpm);
339
340 LogFlow(("TRPMGCTrap06Handler %VGv eflags=%x\n", pRegFrame->eip, pRegFrame->eflags.u32));
341
342 if ( (pRegFrame->ss & X86_SEL_RPL) == 1
343 && PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
344 {
345 /*
346 * Decode the instruction.
347 */
348 RTGCPTR PC;
349 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
350 if (VBOX_FAILURE(rc))
351 {
352 Log(("TRPMGCTrap06Handler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n", pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
353 return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
354 }
355
356 DISCPUSTATE Cpu;
357 uint32_t cbOp;
358 rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
359 if (VBOX_FAILURE(rc))
360 return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
361
362 /** @note monitor causes an #UD exception instead of #GP when not executed in ring 0. */
363 if (Cpu.pCurInstr->opcode == OP_ILLUD2)
364 {
365 int rc = PATMHandleIllegalInstrTrap(pVM, pRegFrame);
366 if (rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_DUPLICATE_FUNCTION || rc == VINF_PATM_PENDING_IRQ_AFTER_IRET)
367 return trpmGCExitTrap(pVM, rc, pRegFrame);
368 }
369 }
370 return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
371}
372
373
374/**
375 * Trap handler for device not present fault (\#NM).
376 *
377 * Device not available, FP or (F)WAIT instruction.
378 *
379 * @returns VBox status code.
380 * VINF_SUCCESS means we completely handled this trap,
381 * other codes are passed execution to host context.
382 *
383 * @param pTrpm Pointer to TRPM data (within VM).
384 * @param pRegFrame Pointer to the register frame for the trap.
385 * @internal
386 */
387DECLASM(int) TRPMGCTrap07Handler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
388{
389 PVM pVM = TRPM2VM(pTrpm);
390
391 LogFlow(("TRPMTrap07HandlerGC: eip=%VGv\n", pRegFrame->eip));
392 return CPUMHandleLazyFPU(pVM);
393}
394
395
396/**
397 * \#NP ((segment) Not Present) handler.
398 *
399 * @returns VBox status code.
400 * VINF_SUCCESS means we completely handled this trap,
401 * other codes are passed execution to host context.
402 *
403 * @param pTrpm Pointer to TRPM data (within VM).
404 * @param pRegFrame Pointer to the register frame for the trap.
405 * @internal
406 */
407DECLASM(int) TRPMGCTrap0bHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
408{
409 LogFlow(("TRPMGCTrap0bHandler: eip=%VGv\n", pRegFrame->eip));
410 PVM pVM = TRPM2VM(pTrpm);
411
412 /*
413 * Try to detect instruction by opcode which caused trap.
414 * XXX note: this code may cause \#PF (trap e) or \#GP (trap d) while
415 * accessing user code. need to handle it somehow in future!
416 */
417 uint8_t *pu8Code;
418 if (SELMValidateAndConvertCSAddr(pVM, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, (PRTGCPTR)&pu8Code) == VINF_SUCCESS)
419 {
420 /*
421 * First skip possible instruction prefixes, such as:
422 * OS, AS
423 * CS:, DS:, ES:, SS:, FS:, GS:
424 * REPE, REPNE
425 *
426 * note: Currently we supports only up to 4 prefixes per opcode, more
427 * prefixes (normally not used anyway) will cause trap d in guest.
428 * note: Instruction length in IA-32 may be up to 15 bytes, we dont
429 * check this issue, its too hard.
430 */
431 for (unsigned i = 0; i < 4; i++)
432 {
433 if ( pu8Code[0] != 0xf2 /* REPNE/REPNZ */
434 && pu8Code[0] != 0xf3 /* REP/REPE/REPZ */
435 && pu8Code[0] != 0x2e /* CS: */
436 && pu8Code[0] != 0x36 /* SS: */
437 && pu8Code[0] != 0x3e /* DS: */
438 && pu8Code[0] != 0x26 /* ES: */
439 && pu8Code[0] != 0x64 /* FS: */
440 && pu8Code[0] != 0x65 /* GS: */
441 && pu8Code[0] != 0x66 /* OS */
442 && pu8Code[0] != 0x67 /* AS */
443 )
444 break;
445 pu8Code++;
446 }
447
448 /*
449 * Detect right switch using a callgate.
450 *
451 * We recognize the following causes for the trap 0b:
452 * CALL FAR, CALL FAR []
453 * JMP FAR, JMP FAR []
454 * IRET (may cause a task switch)
455 *
456 * Note: we can't detect whether the trap was caused by a call to a
457 * callgate descriptor or it is a real trap 0b due to a bad selector.
458 * In both situations we'll pass execution to our recompiler so we don't
459 * have to worry.
460 * If we wanted to do better detection, we have set GDT entries to callgate
461 * descriptors pointing to our own handlers.
462 */
463 /** @todo not sure about IRET, may generate Trap 0d (\#GP), NEED TO CHECK! */
464 if ( pu8Code[0] == 0x9a /* CALL FAR */
465 || ( pu8Code[0] == 0xff /* CALL FAR [] */
466 && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x18)
467 || pu8Code[0] == 0xea /* JMP FAR */
468 || ( pu8Code[0] == 0xff /* JMP FAR [] */
469 && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x28)
470 || pu8Code[0] == 0xcf /* IRET */
471 )
472 {
473 /*
474 * Got potential call to callgate.
475 * We simply return execution to the recompiler to do emulation
476 * starting from the instruction which caused the trap.
477 */
478 pTrpm->uActiveVector = ~0;
479 return VINF_EM_RAW_RING_SWITCH;
480 }
481 }
482
483 /*
484 * Pass trap 0b as is to the recompiler in all other cases.
485 */
486 return VINF_EM_RAW_GUEST_TRAP;
487}
488
489
490/**
491 * \#GP (General Protection Fault) handler for Ring-0 privileged instructions.
492 *
493 * @returns VBox status code.
494 * VINF_SUCCESS means we completely handled this trap,
495 * other codes are passed execution to host context.
496 *
497 * @param pVM The VM handle.
498 * @param pRegFrame Pointer to the register frame for the trap.
499 * @param pCpu The opcode info.
500 * @param PC Program counter.
501 */
502static int trpmGCTrap0dHandlerRing0(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
503{
504 int rc;
505
506 /*
507 * Try handle it here, if not return to HC and emulate/interpret it there.
508 */
509 switch (pCpu->pCurInstr->opcode)
510 {
511 case OP_INT3:
512 /*
513 * Little hack to make the code below not fail
514 */
515 pCpu->param1.flags = USE_IMMEDIATE8;
516 pCpu->param1.parval = 3;
517 /* fallthru */
518 case OP_INT:
519 {
520 Assert(pCpu->param1.flags & USE_IMMEDIATE8);
521 Assert(!(PATMIsPatchGCAddr(pVM, PC)));
522 if (pCpu->param1.parval == 3)
523 {
524 /* Obsolete!! */
525 /* Int 3 replacement patch? */
526 if (PATMHandleInt3PatchTrap(pVM, pRegFrame) == VINF_SUCCESS)
527 {
528 AssertFailed();
529 return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
530 }
531 }
532 rc = TRPMForwardTrap(pVM, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT);
533 if (VBOX_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
534 return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
535
536 pVM->trpm.s.uActiveVector = (pVM->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
537 pVM->trpm.s.fActiveSoftwareInterrupt = true;
538 return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
539 }
540
541#ifdef PATM_EMULATE_SYSENTER
542 case OP_SYSEXIT:
543 case OP_SYSRET:
544 rc = PATMSysCall(pVM, pRegFrame, pCpu);
545 return trpmGCExitTrap(pVM, rc, pRegFrame);
546#endif
547
548 case OP_HLT:
549 /* If it's in patch code, defer to ring-3. */
550 if (PATMIsPatchGCAddr(pVM, PC))
551 break;
552
553 pRegFrame->eip += pCpu->opsize;
554 return trpmGCExitTrap(pVM, VINF_EM_HALT, pRegFrame);
555
556
557 /*
558 * These instructions are used by PATM and CASM for finding
559 * dangerous non-trapping instructions. Thus, since all
560 * scanning and patching is done in ring-3 we'll have to
561 * return to ring-3 on the first encounter of these instructions.
562 */
563 case OP_MOV_CR:
564 case OP_MOV_DR:
565 /* We can safely emulate control/debug register move instructions in patched code. */
566 if ( !PATMIsPatchGCAddr(pVM, PC)
567 && !CSAMIsKnownDangerousInstr(pVM, PC))
568 break;
569 case OP_INVLPG:
570 case OP_LLDT:
571 case OP_STI:
572 case OP_RDTSC:
573 {
574 uint32_t cbIgnored;
575 rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, PC, &cbIgnored);
576 if (VBOX_SUCCESS(rc))
577 pRegFrame->eip += pCpu->opsize;
578 else if (rc == VERR_EM_INTERPRETER)
579 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
580 return trpmGCExitTrap(pVM, rc, pRegFrame);
581 }
582 }
583
584 return trpmGCExitTrap(pVM, VINF_EM_RAW_EXCEPTION_PRIVILEGED, pRegFrame);
585}
586
587
588/**
589 * \#GP (General Protection Fault) handler for Ring-3.
590 *
591 * @returns VBox status code.
592 * VINF_SUCCESS means we completely handled this trap,
593 * other codes are passed execution to host context.
594 *
595 * @param pVM The VM handle.
596 * @param pRegFrame Pointer to the register frame for the trap.
597 * @param pCpu The opcode info.
598 */
599static int trpmGCTrap0dHandlerRing3(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
600{
601 int rc;
602
603 switch (pCpu->pCurInstr->opcode)
604 {
605 /*
606 * STI and CLI are I/O privileged, i.e. if IOPL
607 */
608 case OP_STI:
609 case OP_CLI:
610 {
611 uint32_t efl = CPUMRawGetEFlags(pVM, pRegFrame);
612 if (X86_EFL_GET_IOPL(efl) >= (unsigned)(pRegFrame->ss & X86_SEL_RPL))
613 {
614 LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> REM\n"));
615 return trpmGCExitTrap(pVM, VINF_EM_RESCHEDULE_REM, pRegFrame);
616 }
617 LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> #GP(0)\n"));
618 break;
619 }
620
621 /*
622 * INT3 and INT xx are ring-switching.
623 * (The shadow IDT will have set the entries to DPL=0, that's why we're here.)
624 */
625 case OP_INT3:
626 /*
627 * Little hack to make the code below not fail
628 */
629 pCpu->param1.flags = USE_IMMEDIATE8;
630 pCpu->param1.parval = 3;
631 /* fall thru */
632 case OP_INT:
633 {
634 Assert(pCpu->param1.flags & USE_IMMEDIATE8);
635 rc = TRPMForwardTrap(pVM, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT);
636 if (VBOX_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
637 return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
638
639 pVM->trpm.s.uActiveVector = (pVM->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
640 pVM->trpm.s.fActiveSoftwareInterrupt = true;
641 return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
642 }
643
644 /*
645 * SYSCALL, SYSENTER, INTO and BOUND are also ring-switchers.
646 */
647 case OP_SYSCALL:
648 case OP_SYSENTER:
649#ifdef PATM_EMULATE_SYSENTER
650 rc = PATMSysCall(pVM, pRegFrame, pCpu);
651 if (rc == VINF_SUCCESS)
652 return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
653 /* else no break; */
654#endif
655 case OP_BOUND:
656 case OP_INTO:
657 pVM->trpm.s.uActiveVector = ~0;
658 return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH, pRegFrame);
659 }
660
661 /*
662 * A genuine guest fault.
663 */
664 return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
665}
666
667
668/**
669 * \#GP (General Protection Fault) handler.
670 *
671 * @returns VBox status code.
672 * VINF_SUCCESS means we completely handled this trap,
673 * other codes are passed execution to host context.
674 *
675 * @param pVM The VM handle.
676 * @param pTrpm Pointer to TRPM data (within VM).
677 * @param pRegFrame Pointer to the register frame for the trap.
678 */
679static int trpmGCTrap0dHandler(PVM pVM, PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
680{
681 LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%VGv uErr=%RX32\n", pRegFrame->ss, pRegFrame->eip, pTrpm->uActiveErrorCode));
682
683#if 0 /* not right for iret. Shouldn't really be needed as SELMValidateAndConvertCSAddr deals with invalid cs. */
684 /*
685 * Filter out selector problems first as these may mean that the
686 * instruction isn't safe to read. If we're here because CS is NIL
687 * the flattening of cs:eip will deal with that.
688 */
689 if ( !(pTrpm->uActiveErrorCode & (X86_TRAP_ERR_IDT | X86_TRAP_ERR_EXTERNAL))
690 && (pTrpm->uActiveErrorCode & X86_TRAP_ERR_SEL_MASK))
691 {
692 /* It's a guest trap. */
693 return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
694 }
695#endif
696
697 STAM_PROFILE_ADV_START(&pVM->trpm.s.StatTrap0dDisasm, a);
698
699 /* 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.
700 * Simply fall back to the recompiler to emulate this instruction.
701 */
702 if (pRegFrame->eflags.Bits.u1VM)
703 {
704 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
705 return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
706 }
707
708 /*
709 * Decode the instruction.
710 */
711 RTGCPTR PC;
712 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
713 if (VBOX_FAILURE(rc))
714 {
715 Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
716 pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
717 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
718 return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
719 }
720
721 DISCPUSTATE Cpu;
722 uint32_t cbOp;
723 rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
724 if (VBOX_FAILURE(rc))
725 {
726 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
727 return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
728 }
729 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
730
731 /*
732 * Deal with I/O port access.
733 */
734 if ( pVM->trpm.s.uActiveErrorCode == 0
735 && (Cpu.pCurInstr->optype & OPTYPE_PORTIO))
736 {
737 rc = EMInterpretPortIO(pVM, pRegFrame, &Cpu, cbOp);
738 return trpmGCExitTrap(pVM, rc, pRegFrame);
739 }
740
741 /*
742 * Deal with Ring-0 (privileged instructions)
743 */
744 if ( (pRegFrame->ss & X86_SEL_RPL) <= 1
745 && !pRegFrame->eflags.Bits.u1VM)
746 return trpmGCTrap0dHandlerRing0(pVM, pRegFrame, &Cpu, PC);
747
748 /*
749 * Deal with Ring-3 GPs.
750 */
751 if (!pRegFrame->eflags.Bits.u1VM)
752 return trpmGCTrap0dHandlerRing3(pVM, pRegFrame, &Cpu);
753
754 /** @todo what about V86 mode? */
755 return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
756}
757
758
759/**
760 * \#GP (General Protection Fault) handler.
761 *
762 * @returns VBox status code.
763 * VINF_SUCCESS means we completely handled this trap,
764 * other codes are passed execution to host context.
765 *
766 * @param pTrpm Pointer to TRPM data (within VM).
767 * @param pRegFrame Pointer to the register frame for the trap.
768 * @internal
769 */
770DECLASM(int) TRPMGCTrap0dHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
771{
772 LogFlow(("TRPMGCTrap0dHandler: eip=%RGv\n", pRegFrame->eip));
773 PVM pVM = TRPM2VM(pTrpm);
774
775 int rc = trpmGCTrap0dHandler(pVM, pTrpm, pRegFrame);
776 switch (rc)
777 {
778 case VINF_EM_RAW_GUEST_TRAP:
779 case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
780 if (PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
781 rc = VINF_PATM_PATCH_TRAP_GP;
782 break;
783
784 case VINF_EM_RAW_INTERRUPT_PENDING:
785 Assert(TRPMHasTrap(pVM));
786 /* no break; */
787 case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
788 case VINF_IOM_HC_IOPORT_READWRITE:
789 case VINF_IOM_HC_IOPORT_READ:
790 case VINF_IOM_HC_IOPORT_WRITE:
791 case VINF_IOM_HC_MMIO_WRITE:
792 case VINF_IOM_HC_MMIO_READ:
793 case VINF_IOM_HC_MMIO_READ_WRITE:
794 case VINF_PATM_PATCH_INT3:
795 case VINF_EM_RAW_TO_R3:
796 case VINF_EM_RAW_TIMER_PENDING:
797 case VINF_EM_PENDING_REQUEST:
798 case VINF_EM_HALT:
799 case VINF_SUCCESS:
800 break;
801
802 default:
803 AssertMsg(PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip) == false, ("return code %d\n", rc));
804 break;
805 }
806 return rc;
807}
808
809/**
810 * \#PF (Page Fault) handler.
811 *
812 * Calls PGM which does the actual handling.
813 *
814 *
815 * @returns VBox status code.
816 * VINF_SUCCESS means we completely handled this trap,
817 * other codes are passed execution to host context.
818 *
819 * @param pTrpm Pointer to TRPM data (within VM).
820 * @param pRegFrame Pointer to the register frame for the trap.
821 * @internal
822 */
823DECLASM(int) TRPMGCTrap0eHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
824{
825 LogBird(("TRPMGCTrap0eHandler: eip=%RGv\n", pRegFrame->eip));
826 PVM pVM = TRPM2VM(pTrpm);
827
828 /*
829 * This is all PGM stuff.
830 */
831 int rc = PGMTrap0eHandler(pVM, pTrpm->uActiveErrorCode, pRegFrame, (RTGCPTR)pTrpm->uActiveCR2);
832
833 switch (rc)
834 {
835 case VINF_EM_RAW_EMULATE_INSTR:
836 case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT:
837 case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
838 case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
839 case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
840 case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
841 if (PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
842 rc = VINF_PATCH_EMULATE_INSTR;
843 break;
844
845 case VINF_EM_RAW_GUEST_TRAP:
846 if (PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip))
847 return VINF_PATM_PATCH_TRAP_PF;
848
849 rc = TRPMForwardTrap(pVM, pRegFrame, 0xE, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP);
850 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
851 break;
852
853 case VINF_EM_RAW_INTERRUPT_PENDING:
854 Assert(TRPMHasTrap(pVM));
855 /* no break; */
856 case VINF_IOM_HC_MMIO_READ:
857 case VINF_IOM_HC_MMIO_WRITE:
858 case VINF_IOM_HC_MMIO_READ_WRITE:
859 case VINF_PATM_HC_MMIO_PATCH_READ:
860 case VINF_PATM_HC_MMIO_PATCH_WRITE:
861 case VINF_SUCCESS:
862 case VINF_EM_RAW_TO_R3:
863 case VINF_EM_PENDING_REQUEST:
864 case VINF_EM_RAW_TIMER_PENDING:
865 case VINF_CSAM_PENDING_ACTION:
866 case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
867 break;
868
869 default:
870 AssertMsg(PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip) == false, ("Patch address for return code %d. eip=%08x\n", rc, pRegFrame->eip));
871 break;
872 }
873 return trpmGCExitTrap(pVM, rc, pRegFrame);
874}
875
876
877/**
878 * Scans for the EIP in the specified array of trap handlers.
879 *
880 * If we don't fine the EIP, we'll panic.
881 *
882 * @returns VBox status code.
883 *
884 * @param pVM The VM handle.
885 * @param pRegFrame Pointer to the register frame for the trap.
886 * @param paHandlers The array of trap handler records.
887 * @param pEndRecord The end record (exclusive).
888 */
889static int trpmGCHyperGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, PCTRPMGCHYPER paHandlers, PCTRPMGCHYPER pEndRecord)
890{
891 uintptr_t uEip = (uintptr_t)pRegFrame->eip;
892 Assert(paHandlers <= pEndRecord);
893
894 Log(("trpmGCHyperGeneric: uEip=%x %p-%p\n", uEip, paHandlers, pEndRecord));
895
896#if 0 /// @todo later
897 /*
898 * Start by doing a kind of binary search.
899 */
900 unsigned iStart = 0;
901 unsigned iEnd = pEndRecord - paHandlers;
902 unsigned i = iEnd / 2;
903#endif
904
905 /*
906 * Do a linear search now (in case the array wasn't properly sorted).
907 */
908 for (PCTRPMGCHYPER pCur = paHandlers; pCur < pEndRecord; pCur++)
909 {
910 if ( pCur->uStartEIP <= uEip
911 && (pCur->uEndEIP ? pCur->uEndEIP > uEip : pCur->uStartEIP == uEip))
912 return pCur->pfnHandler(pVM, pRegFrame, pCur->uUser);
913 }
914
915 return VERR_TRPM_DONT_PANIC;
916}
917
918
919/**
920 * Hypervisor \#NP ((segment) Not Present) handler.
921 *
922 * Scans for the EIP in the registered trap handlers.
923 *
924 * @returns VBox status code.
925 * VINF_SUCCESS means we completely handled this trap,
926 * other codes are passed back to host context.
927 *
928 * @param pTrpm Pointer to TRPM data (within VM).
929 * @param pRegFrame Pointer to the register frame for the trap.
930 * @internal
931 */
932DECLASM(int) TRPMGCHyperTrap0bHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
933{
934 return trpmGCHyperGeneric(TRPM2VM(pTrpm), pRegFrame, g_aTrap0bHandlers, g_aTrap0bHandlersEnd);
935}
936
937
938/**
939 * Hypervisor \#GP (General Protection Fault) handler.
940 *
941 * Scans for the EIP in the registered trap handlers.
942 *
943 * @returns VBox status code.
944 * VINF_SUCCESS means we completely handled this trap,
945 * other codes are passed back to host context.
946 *
947 * @param pTrpm Pointer to TRPM data (within VM).
948 * @param pRegFrame Pointer to the register frame for the trap.
949 * @internal
950 */
951DECLASM(int) TRPMGCHyperTrap0dHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
952{
953 return trpmGCHyperGeneric(TRPM2VM(pTrpm), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
954}
955
956
957/**
958 * Hypervisor \#PF (Page Fault) handler.
959 *
960 * Scans for the EIP in the registered trap handlers.
961 *
962 * @returns VBox status code.
963 * VINF_SUCCESS means we completely handled this trap,
964 * other codes are passed back to host context.
965 *
966 * @param pTrpm Pointer to TRPM data (within VM).
967 * @param pRegFrame Pointer to the register frame for the trap.
968 * @internal
969 */
970DECLASM(int) TRPMGCHyperTrap0eHandler(PTRPM pTrpm, PCPUMCTXCORE pRegFrame)
971{
972 return trpmGCHyperGeneric(TRPM2VM(pTrpm), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
973}
974
975
976/**
977 * Deal with hypervisor traps occuring when resuming execution on a trap.
978 *
979 * @returns VBox status code.
980 * @param pVM The VM handle.
981 * @param pRegFrame Register frame.
982 * @param uUser User arg.
983 */
984DECLCALLBACK(int) trpmGCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
985{
986 Log(("trpmGCTrapInGeneric: eip=%RX32 uUser=%#x\n", pRegFrame->eip, uUser));
987
988 if (uUser & TRPM_TRAP_IN_HYPER)
989 {
990 /*
991 * Check that there is still some stack left, if not we'll flag
992 * a guru meditation (the alternative is a triple fault).
993 */
994 RTGCUINTPTR cbStackUsed = (RTGCUINTPTR)VMMGetStackGC(pVM) - pRegFrame->esp;
995 if (cbStackUsed > VMM_STACK_SIZE - _1K)
996 {
997 LogRel(("trpmGCTrapInGeneric: ran out of stack: esp=#x cbStackUsed=%#x\n", pRegFrame->esp, cbStackUsed));
998 return VERR_TRPM_DONT_PANIC;
999 }
1000
1001 /*
1002 * Just zero the register containing the selector in question.
1003 * We'll deal with the actual stale or troublesome selector value in
1004 * the outermost trap frame.
1005 */
1006 PCPUMCTXCORE pCoreCtx = (PCPUMCTXCORE)pRegFrame->esp;
1007 switch (uUser & TRPM_TRAP_IN_OP_MASK)
1008 {
1009 case TRPM_TRAP_IN_MOV_GS:
1010 pRegFrame->eax = 0;
1011 pRegFrame->gs = 0; /* prevent recursive trouble. */
1012 break;
1013 case TRPM_TRAP_IN_MOV_FS:
1014 pRegFrame->eax = 0;
1015 pRegFrame->fs = 0; /* prevent recursive trouble. */
1016 return VINF_SUCCESS;
1017
1018 default:
1019 AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
1020 return VERR_INTERNAL_ERROR;
1021 }
1022 }
1023 else
1024 {
1025 /*
1026 * Reconstruct the guest context and switch to the recompiler.
1027 * We ASSUME we're only at
1028 */
1029 CPUMCTXCORE CtxCore = *pRegFrame;
1030 uint32_t *pEsp = (uint32_t *)pRegFrame->esp;
1031 int rc;
1032
1033 switch (uUser)
1034 {
1035 /*
1036 * This will only occur when resuming guest code in a trap handler!
1037 */
1038 /* @note ASSUMES esp points to the temporary guest CPUMCTXCORE!!! */
1039 case TRPM_TRAP_IN_MOV_GS:
1040 case TRPM_TRAP_IN_MOV_FS:
1041 case TRPM_TRAP_IN_MOV_ES:
1042 case TRPM_TRAP_IN_MOV_DS:
1043 {
1044 PCPUMCTXCORE pTempGuestCtx = (PCPUMCTXCORE)pEsp;
1045
1046 /* Just copy the whole thing; several selector registers, eip (etc) and eax are not yet in pRegFrame. */
1047 CtxCore = *pTempGuestCtx;
1048 rc = VINF_EM_RAW_STALE_SELECTOR;
1049 break;
1050 }
1051
1052 /*
1053 * This will only occur when resuming guest code!
1054 */
1055 case TRPM_TRAP_IN_IRET:
1056 CtxCore.eip = *pEsp++;
1057 CtxCore.cs = (RTSEL)*pEsp++;
1058 CtxCore.eflags.u32 = *pEsp++;
1059 CtxCore.esp = *pEsp++;
1060 CtxCore.ss = (RTSEL)*pEsp++;
1061 rc = VINF_EM_RAW_IRET_TRAP;
1062 break;
1063
1064 /*
1065 * This will only occur when resuming V86 guest code!
1066 */
1067 case TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86:
1068 CtxCore.eip = *pEsp++;
1069 CtxCore.cs = (RTSEL)*pEsp++;
1070 CtxCore.eflags.u32 = *pEsp++;
1071 CtxCore.esp = *pEsp++;
1072 CtxCore.ss = (RTSEL)*pEsp++;
1073 CtxCore.es = (RTSEL)*pEsp++;
1074 CtxCore.ds = (RTSEL)*pEsp++;
1075 CtxCore.fs = (RTSEL)*pEsp++;
1076 CtxCore.gs = (RTSEL)*pEsp++;
1077 rc = VINF_EM_RAW_IRET_TRAP;
1078 break;
1079
1080 default:
1081 AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
1082 return VERR_INTERNAL_ERROR;
1083 }
1084
1085
1086 CPUMSetGuestCtxCore(pVM, &CtxCore);
1087 TRPMGCHyperReturnToHost(pVM, rc);
1088 }
1089
1090 AssertMsgFailed(("Impossible!\n"));
1091 return VERR_INTERNAL_ERROR;
1092}
1093
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