TRPMGCHandlers.cpp revision 0520068cfb8f9f2ce7e9bb6fe98399da2aecfab5
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/* $Id$ */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @file
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * TRPM - Guest Context Trap Handlers, CPP part
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * available from http://www.virtualbox.org. This file is free software;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * General Public License (GPL) as published by the Free Software
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * additional information or have any questions.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync */
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Header Files *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define LOG_GROUP LOG_GROUP_TRPM
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/selm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/iom.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/pgm.h>
da957c069c2a3c582fe265ff88170ce4c42b499dvboxsync#include <VBox/pdm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/dbgf.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/em.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/csam.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/patm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/mm.h>
9496f2d398b49813176939d7a339ae513d5175efvboxsync#include <VBox/cpum.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include "TRPMInternal.h"
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/vm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/vmm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/param.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/err.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/dis.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/disopcode.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/x86.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/log.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/tm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <iprt/asm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <iprt/assert.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Defined Constants And Macros *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/* still here. MODR/M byte parsing */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define X86_OPCODE_MODRM_MOD_MASK 0xc0
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define X86_OPCODE_MODRM_REG_MASK 0x38
9496f2d398b49813176939d7a339ae513d5175efvboxsync#define X86_OPCODE_MODRM_RM_MASK 0x07
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync#define DTRACE_EXPERIMENT
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/*******************************************************************************
9496f2d398b49813176939d7a339ae513d5175efvboxsync* Structures and Typedefs *
9496f2d398b49813176939d7a339ae513d5175efvboxsync*******************************************************************************/
9496f2d398b49813176939d7a339ae513d5175efvboxsync/** Pointer to a readonly hypervisor trap record. */
9496f2d398b49813176939d7a339ae513d5175efvboxsynctypedef const struct TRPMGCHYPER *PCTRPMGCHYPER;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * A hypervisor trap record.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * This contains information about a handler for a instruction range.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @remark This must match what TRPM_HANDLER outputs.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsynctypedef struct TRPMGCHYPER
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The start address. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uintptr_t uStartEIP;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The end address. (exclusive)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * If NULL the it's only for the instruction at pvStartEIP. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uintptr_t uEndEIP;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * The handler.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code
9496f2d398b49813176939d7a339ae513d5175efvboxsync * VINF_SUCCESS means we've handled the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Any other error code means returning to the host context.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pVM The VM handle.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame The register frame.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param uUser The user argument.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync DECLRCCALLBACKMEMBER(int, pfnHandler, (PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser));
9496f2d398b49813176939d7a339ae513d5175efvboxsync /** Whatever the handler desires to put here. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync uintptr_t uUser;
9496f2d398b49813176939d7a339ae513d5175efvboxsync} TRPMGCHYPER;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/*******************************************************************************
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync* Global Variables *
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync*******************************************************************************/
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync__BEGIN_DECLS
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync/** Defined in VMMGC0.asm or VMMGC99.asm.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @{ */
9496f2d398b49813176939d7a339ae513d5175efvboxsyncextern const TRPMGCHYPER g_aTrap0bHandlers[1];
9496f2d398b49813176939d7a339ae513d5175efvboxsyncextern const TRPMGCHYPER g_aTrap0bHandlersEnd[1];
9496f2d398b49813176939d7a339ae513d5175efvboxsyncextern const TRPMGCHYPER g_aTrap0dHandlers[1];
9496f2d398b49813176939d7a339ae513d5175efvboxsyncextern const TRPMGCHYPER g_aTrap0dHandlersEnd[1];
9496f2d398b49813176939d7a339ae513d5175efvboxsyncextern const TRPMGCHYPER g_aTrap0eHandlers[1];
9496f2d398b49813176939d7a339ae513d5175efvboxsyncextern const TRPMGCHYPER g_aTrap0eHandlersEnd[1];
9496f2d398b49813176939d7a339ae513d5175efvboxsync/** @} */
9496f2d398b49813176939d7a339ae513d5175efvboxsync__END_DECLS
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Internal Functions *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync__BEGIN_DECLS /* addressed from asm (not called so no DECLASM). */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncDECLCALLBACK(int) trpmGCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync__END_DECLS
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Exits the trap, called when exiting a trap handler.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Will reset the trap if it's not a guest trap or the trap
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * is already handled. Will process resume guest FFs.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns rc, can be adjusted if its VINF_SUCCESS or something really bad
9496f2d398b49813176939d7a339ae513d5175efvboxsync * happened.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pVM VM handle.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param rc The VBox status code to return.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pRegFrame Pointer to the register frame for the trap.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic int trpmGCExitTrap(PVM pVM, int rc, PCPUMCTXCORE pRegFrame)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9496f2d398b49813176939d7a339ae513d5175efvboxsync uint32_t uOldActiveVector = pVCpu->trpm.s.uActiveVector;
9496f2d398b49813176939d7a339ae513d5175efvboxsync NOREF(uOldActiveVector);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Reset trap? */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if ( rc != VINF_EM_RAW_GUEST_TRAP
9496f2d398b49813176939d7a339ae513d5175efvboxsync && rc != VINF_EM_RAW_RING_SWITCH_INT)
9496f2d398b49813176939d7a339ae513d5175efvboxsync pVCpu->trpm.s.uActiveVector = ~0;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifdef VBOX_HIGH_RES_TIMERS_HACK
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * We should poll the timers occationally.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * We must *NOT* do this too frequently as it adds a significant overhead
9496f2d398b49813176939d7a339ae513d5175efvboxsync * and it'll kill us if the trap load is high. (See #1354.)
9496f2d398b49813176939d7a339ae513d5175efvboxsync * (The heuristic is not very intelligent, we should really check trap
9496f2d398b49813176939d7a339ae513d5175efvboxsync * frequency etc. here, but alas, we lack any such information atm.)
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync static unsigned s_iTimerPoll = 0;
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (rc == VINF_SUCCESS)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (!(++s_iTimerPoll & 0xf))
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync uint64_t cTicks = TMTimerPoll(pVM); NOREF(cTicks);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log2(("TMTimerPoll at %08RX32 returned %RX64 (VM_FF_TIMER=%d)\n", pRegFrame->eip, cTicks, VM_FF_ISPENDING(pVM, VM_FF_TIMER)));
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync else
9496f2d398b49813176939d7a339ae513d5175efvboxsync s_iTimerPoll = 0;
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Clear pending inhibit interrupt state if required. (necessary for dispatching interrupts later on) */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log2(("VM_FF_INHIBIT_INTERRUPTS at %08RX32 successor %RGv\n", pRegFrame->eip, EMGetInhibitInterruptsPC(pVM, pVCpu)));
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (pRegFrame->eip != EMGetInhibitInterruptsPC(pVM, pVCpu))
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync /** @note we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here if the eip is the same as the inhibited instr address.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
9496f2d398b49813176939d7a339ae513d5175efvboxsync * force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
9496f2d398b49813176939d7a339ae513d5175efvboxsync * break the guest. Sounds very unlikely, but such timing sensitive problem are not as rare as you might think.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync VM_FF_CLEAR(pVM, VM_FF_INHIBIT_INTERRUPTS);
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Pending resume-guest-FF?
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Or pending (A)PIC interrupt? Windows XP will crash if we delay APIC interrupts.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if ( rc == VINF_SUCCESS
9496f2d398b49813176939d7a339ae513d5175efvboxsync && VM_FF_ISPENDING(pVM, VM_FF_TO_R3 | VM_FF_TIMER | VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_REQUEST
9496f2d398b49813176939d7a339ae513d5175efvboxsync | VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL | VM_FF_PGM_NO_MEMORY))
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* The out of memory condition naturally outrang the others. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)))
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = VINF_EM_NO_MEMORY;
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Pending Ring-3 action. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if (VM_FF_ISPENDING(pVM, VM_FF_TO_R3))
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync VM_FF_CLEAR(pVM, VM_FF_TO_R3);
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = VINF_EM_RAW_TO_R3;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Pending timer action. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if (VM_FF_ISPENDING(pVM, VM_FF_TIMER))
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = VINF_EM_RAW_TIMER_PENDING;
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Pending interrupt: dispatch it. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if ( VM_FF_ISPENDING(pVM, VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC)
9496f2d398b49813176939d7a339ae513d5175efvboxsync && !VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS)
9496f2d398b49813176939d7a339ae513d5175efvboxsync && PATMAreInterruptsEnabledByCtxCore(pVM, pRegFrame)
9496f2d398b49813176939d7a339ae513d5175efvboxsync )
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync uint8_t u8Interrupt;
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = PDMGetInterrupt(pVM, &u8Interrupt);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log(("trpmGCExitTrap: u8Interrupt=%d (%#x) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
9496f2d398b49813176939d7a339ae513d5175efvboxsync AssertFatalMsgRC(rc, ("PDMGetInterrupt failed with %Rrc\n", rc));
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)u8Interrupt, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_HARDWARE_INT, uOldActiveVector);
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* can't return if successful */
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(rc != VINF_SUCCESS);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Stop the profile counter that was started in TRPMGCHandlersA.asm */
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(uOldActiveVector <= 16);
9496f2d398b49813176939d7a339ae513d5175efvboxsync STAM_PROFILE_ADV_STOP(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /* Assert the trap and go to the recompiler to dispatch it. */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync TRPMAssertTrap(pVCpu, u8Interrupt, TRPM_HARDWARE_INT);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync STAM_PROFILE_ADV_START(&pVM->trpm.s.aStatGCTraps[uOldActiveVector], a);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = VINF_EM_RAW_INTERRUPT_PENDING;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync }
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /*
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * Try sync CR3?
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync else if (VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL))
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync#if 1
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = PGMSyncCR3(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR3(pVCpu), CPUMGetGuestCR4(pVCpu), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3));
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync#else
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = VINF_PGM_SYNC_CR3;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync#endif
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync else if (VM_FF_ISPENDING(pVM, VM_FF_REQUEST))
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = VINF_EM_PENDING_REQUEST;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync }
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync AssertMsg( rc != VINF_SUCCESS
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync || ( pRegFrame->eflags.Bits.u1IF
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync && ( pRegFrame->eflags.Bits.u2IOPL < (unsigned)(pRegFrame->ss & X86_SEL_RPL) || pRegFrame->eflags.Bits.u1VM))
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync , ("rc=%Rrc\neflags=%RX32 ss=%RTsel IOPL=%d\n", rc, pRegFrame->eflags.u32, pRegFrame->ss, pRegFrame->eflags.Bits.u2IOPL));
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync return rc;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync}
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync/**
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * \#DB (Debug event) handler.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync *
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * @returns VBox status code.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * VINF_SUCCESS means we completely handled this trap,
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * other codes are passed execution to host context.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync *
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * @param pRegFrame Pointer to the register frame for the trap.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * @internal
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsyncDECLASM(int) TRPMGCTrap01Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync{
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync RTGCUINTREG uDr6 = ASMGetAndClearDR6();
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync PVM pVM = TRPMCPU2VM(pTrpmCpu);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync LogFlow(("TRPMGC01: cs:eip=%04x:%08x uDr6=%RTreg\n", pRegFrame->cs, pRegFrame->eip, uDr6));
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * We currently don't make sure of the X86_DR7_GD bit, but
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * there might come a time when we do.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if ((uDr6 & X86_DR6_BD) == X86_DR6_BD)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync AssertReleaseMsgFailed(("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n",
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync ASMGetDR7(), CPUMGetHyperDR7(pVCpu), uDr6));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return VERR_NOT_IMPLEMENTED;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AssertReleaseMsg(!(uDr6 & X86_DR6_BT), ("X86_DR6_BT is impossible!\n"));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Now leave the rest to the DBGF.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = DBGFGCTrap01Handler(pVM, pRegFrame, uDr6);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (rc == VINF_EM_RAW_GUEST_TRAP)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync CPUMSetGuestDR6(pVCpu, uDr6);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = trpmGCExitTrap(pVM, rc, pRegFrame);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync Log6(("TRPMGC01: %Rrc (%04x:%08x %RTreg)\n", rc, pRegFrame->cs, pRegFrame->eip, uDr6));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync return rc;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * NMI handler, for when we are using NMIs to debug things.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VINF_SUCCESS means we completely handled this trap,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to the register frame for the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @internal
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @remark This is not hooked up unless you're building with VBOX_WITH_NMI defined.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncDECLASM(int) TRPMGCTrap02Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("TRPMGCTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RTLogComPrintf("TRPMGCTrap02Handler: cs:eip=%04x:%08x\n", pRegFrame->cs, pRegFrame->eip);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return VERR_TRPM_DONT_PANIC;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * \#BP (Breakpoint) handler.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * VINF_SUCCESS means we completely handled this trap,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to the register frame for the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @internal
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncDECLASM(int) TRPMGCTrap03Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("TRPMGC03: %04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVM pVM = TRPMCPU2VM(pTrpmCpu);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Both PATM are using INT3s, let them have a go first.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if ( (pRegFrame->ss & X86_SEL_RPL) == 1
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && !pRegFrame->eflags.Bits.u1VM)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = PATMHandleInt3PatchTrap(pVM, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_PATCH_INT3 || rc == VINF_PATM_DUPLICATE_FUNCTION)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log6(("TRPMGC03: %Rrc (%04x:%08x) (PATM)\n", rc, pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = DBGFGCTrap03Handler(pVM, pRegFrame);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* anything we should do with this? Schedule it in GC? */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log6(("TRPMGC03: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs, pRegFrame->eip));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync return rc;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync}
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * Trap handler for illegal opcode fault (\#UD).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VINF_SUCCESS means we completely handled this trap,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param pRegFrame Pointer to the register frame for the trap.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @internal
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncDECLASM(int) TRPMGCTrap06Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("TRPMGC06: %04x:%08x efl=%x\n", pRegFrame->cs, pRegFrame->eip, pRegFrame->eflags.u32));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync PVM pVM = TRPMCPU2VM(pTrpmCpu);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync int rc;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (CPUMGetGuestCPL(pVCpu, pRegFrame) == 0)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync /*
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * Decode the instruction.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RTGCPTR PC;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (RT_FAILURE(rc))
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync Log(("TRPMGCTrap06Handler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n", pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync Log6(("TRPMGC06: %Rrc (%04x:%08x) (SELM)\n", rc, pRegFrame->cs, pRegFrame->eip));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync return rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync DISCPUSTATE Cpu;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint32_t cbOp;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = EMInterpretDisasOneEx(pVM, pVCpu, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (RT_FAILURE(rc))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync rc = trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log6(("TRPMGC06: %Rrc (%04x:%08x) (EM)\n", rc, pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * UD2 in a patch?
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if ( Cpu.pCurInstr->opcode == OP_ILLUD2
9496f2d398b49813176939d7a339ae513d5175efvboxsync && PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = PATMGCHandleIllegalInstrTrap(pVM, pRegFrame);
9496f2d398b49813176939d7a339ae513d5175efvboxsync /** @todo These tests are completely unnecessary, should just follow the
9496f2d398b49813176939d7a339ae513d5175efvboxsync * flow and return at the end of the function. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if ( rc == VINF_SUCCESS
9496f2d398b49813176939d7a339ae513d5175efvboxsync || rc == VINF_EM_RAW_EMULATE_INSTR
9496f2d398b49813176939d7a339ae513d5175efvboxsync || rc == VINF_PATM_DUPLICATE_FUNCTION
9496f2d398b49813176939d7a339ae513d5175efvboxsync || rc == VINF_PATM_PENDING_IRQ_AFTER_IRET
9496f2d398b49813176939d7a339ae513d5175efvboxsync || rc == VINF_EM_RESCHEDULE)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = trpmGCExitTrap(pVM, rc, pRegFrame);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log6(("TRPMGC06: %Rrc (%04x:%08x) (PATM)\n", rc, pRegFrame->cs, pRegFrame->eip));
9496f2d398b49813176939d7a339ae513d5175efvboxsync return rc;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Speed up dtrace and don't entrust invalid lock sequences to the recompiler.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if (Cpu.prefix & PREFIX_LOCK)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log(("TRPMGCTrap06Handler: pc=%08x op=%d\n", pRegFrame->eip, Cpu.pCurInstr->opcode));
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifdef DTRACE_EXPERIMENT /** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(!PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip));
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(rc == VINF_EM_RAW_GUEST_TRAP);
9496f2d398b49813176939d7a339ae513d5175efvboxsync#else
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = VINF_EM_RAW_EMULATE_INSTR;
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Handle MONITOR - it causes an #UD exception instead of #GP when not executed in ring 0.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if (Cpu.pCurInstr->opcode == OP_MONITOR)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync uint32_t cbIgnored;
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = EMInterpretInstructionCPU(pVM, pVCpu, &Cpu, pRegFrame, PC, &cbIgnored);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (RT_LIKELY(RT_SUCCESS(rc)))
9496f2d398b49813176939d7a339ae513d5175efvboxsync pRegFrame->eip += Cpu.opsize;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Never generate a raw trap here; it might be an instruction, that requires emulation. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync else
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = VINF_EM_RAW_EMULATE_INSTR;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync else
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(rc == VINF_EM_RAW_GUEST_TRAP);
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = trpmGCExitTrap(pVM, rc, pRegFrame);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log6(("TRPMGC06: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs, pRegFrame->eip));
9496f2d398b49813176939d7a339ae513d5175efvboxsync return rc;
9496f2d398b49813176939d7a339ae513d5175efvboxsync}
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Trap handler for device not present fault (\#NM).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Device not available, FP or (F)WAIT instruction.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * VINF_SUCCESS means we completely handled this trap,
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to the register frame for the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @internal
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncDECLASM(int) TRPMGCTrap07Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("TRPMGC07: %04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVM pVM = TRPMCPU2VM(pTrpmCpu);
9496f2d398b49813176939d7a339ae513d5175efvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync int rc = CPUMHandleLazyFPU(pVCpu);
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log6(("TRPMGC07: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * \#NP ((segment) Not Present) handler.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VINF_SUCCESS means we completely handled this trap,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to the register frame for the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @internal
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncDECLASM(int) TRPMGCTrap0bHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("TRPMGC0b: %04x:%08x\n", pRegFrame->cs, pRegFrame->eip));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVM pVM = TRPMCPU2VM(pTrpmCpu);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync /*
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * Try to detect instruction by opcode which caused trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * XXX note: this code may cause \#PF (trap e) or \#GP (trap d) while
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * accessing user code. need to handle it somehow in future!
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RTGCPTR GCPtr;
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync if (SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &GCPtr) == VINF_SUCCESS)
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint8_t *pu8Code = (uint8_t *)(uintptr_t)GCPtr;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * First skip possible instruction prefixes, such as:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * OS, AS
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * CS:, DS:, ES:, SS:, FS:, GS:
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * REPE, REPNE
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync *
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync * note: Currently we supports only up to 4 prefixes per opcode, more
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync * prefixes (normally not used anyway) will cause trap d in guest.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * note: Instruction length in IA-32 may be up to 15 bytes, we dont
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * check this issue, its too hard.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync for (unsigned i = 0; i < 4; i++)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if ( pu8Code[0] != 0xf2 /* REPNE/REPNZ */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && pu8Code[0] != 0xf3 /* REP/REPE/REPZ */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && pu8Code[0] != 0x2e /* CS: */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && pu8Code[0] != 0x36 /* SS: */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && pu8Code[0] != 0x3e /* DS: */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && pu8Code[0] != 0x26 /* ES: */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && pu8Code[0] != 0x64 /* FS: */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync && pu8Code[0] != 0x65 /* GS: */
9496f2d398b49813176939d7a339ae513d5175efvboxsync && pu8Code[0] != 0x66 /* OS */
9496f2d398b49813176939d7a339ae513d5175efvboxsync && pu8Code[0] != 0x67 /* AS */
9496f2d398b49813176939d7a339ae513d5175efvboxsync )
9496f2d398b49813176939d7a339ae513d5175efvboxsync break;
9496f2d398b49813176939d7a339ae513d5175efvboxsync pu8Code++;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Detect right switch using a callgate.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * We recognize the following causes for the trap 0b:
9496f2d398b49813176939d7a339ae513d5175efvboxsync * CALL FAR, CALL FAR []
9496f2d398b49813176939d7a339ae513d5175efvboxsync * JMP FAR, JMP FAR []
7ff8f890c69a5c0a5f7a4c36308eabf2dbe4995cvboxsync * IRET (may cause a task switch)
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Note: we can't detect whether the trap was caused by a call to a
9496f2d398b49813176939d7a339ae513d5175efvboxsync * callgate descriptor or it is a real trap 0b due to a bad selector.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * In both situations we'll pass execution to our recompiler so we don't
9496f2d398b49813176939d7a339ae513d5175efvboxsync * have to worry.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * If we wanted to do better detection, we have set GDT entries to callgate
9496f2d398b49813176939d7a339ae513d5175efvboxsync * descriptors pointing to our own handlers.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync /** @todo not sure about IRET, may generate Trap 0d (\#GP), NEED TO CHECK! */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if ( pu8Code[0] == 0x9a /* CALL FAR */
9496f2d398b49813176939d7a339ae513d5175efvboxsync || ( pu8Code[0] == 0xff /* CALL FAR [] */
9496f2d398b49813176939d7a339ae513d5175efvboxsync && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x18)
9496f2d398b49813176939d7a339ae513d5175efvboxsync || pu8Code[0] == 0xea /* JMP FAR */
9496f2d398b49813176939d7a339ae513d5175efvboxsync || ( pu8Code[0] == 0xff /* JMP FAR [] */
9496f2d398b49813176939d7a339ae513d5175efvboxsync && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x28)
9496f2d398b49813176939d7a339ae513d5175efvboxsync || pu8Code[0] == 0xcf /* IRET */
9496f2d398b49813176939d7a339ae513d5175efvboxsync )
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync {
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /*
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * Got potential call to callgate.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * We simply return execution to the recompiler to do emulation
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * starting from the instruction which caused the trap.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync pTrpmCpu->uActiveVector = ~0;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync Log6(("TRPMGC0b: %Rrc (%04x:%08x) (CG)\n", VINF_EM_RAW_RING_SWITCH, pRegFrame->cs, pRegFrame->eip));
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync return VINF_EM_RAW_RING_SWITCH;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync }
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync }
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /*
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync * Pass trap 0b as is to the recompiler in all other cases.
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync Log6(("TRPMGC0b: %Rrc (%04x:%08x)\n", VINF_EM_RAW_GUEST_TRAP, pRegFrame->cs, pRegFrame->eip));
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync return VINF_EM_RAW_GUEST_TRAP;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync}
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * \#GP (General Protection Fault) handler for Ring-0 privileged instructions.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns VBox status code.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * VINF_SUCCESS means we completely handled this trap,
9496f2d398b49813176939d7a339ae513d5175efvboxsync * other codes are passed execution to host context.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pVM The VM handle.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pRegFrame Pointer to the register frame for the trap.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pCpu The opcode info.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param PC The program counter corresponding to cs:eip in pRegFrame.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic int trpmGCTrap0dHandlerRing0(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync int rc;
9496f2d398b49813176939d7a339ae513d5175efvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Try handle it here, if not return to HC and emulate/interpret it there.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync switch (pCpu->pCurInstr->opcode)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync case OP_INT3:
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Little hack to make the code below not fail
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync pCpu->param1.flags = USE_IMMEDIATE8;
9496f2d398b49813176939d7a339ae513d5175efvboxsync pCpu->param1.parval = 3;
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* fallthru */
9496f2d398b49813176939d7a339ae513d5175efvboxsync case OP_INT:
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(pCpu->param1.flags & USE_IMMEDIATE8);
9496f2d398b49813176939d7a339ae513d5175efvboxsync Assert(!(PATMIsPatchGCAddr(pVM, (RTRCPTR)PC)));
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (pCpu->param1.parval == 3)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Int 3 replacement patch? */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (PATMHandleInt3PatchTrap(pVM, pRegFrame) == VINF_SUCCESS)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AssertFailed();
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT, 0xd);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (RT_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pVCpu->trpm.s.uActiveVector = (pVCpu->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pVCpu->trpm.s.enmActiveType = TRPM_SOFTWARE_INT;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync }
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef PATM_EMULATE_SYSENTER
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync case OP_SYSEXIT:
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync case OP_SYSRET:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = PATMSysCall(pVM, pRegFrame, pCpu);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync case OP_HLT:
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync /* If it's in patch code, defer to ring-3. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (PATMIsPatchGCAddr(pVM, (RTRCPTR)PC))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pRegFrame->eip += pCpu->opsize;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_EM_HALT, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * These instructions are used by PATM and CASM for finding
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * dangerous non-trapping instructions. Thus, since all
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * scanning and patching is done in ring-3 we'll have to
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * return to ring-3 on the first encounter of these instructions.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_MOV_CR:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_MOV_DR:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* We can safely emulate control/debug register move instructions in patched code. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if ( !PATMIsPatchGCAddr(pVM, (RTRCPTR)PC)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync && !CSAMIsKnownDangerousInstr(pVM, (RTRCPTR)PC))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_INVLPG:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case OP_LLDT:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case OP_STI:
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync case OP_RDTSC: /* just in case */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_RDPMC:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_CLTS:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case OP_WBINVD: /* nop */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_RDMSR:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_WRMSR:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint32_t cbIgnored;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = EMInterpretInstructionCPU(pVM, pVCpu, pCpu, pRegFrame, PC, &cbIgnored);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (RT_SUCCESS(rc))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pRegFrame->eip += pCpu->opsize;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync else if (rc == VERR_EM_INTERPRETER)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_EXCEPTION_PRIVILEGED, pRegFrame);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync}
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync/**
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync * \#GP (General Protection Fault) handler for Ring-3.
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync *
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VINF_SUCCESS means we completely handled this trap,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pVM The VM handle.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to the register frame for the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pCpu The opcode info.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param PC The program counter corresponding to cs:eip in pRegFrame.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic int trpmGCTrap0dHandlerRing3(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR PC)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Assert(!pRegFrame->eflags.Bits.u1VM);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync switch (pCpu->pCurInstr->opcode)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * INT3 and INT xx are ring-switching.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * (The shadow IDT will have set the entries to DPL=0, that's why we're here.)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_INT3:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Little hack to make the code below not fail
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pCpu->param1.flags = USE_IMMEDIATE8;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pCpu->param1.parval = 3;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* fall thru */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case OP_INT:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync {
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync Assert(pCpu->param1.flags & USE_IMMEDIATE8);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = TRPMForwardTrap(pVCpu, pRegFrame, (uint32_t)pCpu->param1.parval, pCpu->opsize, TRPM_TRAP_NO_ERRORCODE, TRPM_SOFTWARE_INT, 0xd);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync if (RT_SUCCESS(rc) && rc != VINF_EM_RAW_GUEST_TRAP)
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pVCpu->trpm.s.uActiveVector = (pVCpu->trpm.s.uActiveErrorCode & X86_TRAP_ERR_SEL_MASK) >> X86_TRAP_ERR_SEL_SHIFT;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pVCpu->trpm.s.enmActiveType = TRPM_SOFTWARE_INT;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH_INT, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * SYSCALL, SYSENTER, INTO and BOUND are also ring-switchers.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_SYSCALL:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_SYSENTER:
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifdef PATM_EMULATE_SYSENTER
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = PATMSysCall(pVM, pRegFrame, pCpu);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (rc == VINF_SUCCESS)
9496f2d398b49813176939d7a339ae513d5175efvboxsync return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync /* else no break; */
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync case OP_BOUND:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case OP_INTO:
9496f2d398b49813176939d7a339ae513d5175efvboxsync pVCpu->trpm.s.uActiveVector = ~0;
9496f2d398b49813176939d7a339ae513d5175efvboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_RING_SWITCH, pRegFrame);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Handle virtualized TSC & PMC reads, just in case.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_RDTSC:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_RDPMC:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint32_t cbIgnored;
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = EMInterpretInstructionCPU(pVM, pVCpu, pCpu, pRegFrame, PC, &cbIgnored);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (RT_SUCCESS(rc))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pRegFrame->eip += pCpu->opsize;
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if (rc == VERR_EM_INTERPRETER)
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, rc, pRegFrame);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync }
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * STI and CLI are I/O privileged, i.e. if IOPL
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_STI:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case OP_CLI:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint32_t efl = CPUMRawGetEFlags(pVCpu, pRegFrame);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync if (X86_EFL_GET_IOPL(efl) >= (unsigned)(pRegFrame->ss & X86_SEL_RPL))
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync {
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> REM\n"));
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync return trpmGCExitTrap(pVM, VINF_EM_RESCHEDULE_REM, pRegFrame);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync }
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync LogFlow(("trpmGCTrap0dHandlerRing3: CLI/STI -> #GP(0)\n"));
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync break;
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync }
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync }
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync /*
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync * A genuine guest fault.
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
9496f2d398b49813176939d7a339ae513d5175efvboxsync}
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Emulates RDTSC for the \#GP handler.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns VINF_SUCCESS or VINF_EM_RAW_EMULATE_INSTR.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pVM Pointer to the shared VM structure.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pRegFrame Pointer to the registre frame for the trap.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * This will be updated on successful return.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsyncDECLINLINE(int) trpmGCTrap0dHandlerRdTsc(PVM pVM, PCPUMCTXCORE pRegFrame)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRdTsc);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (CPUMGetGuestCR4(pVCpu) & X86_CR4_TSD)
9496f2d398b49813176939d7a339ae513d5175efvboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame); /* will trap (optimize later). */
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync uint64_t uTicks = TMCpuTickGet(pVCpu);
9496f2d398b49813176939d7a339ae513d5175efvboxsync pRegFrame->eax = uTicks;
9496f2d398b49813176939d7a339ae513d5175efvboxsync pRegFrame->edx = uTicks >> 32;
9496f2d398b49813176939d7a339ae513d5175efvboxsync pRegFrame->eip += 2;
9496f2d398b49813176939d7a339ae513d5175efvboxsync return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
9496f2d398b49813176939d7a339ae513d5175efvboxsync}
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * \#GP (General Protection Fault) handler.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns VBox status code.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * VINF_SUCCESS means we completely handled this trap,
9496f2d398b49813176939d7a339ae513d5175efvboxsync * other codes are passed execution to host context.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pVM The VM handle.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param pRegFrame Pointer to the register frame for the trap.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic int trpmGCTrap0dHandler(PVM pVM, PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%08RX32 uErr=%RGv\n", pRegFrame->ss, pRegFrame->eip, pTrpmCpu->uActiveErrorCode));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Convert and validate CS.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync STAM_PROFILE_START(&pVM->trpm.s.StatTrap0dDisasm, a);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RTGCPTR PC;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint32_t cBits;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = SELMValidateAndConvertCSAddrGCTrap(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync (RTGCPTR)pRegFrame->eip, &PC, &cBits);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (RT_FAILURE(rc))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n",
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
9496f2d398b49813176939d7a339ae513d5175efvboxsync STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
05d0c18daabd17b1b434b3684ae642fbc8313ef2vboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
05d0c18daabd17b1b434b3684ae642fbc8313ef2vboxsync }
05d0c18daabd17b1b434b3684ae642fbc8313ef2vboxsync
05d0c18daabd17b1b434b3684ae642fbc8313ef2vboxsync /*
05d0c18daabd17b1b434b3684ae642fbc8313ef2vboxsync * Optimize RDTSC traps.
05d0c18daabd17b1b434b3684ae642fbc8313ef2vboxsync * Some guests (like Solaris) are using RDTSC all over the place and
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * will end up trapping a *lot* because of that.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if ( !pRegFrame->eflags.Bits.u1VM
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync && ((uint8_t *)PC)[0] == 0x0f
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync && ((uint8_t *)PC)[1] == 0x31)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCTrap0dHandlerRdTsc(pVM, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Disassemble the instruction.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync DISCPUSTATE Cpu;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync uint32_t cbOp;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = DISCoreOneEx((RTGCUINTPTR)PC, cBits == 32 ? CPUMODE_32BIT : cBits == 16 ? CPUMODE_16BIT : CPUMODE_64BIT,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync NULL, NULL, &Cpu, &cbOp);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (RT_FAILURE(rc))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AssertMsgFailed(("DISCoreOneEx failed to PC=%RGv rc=%Rrc\n", PC, rc));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Deal with I/O port access.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if ( pVCpu->trpm.s.uActiveErrorCode == 0
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync && (Cpu.pCurInstr->optype & OPTYPE_PORTIO))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = EMInterpretPortIO(pVM, pVCpu, pRegFrame, &Cpu, cbOp);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync return trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Deal with Ring-0 (privileged instructions)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if ( (pRegFrame->ss & X86_SEL_RPL) <= 1
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync && !pRegFrame->eflags.Bits.u1VM)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCTrap0dHandlerRing0(pVM, pRegFrame, &Cpu, PC);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Deal with Ring-3 GPs.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (!pRegFrame->eflags.Bits.u1VM)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCTrap0dHandlerRing3(pVM, pRegFrame, &Cpu, PC);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Deal with v86 code.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * We always set IOPL to zero which makes e.g. pushf fault in V86
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * mode. The guest might use IOPL=3 and therefore not expect a #GP.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Simply fall back to the recompiler to emulate this instruction if
9496f2d398b49813176939d7a339ae513d5175efvboxsync * that's the case. To get the correct we must use CPUMRawGetEFlags.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync X86EFLAGS eflags;
9496f2d398b49813176939d7a339ae513d5175efvboxsync eflags.u32 = CPUMRawGetEFlags(pVCpu, pRegFrame); /* Get the correct value. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync Log3(("TRPM #GP V86: cs:eip=%04x:%08x IOPL=%d efl=%08x\n", pRegFrame->cs, pRegFrame->eip, eflags.Bits.u2IOPL, eflags.u));
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (eflags.Bits.u2IOPL != 3)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Assert(eflags.Bits.u2IOPL == 0);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = TRPMForwardTrap(pVCpu, pRegFrame, 0xD, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP, 0xd);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Assert(rc == VINF_EM_RAW_GUEST_TRAP);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, rc, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
09127e6ed46502ff8a6a521713ee8ace53667683vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * \#GP (General Protection Fault) handler.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VINF_SUCCESS means we completely handled this trap,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * other codes are passed execution to host context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pTrpmCpu Pointer to TRPMCPU data (within VM).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to the register frame for the trap.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @internal
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsyncDECLASM(int) TRPMGCTrap0dHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync PVM pVM = TRPMCPU2VM(pTrpmCpu);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("TRPMGC0d: %04x:%08x err=%x\n", pRegFrame->cs, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = trpmGCTrap0dHandler(pVM, pTrpmCpu, pRegFrame);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync switch (rc)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync case VINF_EM_RAW_GUEST_TRAP:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case VINF_EM_RAW_EXCEPTION_PRIVILEGED:
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = VINF_PATM_PATCH_TRAP_GP;
9496f2d398b49813176939d7a339ae513d5175efvboxsync break;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync case VINF_EM_RAW_INTERRUPT_PENDING:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Assert(TRPMHasTrap(pVCpu));
/* no break; */
case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */
case VINF_EM_RAW_EMULATE_INSTR:
case VINF_IOM_HC_IOPORT_READ:
case VINF_IOM_HC_IOPORT_WRITE:
case VINF_IOM_HC_MMIO_WRITE:
case VINF_IOM_HC_MMIO_READ:
case VINF_IOM_HC_MMIO_READ_WRITE:
case VINF_PATM_PATCH_INT3:
case VINF_EM_NO_MEMORY:
case VINF_EM_RAW_TO_R3:
case VINF_EM_RAW_TIMER_PENDING:
case VINF_EM_PENDING_REQUEST:
case VINF_EM_HALT:
case VINF_SUCCESS:
break;
default:
AssertMsg(PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip) == false, ("return code %d\n", rc));
break;
}
Log6(("TRPMGC0d: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs, pRegFrame->eip));
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
*/
DECLASM(int) TRPMGCTrap0eHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
{
PVM pVM = TRPMCPU2VM(pTrpmCpu);
PVMCPU pVCpu = VMMGetCpu0(pVM);
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)
{
case VINF_EM_RAW_EMULATE_INSTR:
case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT:
case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT:
case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT:
case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT:
case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT:
if (PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
rc = VINF_PATCH_EMULATE_INSTR;
break;
case VINF_EM_RAW_GUEST_TRAP:
if (PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
return VINF_PATM_PATCH_TRAP_PF;
rc = TRPMForwardTrap(pVCpu, pRegFrame, 0xE, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP, 0xe);
Assert(rc == VINF_EM_RAW_GUEST_TRAP);
break;
case VINF_EM_RAW_INTERRUPT_PENDING:
Assert(TRPMHasTrap(pVCpu));
/* no break; */
case VINF_IOM_HC_MMIO_READ:
case VINF_IOM_HC_MMIO_WRITE:
case VINF_IOM_HC_MMIO_READ_WRITE:
case VINF_PATM_HC_MMIO_PATCH_READ:
case VINF_PATM_HC_MMIO_PATCH_WRITE:
case VINF_SUCCESS:
case VINF_EM_RAW_TO_R3:
case VINF_EM_PENDING_REQUEST:
case VINF_EM_RAW_TIMER_PENDING:
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, (RTRCPTR)pRegFrame->eip) == false, ("Patch address for return code %d. eip=%08x\n", rc, pRegFrame->eip));
break;
}
rc = trpmGCExitTrap(pVM, rc, pRegFrame);
Log6(("TRPMGC0e: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs, pRegFrame->eip));
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)
{
uintptr_t uEip = (uintptr_t)pRegFrame->eip;
Assert(paHandlers <= pEndRecord);
Log(("trpmGCHyperGeneric: uEip=%x %p-%p\n", uEip, paHandlers, pEndRecord));
#if 0 /// @todo later
/*
* Start by doing a kind of binary search.
*/
unsigned iStart = 0;
unsigned iEnd = pEndRecord - paHandlers;
unsigned i = iEnd / 2;
#endif
/*
* Do a linear search now (in case the array wasn't properly sorted).
*/
for (PCTRPMGCHYPER pCur = paHandlers; pCur < pEndRecord; pCur++)
{
if ( pCur->uStartEIP <= uEip
&& (pCur->uEndEIP ? pCur->uEndEIP > uEip : pCur->uStartEIP == uEip))
return pCur->pfnHandler(pVM, pRegFrame, pCur->uUser);
}
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
*/
DECLASM(int) TRPMGCHyperTrap0bHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
{
return trpmGCHyperGeneric(TRPMCPU2VM(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
*/
DECLASM(int) TRPMGCHyperTrap0dHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
{
return trpmGCHyperGeneric(TRPMCPU2VM(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
*/
DECLASM(int) TRPMGCHyperTrap0eHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame)
{
return trpmGCHyperGeneric(TRPMCPU2VM(pTrpmCpu), pRegFrame, g_aTrap0dHandlers, g_aTrap0dHandlersEnd);
}
/**
* Deal with hypervisor traps occuring when resuming execution on a trap.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pRegFrame Register frame.
* @param uUser User arg.
*/
DECLCALLBACK(int) trpmGCTrapInGeneric(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
{
Log(("********************************************************\n"));
Log(("trpmGCTrapInGeneric: eip=%RX32 uUser=%#x\n", pRegFrame->eip, uUser));
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).
*/
RTRCUINTPTR cbStackUsed = (RTRCUINTPTR)VMMGetStackRC(pVM) - pRegFrame->esp;
if (cbStackUsed > VMM_STACK_SIZE - _1K)
{
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:
pRegFrame->eax = 0;
pRegFrame->gs = 0; /* prevent recursive trouble. */
break;
case TRPM_TRAP_IN_MOV_FS:
pRegFrame->eax = 0;
pRegFrame->fs = 0; /* prevent recursive trouble. */
return VINF_SUCCESS;
default:
AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
return VERR_INTERNAL_ERROR;
}
}
else
{
/*
* Reconstruct the guest context and switch to the recompiler.
* We ASSUME we're only at
*/
CPUMCTXCORE CtxCore = *pRegFrame;
uint32_t *pEsp = (uint32_t *)pRegFrame->esp;
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:
{
PCPUMCTXCORE pTempGuestCtx = (PCPUMCTXCORE)pEsp;
/* Just copy the whole thing; several selector registers, eip (etc) and eax are not yet in pRegFrame. */
CtxCore = *pTempGuestCtx;
rc = VINF_EM_RAW_STALE_SELECTOR;
break;
}
/*
* This will only occur when resuming guest code!
*/
case TRPM_TRAP_IN_IRET:
CtxCore.eip = *pEsp++;
CtxCore.cs = (RTSEL)*pEsp++;
CtxCore.eflags.u32 = *pEsp++;
CtxCore.esp = *pEsp++;
CtxCore.ss = (RTSEL)*pEsp++;
rc = VINF_EM_RAW_IRET_TRAP;
break;
/*
* This will only occur when resuming V86 guest code!
*/
case TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86:
CtxCore.eip = *pEsp++;
CtxCore.cs = (RTSEL)*pEsp++;
CtxCore.eflags.u32 = *pEsp++;
CtxCore.esp = *pEsp++;
CtxCore.ss = (RTSEL)*pEsp++;
CtxCore.es = (RTSEL)*pEsp++;
CtxCore.ds = (RTSEL)*pEsp++;
CtxCore.fs = (RTSEL)*pEsp++;
CtxCore.gs = (RTSEL)*pEsp++;
rc = VINF_EM_RAW_IRET_TRAP;
break;
default:
AssertMsgFailed(("Invalid uUser=%#x\n", uUser));
return VERR_INTERNAL_ERROR;
}
CPUMSetGuestCtxCore(VMMGetCpu0(pVM), &CtxCore);
TRPMGCHyperReturnToHost(pVM, rc);
}
AssertMsgFailed(("Impossible!\n"));
return VERR_INTERNAL_ERROR;
}