TRPMRCHandlers.cpp revision 9f9d378b670af8b781bc9e53e1256e9518e228ea
/* $Id$ */
/** @file
* TRPM - Guest Context Trap Handlers, CPP part
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_TRPM
#include "TRPMInternal.h"
#include <VBox/disopcode.h>
#include <iprt/asm-amd64-x86.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/* still here. MODR/M byte parsing */
#define X86_OPCODE_MODRM_MOD_MASK 0xc0
#define X86_OPCODE_MODRM_REG_MASK 0x38
#define X86_OPCODE_MODRM_RM_MASK 0x07
/** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
#define DTRACE_EXPERIMENT
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** Pointer to a readonly hypervisor trap record. */
typedef const struct TRPMGCHYPER *PCTRPMGCHYPER;
/**
* A hypervisor trap record.
* This contains information about a handler for a instruction range.
*
* @remark This must match what TRPM_HANDLER outputs.
*/
typedef struct TRPMGCHYPER
{
/** The start address. */
/** The end address. (exclusive)
* If NULL the it's only for the instruction at pvStartEIP. */
/**
* The handler.
*
* @returns VBox status code
* VINF_SUCCESS means we've handled the trap.
* Any other error code means returning to the host context.
* @param pVM The VM handle.
* @param pRegFrame The register frame.
* @param uUser The user argument.
*/
/** Whatever the handler desires to put here. */
} TRPMGCHYPER;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Defined in VMMGC0.asm or VMMGC99.asm.
* @{ */
/** @} */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
RT_C_DECLS_BEGIN /* addressed from asm (not called so no DECLASM). */
/**
* Exits the trap, called when exiting a trap handler.
*
* Will reset the trap if it's not a guest trap or the trap
* is already handled. Will process resume guest FFs.
*
* @returns rc, can be adjusted if its VINF_SUCCESS or something really bad
* happened.
* @param pVM VM handle.
* @param pVCpu The virtual CPU handle.
* @param rc The VBox status code to return.
* @param pRegFrame Pointer to the register frame for the trap.
*
* @remarks This must not be used for hypervisor traps, only guest traps.
*/
{
/* Reset trap? */
if ( rc != VINF_EM_RAW_GUEST_TRAP
&& rc != VINF_EM_RAW_RING_SWITCH_INT)
#ifdef VBOX_HIGH_RES_TIMERS_HACK
/*
* We should poll the timers occasionally.
* We must *NOT* do this too frequently as it adds a significant overhead
* and it'll kill us if the trap load is high. (See #1354.)
* (The heuristic is not very intelligent, we should really check trap
* frequency etc. here, but alas, we lack any such information atm.)
*/
static unsigned s_iTimerPoll = 0;
if (rc == VINF_SUCCESS)
{
if (!(++s_iTimerPoll & 0xf))
{
Log2(("TMTimerPoll at %08RX32 - VM_FF_TM_VIRTUAL_SYNC=%d VM_FF_TM_VIRTUAL_SYNC=%d\n", pRegFrame->eip,
}
}
else
s_iTimerPoll = 0;
#endif
/* Clear pending inhibit interrupt state if required. (necessary for dispatching interrupts later on) */
{
Log2(("VM_FF_INHIBIT_INTERRUPTS at %08RX32 successor %RGv\n", pRegFrame->eip, EMGetInhibitInterruptsPC(pVCpu)));
{
/** @note we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here if the eip is the same as the inhibited instr address.
* Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
* force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
* break the guest. Sounds very unlikely, but such timing sensitive problem are not as rare as you might think.
*/
}
}
/*
* Pending resume-guest-FF?
* Or pending (A)PIC interrupt? Windows XP will crash if we delay APIC interrupts.
*/
if ( rc == VINF_SUCCESS
&& ( VM_FF_ISPENDING(pVM, VM_FF_TM_VIRTUAL_SYNC | VM_FF_REQUEST | VM_FF_PGM_NO_MEMORY | VM_FF_PDM_DMA)
|| VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TIMER | VMCPU_FF_TO_R3 | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
)
)
{
/* The out of memory condition naturally outranks the others. */
/* Pending Ring-3 action. */
{
}
/* Pending timer action. */
/* The Virtual Sync clock has stopped. */
/* DMA work pending? */
/* Pending request packets might contain actions that need immediate
attention, such as pending hardware interrupts. */
/* Pending interrupt: dispatch it. */
)
{
rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)u8Interrupt, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_HARDWARE_INT, uOldActiveVector);
/* can't return if successful */
/* Stop the profile counter that was started in TRPMGCHandlersA.asm */
/* Assert the trap and go to the recompiler to dispatch it. */
}
/*
* Try sync CR3?
*/
{
#if 1
rc = PGMSyncCR3(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR3(pVCpu), CPUMGetGuestCR4(pVCpu), VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
#else
#endif
}
}
&& ( pRegFrame->eflags.Bits.u2IOPL < (unsigned)(pRegFrame->ss & X86_SEL_RPL) || pRegFrame->eflags.Bits.u1VM))
, ("rc=%Rrc\neflags=%RX32 ss=%RTsel IOPL=%d\n", rc, pRegFrame->eflags.u32, pRegFrame->ss, pRegFrame->eflags.Bits.u2IOPL));
return rc;
}
/**
* \#DB (Debug event) handler.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
/*
* We currently don't make use of the X86_DR7_GD bit, but
* there might come a time when we do.
*/
("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n",
/*
* Now leave the rest to the DBGF.
*/
if (rc == VINF_EM_RAW_GUEST_TRAP)
return rc;
}
/**
* \#DB (Debug event) handler for the hypervisor code.
*
* This is mostly the same as TRPMGCTrap01Handler, but we skip the PGM auto
* mapping set as well as the default trap exit path since they are both really
* bad ideas in this context.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
/*
* We currently don't make use of the X86_DR7_GD bit, but
* there might come a time when we do.
*/
("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n",
/*
* Now leave the rest to the DBGF.
*/
return rc;
}
/**
* NMI handler, for when we are using NMIs to debug things.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
* @remark This is not hooked up unless you're building with VBOX_WITH_NMI defined.
*/
{
return VERR_TRPM_DONT_PANIC;
}
/**
* NMI handler, for when we are using NMIs to debug things.
*
* This is the handler we're most likely to hit when the NMI fires (it is
* unlikely that we'll be stuck in guest code).
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
* @remark This is not hooked up unless you're building with VBOX_WITH_NMI defined.
*/
{
return VERR_TRPM_DONT_PANIC;
}
/**
* \#BP (Breakpoint) handler.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
int rc;
/*
* PATM is using INT3s, let them have a go first.
*/
{
if (rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_PATCH_INT3 || rc == VINF_PATM_DUPLICATE_FUNCTION)
{
return rc;
}
}
/* anything we should do with this? Schedule it in GC? */
return rc;
}
/**
* \#BP (Breakpoint) handler.
*
* This is similar to TRPMGCTrap03Handler but we bits which are potentially
* harmful to us (common trap exit and the auto mapping set).
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
/*
* Hand it over to DBGF.
*/
return rc;
}
/**
* Trap handler for illegal opcode fault (\#UD).
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
int rc;
{
/*
* Decode the instruction.
*/
rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid,
if (RT_FAILURE(rc))
{
Log(("TRPMGCTrap06Handler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n", pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
return rc;
}
if (RT_FAILURE(rc))
{
return rc;
}
/*
* UD2 in a patch?
* Note! PATMGCHandleIllegalInstrTrap doesn't always return.
*/
{
LogFlow(("TRPMGCTrap06Handler: -> PATMRCHandleIllegalInstrTrap\n"));
/** @todo These tests are completely unnecessary, should just follow the
* flow and return at the end of the function. */
if ( rc == VINF_SUCCESS
|| rc == VINF_EM_RAW_EMULATE_INSTR
|| rc == VINF_EM_RESCHEDULE)
{
return rc;
}
}
/*
* Speed up dtrace and don't entrust invalid lock sequences to the recompiler.
*/
{
#ifdef DTRACE_EXPERIMENT /** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
#else
#endif
}
/*
* Handle MONITOR - it causes an #UD exception instead of #GP when not executed in ring 0.
*/
{
LogFlow(("TRPMGCTrap06Handler: -> EMInterpretInstructionCPU\n"));
}
/* Never generate a raw trap here; it might be an instruction, that requires emulation. */
else
{
LogFlow(("TRPMGCTrap06Handler: -> VINF_EM_RAW_EMULATE_INSTR\n"));
}
}
else
{
LogFlow(("TRPMGCTrap06Handler: -> TRPMForwardTrap\n"));
}
return rc;
}
/**
* Trap handler for device not present fault (\#NM).
*
* Device not available, FP or (F)WAIT instruction.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
return rc;
}
/**
* \#NP ((segment) Not Present) handler.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
/*
* Try to detect instruction by opcode which caused trap.
* XXX note: this code may cause \#PF (trap e) or \#GP (trap d) while
* accessing user code. need to handle it somehow in future!
*/
if ( SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid,
== VINF_SUCCESS)
{
/*
* First skip possible instruction prefixes, such as:
* OS, AS
* CS:, DS:, ES:, SS:, FS:, GS:
* REPE, REPNE
*
* note: Currently we supports only up to 4 prefixes per opcode, more
* prefixes (normally not used anyway) will cause trap d in guest.
* note: Instruction length in IA-32 may be up to 15 bytes, we dont
* check this issue, its too hard.
*/
for (unsigned i = 0; i < 4; i++)
{
)
break;
pu8Code++;
}
/*
* Detect right switch using a callgate.
*
* We recognize the following causes for the trap 0b:
* CALL FAR, CALL FAR []
* JMP FAR, JMP FAR []
* IRET (may cause a task switch)
*
* Note: we can't detect whether the trap was caused by a call to a
* callgate descriptor or it is a real trap 0b due to a bad selector.
* In both situations we'll pass execution to our recompiler so we don't
* have to worry.
* If we wanted to do better detection, we have set GDT entries to callgate
* descriptors pointing to our own handlers.
*/
/** @todo not sure about IRET, may generate Trap 0d (\#GP), NEED TO CHECK! */
)
{
/*
* Got potential call to callgate.
* We simply return execution to the recompiler to do emulation
* starting from the instruction which caused the trap.
*/
Log6(("TRPMGC0b: %Rrc (%04x:%08x) (CG)\n", VINF_EM_RAW_RING_SWITCH, pRegFrame->cs, pRegFrame->eip));
return VINF_EM_RAW_RING_SWITCH;
}
}
/*
* Pass trap 0b as is to the recompiler in all other cases.
*/
return VINF_EM_RAW_GUEST_TRAP;
}
/**
* \#GP (General Protection Fault) handler for Ring-0 privileged instructions.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pVM The VM handle.
* @param pVCpu The virtual CPU handle.
* @param pRegFrame Pointer to the register frame for the trap.
* @param pCpu The opcode info.
* @param PC The program counter corresponding to cs:eip in pRegFrame.
*/
static int trpmGCTrap0dHandlerRing0(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
{
int rc;
/*
*/
{
case OP_INT3:
/*
* Little hack to make the code below not fail
*/
/* fallthru */
case OP_INT:
{
{
/* Int 3 replacement patch? */
{
AssertFailed();
}
}
rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT, 0xd);
pVCpu->trpm.s.uActiveVector = (pVCpu->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
}
#ifdef PATM_EMULATE_SYSENTER
case OP_SYSEXIT:
case OP_SYSRET:
#endif
case OP_HLT:
/* If it's in patch code, defer to ring-3. */
break;
/*
* These instructions are used by PATM and CASM for finding
* dangerous non-trapping instructions. Thus, since all
* scanning and patching is done in ring-3 we'll have to
* return to ring-3 on the first encounter of these instructions.
*/
case OP_MOV_CR:
case OP_MOV_DR:
break;
case OP_INVLPG:
case OP_LLDT:
case OP_STI:
case OP_RDTSC: /* just in case */
case OP_RDPMC:
case OP_CLTS:
case OP_WBINVD: /* nop */
case OP_RDMSR:
case OP_WRMSR:
{
if (rc == VERR_EM_INTERPRETER)
}
}
}
/**
* \#GP (General Protection Fault) handler for Ring-3.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pVM The VM handle.
* @param pVCpu The virtual CPU handle.
* @param pRegFrame Pointer to the register frame for the trap.
* @param pCpu The opcode info.
* @param PC The program counter corresponding to cs:eip in pRegFrame.
*/
static int trpmGCTrap0dHandlerRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
{
int rc;
{
/*
* INT3 and INT xx are ring-switching.
* (The shadow IDT will have set the entries to DPL=0, that's why we're here.)
*/
case OP_INT3:
/*
* Little hack to make the code below not fail
*/
/* fall thru */
case OP_INT:
{
rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT, 0xd);
pVCpu->trpm.s.uActiveVector = (pVCpu->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
}
/*
* SYSCALL, SYSENTER, INTO and BOUND are also ring-switchers.
*/
case OP_SYSCALL:
case OP_SYSENTER:
#ifdef PATM_EMULATE_SYSENTER
if (rc == VINF_SUCCESS)
/* else no break; */
#endif
case OP_BOUND:
case OP_INTO:
/*
* Handle virtualized TSC & PMC reads, just in case.
*/
case OP_RDTSC:
case OP_RDPMC:
{
if (rc == VERR_EM_INTERPRETER)
}
/*
* STI and CLI are I/O privileged, i.e. if IOPL
*/
case OP_STI:
case OP_CLI:
{
{
}
break;
}
}
/*
* A genuine guest fault.
*/
}
/**
* Emulates RDTSC for the \#GP handler.
*
* @returns VINF_SUCCESS or VINF_EM_RAW_EMULATE_INSTR.
*
* @param pVM Pointer to the shared VM structure.
* @param pVCpu The virtual CPU handle.
* @param pRegFrame Pointer to the register frame for the trap.
* This will be updated on successful return.
*/
{
return trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame); /* will trap (optimize later). */
}
/**
* \#GP (General Protection Fault) handler.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pVM The VM handle.
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
*/
{
LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%08RX32 uErr=%RGv\n", pRegFrame->ss, pRegFrame->eip, pTrpmCpu->uActiveErrorCode));
/*
* Convert and validate CS.
*/
if (RT_FAILURE(rc))
{
Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n",
}
/*
* Disassemble the instruction.
*/
if (RT_FAILURE(rc))
{
}
/*
* Optimize RDTSC traps.
* Some guests (like Solaris) are using RDTSC all over the place and
* will end up trapping a *lot* because of that.
*
* Note: it's no longer safe to access the instruction opcode directly due to possible stale code TLB entries
*/
/*
* Deal with I/O port access.
*/
{
if (IOM_SUCCESS(rcStrict))
}
/*
* Deal with Ring-0 (privileged instructions)
*/
/*
* Deal with Ring-3 GPs.
*/
/*
* Deal with v86 code.
*
* We always set IOPL to zero which makes e.g. pushf fault in V86
* mode. The guest might use IOPL=3 and therefore not expect a #GP.
* Simply fall back to the recompiler to emulate this instruction if
* that's the case. To get the correct we must use CPUMRawGetEFlags.
*/
Log3(("TRPM #GP V86: cs:eip=%04x:%08x IOPL=%d efl=%08x\n", pRegFrame->cs, pRegFrame->eip, eflags.Bits.u2IOPL, eflags.u));
{
}
}
/**
* \#GP (General Protection Fault) handler.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
LogFlow(("TRPMGC0d: %04x:%08x err=%x\n", pRegFrame->cs, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode));
switch (rc)
{
case VINF_EM_RAW_GUEST_TRAP:
break;
/* no break; */
case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
case VINF_IOM_R3_IOPORT_READ:
case VINF_IOM_R3_IOPORT_WRITE:
case VINF_IOM_R3_MMIO_WRITE:
case VINF_IOM_R3_MMIO_READ:
case VINF_PATM_PATCH_INT3:
case VINF_EM_NO_MEMORY:
case VINF_EM_RAW_TO_R3:
case VINF_EM_PENDING_REQUEST:
case VINF_EM_HALT:
case VINF_SUCCESS:
break;
default:
break;
}
return rc;
}
/**
* \#PF (Page Fault) handler.
*
* Calls PGM which does the actual handling.
*
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed execution to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
LogFlow(("TRPMGC0e: %04x:%08x err=%x cr2=%08x\n", pRegFrame->cs, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode, (uint32_t)pVCpu->trpm.s.uActiveCR2));
/*
* This is all PGM stuff.
*/
int rc = PGMTrap0eHandler(pVCpu, pVCpu->trpm.s.uActiveErrorCode, pRegFrame, (RTGCPTR)pVCpu->trpm.s.uActiveCR2);
switch (rc)
{
break;
case VINF_EM_RAW_GUEST_TRAP:
{
return VINF_PATM_PATCH_TRAP_PF;
}
break;
/* no break; */
case VINF_IOM_R3_MMIO_READ:
case VINF_IOM_R3_MMIO_WRITE:
case VINF_SUCCESS:
case VINF_EM_RAW_TO_R3:
case VINF_EM_PENDING_REQUEST:
case VINF_EM_NO_MEMORY:
case VINF_CSAM_PENDING_ACTION:
case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
break;
default:
AssertMsg(PATMIsPatchGCAddr(pVM, pRegFrame->eip) == false, ("Patch address for return code %d. eip=%08x\n", rc, pRegFrame->eip));
break;
}
return rc;
}
/**
* Scans for the EIP in the specified array of trap handlers.
*
* If we don't fine the EIP, we'll panic.
*
* @returns VBox status code.
*
* @param pVM The VM handle.
* @param pRegFrame Pointer to the register frame for the trap.
* @param paHandlers The array of trap handler records.
* @param pEndRecord The end record (exclusive).
*/
static int trpmGCHyperGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, PCTRPMGCHYPER paHandlers, PCTRPMGCHYPER pEndRecord)
{
#if 0 /// @todo later
/*
* Start by doing a kind of binary search.
*/
unsigned iStart = 0;
unsigned i = iEnd / 2;
#endif
/*
* Do a linear search now (in case the array wasn't properly sorted).
*/
{
}
return VERR_TRPM_DONT_PANIC;
}
/**
* Hypervisor \#NP ((segment) Not Present) handler.
*
* Scans for the EIP in the registered trap handlers.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed back to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
return trpmGCHyperGeneric(TRPMCPU_2_VM(pTrpmCpu), pRegFrame, g_aTrap0bHandlers, g_aTrap0bHandlersEnd);
}
/**
* Hypervisor \#GP (General Protection Fault) handler.
*
* Scans for the EIP in the registered trap handlers.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed back to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
return trpmGCHyperGeneric(TRPMCPU_2_VM(pTrpmCpu), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
}
/**
* Hypervisor \#PF (Page Fault) handler.
*
* Scans for the EIP in the registered trap handlers.
*
* @returns VBox status code.
* VINF_SUCCESS means we completely handled this trap,
* other codes are passed back to host context.
*
* @param pTrpmCpu Pointer to TRPMCPU data (within VM).
* @param pRegFrame Pointer to the register frame for the trap.
* @internal
*/
{
return trpmGCHyperGeneric(TRPMCPU_2_VM(pTrpmCpu), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
}
/**
* Deal with hypervisor traps occurring when resuming execution on a trap.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pRegFrame Register frame.
* @param uUser User arg.
*/
{
Log(("********************************************************\n"));
Log(("********************************************************\n"));
if (uUser & TRPM_TRAP_IN_HYPER)
{
/*
* Check that there is still some stack left, if not we'll flag
* a guru meditation (the alternative is a triple fault).
*/
{
LogRel(("trpmGCTrapInGeneric: ran out of stack: esp=#x cbStackUsed=%#x\n", pRegFrame->esp, cbStackUsed));
return VERR_TRPM_DONT_PANIC;
}
/*
* Just zero the register containing the selector in question.
* We'll deal with the actual stale or troublesome selector value in
* the outermost trap frame.
*/
switch (uUser & TRPM_TRAP_IN_OP_MASK)
{
case TRPM_TRAP_IN_MOV_GS:
break;
case TRPM_TRAP_IN_MOV_FS:
return VINF_SUCCESS;
default:
return VERR_TRPM_BAD_TRAP_IN_OP;
}
}
else
{
/*
* Reconstruct the guest context and switch to the recompiler.
* We ASSUME we're only at
*/
int rc;
switch (uUser)
{
/*
* This will only occur when resuming guest code in a trap handler!
*/
/* @note ASSUMES esp points to the temporary guest CPUMCTXCORE!!! */
case TRPM_TRAP_IN_MOV_GS:
case TRPM_TRAP_IN_MOV_FS:
case TRPM_TRAP_IN_MOV_ES:
case TRPM_TRAP_IN_MOV_DS:
{
/* Just copy the whole thing; several selector registers, eip (etc) and eax are not yet in pRegFrame. */
CtxCore = *pTempGuestCtx;
break;
}
/*
* This will only occur when resuming guest code!
*/
case TRPM_TRAP_IN_IRET:
break;
/*
* This will only occur when resuming V86 guest code!
*/
case TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86:
break;
default:
return VERR_TRPM_BAD_TRAP_IN_OP;
}
}
AssertMsgFailed(("Impossible!\n"));
return VERR_TRPM_IPE_3;
}