summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/VMMAll/TRPMAll.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/VMM/VMMAll/TRPMAll.cpp
parentInitial commit. (diff)
downloadvirtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz
virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/VMM/VMMAll/TRPMAll.cpp')
-rw-r--r--src/VBox/VMM/VMMAll/TRPMAll.cpp987
1 files changed, 987 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMAll/TRPMAll.cpp b/src/VBox/VMM/VMMAll/TRPMAll.cpp
new file mode 100644
index 00000000..a81ba7af
--- /dev/null
+++ b/src/VBox/VMM/VMMAll/TRPMAll.cpp
@@ -0,0 +1,987 @@
+/* $Id: TRPMAll.cpp $ */
+/** @file
+ * TRPM - Trap Monitor - Any Context.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * 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 <VBox/vmm/trpm.h>
+#include <VBox/vmm/pgm.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/vmm/hm.h>
+#include <VBox/vmm/patm.h>
+#include <VBox/vmm/selm.h>
+#include <VBox/vmm/stam.h>
+#include <VBox/vmm/dbgf.h>
+#include "TRPMInternal.h"
+#include <VBox/vmm/vm.h>
+#include <VBox/err.h>
+#include <VBox/vmm/em.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/param.h>
+#include <iprt/x86.h>
+
+
+
+#if defined(TRPM_TRACK_GUEST_IDT_CHANGES) && !defined(IN_RING0)
+/**
+ * @callback_method_impl{FNPGMVIRTPFHANDLER,
+ * \#PF Handler callback for virtual access handler ranges.}
+ *
+ * Important to realize that a physical page in a range can have aliases, and
+ * for ALL and WRITE handlers these will also trigger.
+ */
+PGM_ALL_CB2_DECL(VBOXSTRICTRC)
+trpmGuestIDTWriteHandler(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf,
+ PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
+{
+ Assert(enmAccessType == PGMACCESSTYPE_WRITE); NOREF(enmAccessType);
+ Log(("trpmGuestIDTWriteHandler: write to %RGv size %d\n", GCPtr, cbBuf)); NOREF(GCPtr); NOREF(cbBuf);
+ NOREF(pvPtr); NOREF(pvUser); NOREF(pvBuf); NOREF(enmOrigin); NOREF(pvUser); RT_NOREF_PV(pVM);
+ Assert(VM_IS_RAW_MODE_ENABLED(pVM));
+
+ /** @todo Check which IDT entry and keep the update cost low in TRPMR3SyncIDT() and CSAMCheckGates(). */
+ VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
+# ifdef IN_RC
+ STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTFault);
+# endif
+ return VINF_PGM_HANDLER_DO_DEFAULT;
+}
+#endif /* TRPM_TRACK_GUEST_IDT_CHANGES && !IN_RING0 */
+
+
+/**
+ * Query info about the current active trap/interrupt.
+ * If no trap is active active an error code is returned.
+ *
+ * @returns VBox status code.
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param pu8TrapNo Where to store the trap number.
+ * @param penmType Where to store the trap type
+ */
+VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *penmType)
+{
+ /*
+ * Check if we have a trap at present.
+ */
+ if (pVCpu->trpm.s.uActiveVector != ~0U)
+ {
+ if (pu8TrapNo)
+ *pu8TrapNo = (uint8_t)pVCpu->trpm.s.uActiveVector;
+ if (penmType)
+ *penmType = pVCpu->trpm.s.enmActiveType;
+ return VINF_SUCCESS;
+ }
+
+ return VERR_TRPM_NO_ACTIVE_TRAP;
+}
+
+
+/**
+ * Gets the trap number for the current trap.
+ *
+ * The caller is responsible for making sure there is an active trap which
+ * takes an error code when making this request.
+ *
+ * @returns The current trap number.
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu)
+{
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ return (uint8_t)pVCpu->trpm.s.uActiveVector;
+}
+
+
+/**
+ * Gets the error code for the current trap.
+ *
+ * The caller is responsible for making sure there is an active trap which
+ * takes an error code when making this request.
+ *
+ * @returns Error code.
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(RTGCUINT) TRPMGetErrorCode(PVMCPU pVCpu)
+{
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+#ifdef VBOX_STRICT
+ switch (pVCpu->trpm.s.uActiveVector)
+ {
+ case X86_XCPT_TS:
+ case X86_XCPT_NP:
+ case X86_XCPT_SS:
+ case X86_XCPT_GP:
+ case X86_XCPT_PF:
+ case X86_XCPT_AC:
+ case X86_XCPT_DF:
+ break;
+ default:
+ AssertMsgFailed(("This trap (%#x) doesn't have any error code\n", pVCpu->trpm.s.uActiveVector));
+ break;
+ }
+#endif
+ return pVCpu->trpm.s.uActiveErrorCode;
+}
+
+
+/**
+ * Gets the fault address for the current trap.
+ *
+ * The caller is responsible for making sure there is an active trap 0x0e when
+ * making this request.
+ *
+ * @returns Fault address associated with the trap.
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu)
+{
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ AssertMsg(pVCpu->trpm.s.uActiveVector == X86_XCPT_PF, ("Not page-fault trap!\n"));
+ return pVCpu->trpm.s.uActiveCR2;
+}
+
+
+/**
+ * Gets the instruction-length for the current trap (only relevant for software
+ * interrupts and software exceptions \#BP and \#OF).
+ *
+ * The caller is responsible for making sure there is an active trap 0x0e when
+ * making this request.
+ *
+ * @returns Fault address associated with the trap.
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(uint8_t) TRPMGetInstrLength(PVMCPU pVCpu)
+{
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ return pVCpu->trpm.s.cbInstr;
+}
+
+
+/**
+ * Clears the current active trap/exception/interrupt.
+ *
+ * The caller is responsible for making sure there is an active trap
+ * when making this request.
+ *
+ * @returns VBox status code.
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(int) TRPMResetTrap(PVMCPU pVCpu)
+{
+ /*
+ * Cannot reset non-existing trap!
+ */
+ if (pVCpu->trpm.s.uActiveVector == ~0U)
+ {
+ AssertMsgFailed(("No active trap!\n"));
+ return VERR_TRPM_NO_ACTIVE_TRAP;
+ }
+
+ /*
+ * Reset it.
+ */
+ pVCpu->trpm.s.uActiveVector = ~0U;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Assert trap/exception/interrupt.
+ *
+ * The caller is responsible for making sure there is no active trap
+ * when making this request.
+ *
+ * @returns VBox status code.
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param u8TrapNo The trap vector to assert.
+ * @param enmType Trap type.
+ */
+VMMDECL(int) TRPMAssertTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType)
+{
+ Log2(("TRPMAssertTrap: u8TrapNo=%02x type=%d\n", u8TrapNo, enmType));
+
+ /*
+ * Cannot assert a trap when one is already active.
+ */
+ if (pVCpu->trpm.s.uActiveVector != ~0U)
+ {
+ AssertMsgFailed(("CPU%d: Active trap %#x\n", pVCpu->idCpu, pVCpu->trpm.s.uActiveVector));
+ return VERR_TRPM_ACTIVE_TRAP;
+ }
+
+ pVCpu->trpm.s.uActiveVector = u8TrapNo;
+ pVCpu->trpm.s.enmActiveType = enmType;
+ pVCpu->trpm.s.uActiveErrorCode = ~(RTGCUINT)0;
+ pVCpu->trpm.s.uActiveCR2 = 0xdeadface;
+ pVCpu->trpm.s.cbInstr = UINT8_MAX;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Assert a page-fault exception.
+ *
+ * The caller is responsible for making sure there is no active trap
+ * when making this request.
+ *
+ * @returns VBox status code.
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param uCR2 The new fault address.
+ * @param uErrorCode The error code for the page-fault.
+ */
+VMMDECL(int) TRPMAssertXcptPF(PVMCPU pVCpu, RTGCUINTPTR uCR2, RTGCUINT uErrorCode)
+{
+ Log2(("TRPMAssertXcptPF: uCR2=%RGv uErrorCode=%RGv\n", uCR2, uErrorCode)); /** @todo RTGCUINT to be fixed. */
+
+ /*
+ * Cannot assert a trap when one is already active.
+ */
+ if (pVCpu->trpm.s.uActiveVector != ~0U)
+ {
+ AssertMsgFailed(("CPU%d: Active trap %#x\n", pVCpu->idCpu, pVCpu->trpm.s.uActiveVector));
+ return VERR_TRPM_ACTIVE_TRAP;
+ }
+
+ pVCpu->trpm.s.uActiveVector = X86_XCPT_PF;
+ pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
+ pVCpu->trpm.s.uActiveErrorCode = uErrorCode;
+ pVCpu->trpm.s.uActiveCR2 = uCR2;
+ pVCpu->trpm.s.cbInstr = UINT8_MAX;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets the error code of the current trap.
+ * (This function is for use in trap handlers and such.)
+ *
+ * The caller is responsible for making sure there is an active trap
+ * which takes an errorcode when making this request.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param uErrorCode The new error code.
+ */
+VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, RTGCUINT uErrorCode)
+{
+ Log2(("TRPMSetErrorCode: uErrorCode=%RGv\n", uErrorCode)); /** @todo RTGCUINT mess! */
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ pVCpu->trpm.s.uActiveErrorCode = uErrorCode;
+#ifdef VBOX_STRICT
+ switch (pVCpu->trpm.s.uActiveVector)
+ {
+ case X86_XCPT_TS: case X86_XCPT_NP: case X86_XCPT_SS: case X86_XCPT_GP: case X86_XCPT_PF:
+ AssertMsg(uErrorCode != ~(RTGCUINT)0, ("Invalid uErrorCode=%#x u8TrapNo=%d\n", uErrorCode, pVCpu->trpm.s.uActiveVector));
+ break;
+ case X86_XCPT_AC: case X86_XCPT_DF:
+ AssertMsg(uErrorCode == 0, ("Invalid uErrorCode=%#x u8TrapNo=%d\n", uErrorCode, pVCpu->trpm.s.uActiveVector));
+ break;
+ default:
+ AssertMsg(uErrorCode == ~(RTGCUINT)0, ("Invalid uErrorCode=%#x u8TrapNo=%d\n", uErrorCode, pVCpu->trpm.s.uActiveVector));
+ break;
+ }
+#endif
+}
+
+
+/**
+ * Sets the fault address of the current \#PF trap. (This function is for use in
+ * trap handlers and such.)
+ *
+ * The caller is responsible for making sure there is an active trap 0e
+ * when making this request.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param uCR2 The new fault address (cr2 register).
+ */
+VMMDECL(void) TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2)
+{
+ Log2(("TRPMSetFaultAddress: uCR2=%RGv\n", uCR2));
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ AssertMsg(pVCpu->trpm.s.uActiveVector == X86_XCPT_PF, ("Not trap 0e!\n"));
+ pVCpu->trpm.s.uActiveCR2 = uCR2;
+}
+
+
+/**
+ * Sets the instruction-length of the current trap (relevant for software
+ * interrupts and software exceptions like \#BP, \#OF).
+ *
+ * The caller is responsible for making sure there is an active trap 0e
+ * when making this request.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param cbInstr The instruction length.
+ */
+VMMDECL(void) TRPMSetInstrLength(PVMCPU pVCpu, uint8_t cbInstr)
+{
+ Log2(("TRPMSetInstrLength: cbInstr=%u\n", cbInstr));
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ AssertMsg( pVCpu->trpm.s.enmActiveType == TRPM_SOFTWARE_INT
+ || ( pVCpu->trpm.s.enmActiveType == TRPM_TRAP
+ && ( pVCpu->trpm.s.uActiveVector == X86_XCPT_BP
+ || pVCpu->trpm.s.uActiveVector == X86_XCPT_OF)),
+ ("Invalid trap type %#x\n", pVCpu->trpm.s.enmActiveType));
+ pVCpu->trpm.s.cbInstr = cbInstr;
+}
+
+
+/**
+ * Checks if the current active trap/interrupt/exception/fault/whatever is a software
+ * interrupt or not.
+ *
+ * The caller is responsible for making sure there is an active trap
+ * when making this request.
+ *
+ * @returns true if software interrupt, false if not.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(bool) TRPMIsSoftwareInterrupt(PVMCPU pVCpu)
+{
+ AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+ return (pVCpu->trpm.s.enmActiveType == TRPM_SOFTWARE_INT);
+}
+
+
+/**
+ * Check if there is an active trap.
+ *
+ * @returns true if trap active, false if not.
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu)
+{
+ return pVCpu->trpm.s.uActiveVector != ~0U;
+}
+
+
+/**
+ * Query all info about the current active trap/interrupt.
+ * If no trap is active active an error code is returned.
+ *
+ * @returns VBox status code.
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param pu8TrapNo Where to store the trap number.
+ * @param pEnmType Where to store the trap type
+ * @param puErrorCode Where to store the error code associated with some traps.
+ * ~0U is stored if the trap has no error code.
+ * @param puCR2 Where to store the CR2 associated with a trap 0E.
+ * @param pcbInstr Where to store the instruction-length
+ * associated with some traps.
+ */
+VMMDECL(int) TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *pEnmType, PRTGCUINT puErrorCode, PRTGCUINTPTR puCR2,
+ uint8_t *pcbInstr)
+{
+ /*
+ * Check if we have a trap at present.
+ */
+ if (pVCpu->trpm.s.uActiveVector == ~0U)
+ return VERR_TRPM_NO_ACTIVE_TRAP;
+
+ if (pu8TrapNo)
+ *pu8TrapNo = (uint8_t)pVCpu->trpm.s.uActiveVector;
+ if (pEnmType)
+ *pEnmType = pVCpu->trpm.s.enmActiveType;
+ if (puErrorCode)
+ *puErrorCode = pVCpu->trpm.s.uActiveErrorCode;
+ if (puCR2)
+ *puCR2 = pVCpu->trpm.s.uActiveCR2;
+ if (pcbInstr)
+ *pcbInstr = pVCpu->trpm.s.cbInstr;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Save the active trap.
+ *
+ * This routine useful when doing try/catch in the hypervisor.
+ * Any function which uses temporary trap handlers should
+ * probably also use this facility to save the original trap.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(void) TRPMSaveTrap(PVMCPU pVCpu)
+{
+ pVCpu->trpm.s.uSavedVector = pVCpu->trpm.s.uActiveVector;
+ pVCpu->trpm.s.enmSavedType = pVCpu->trpm.s.enmActiveType;
+ pVCpu->trpm.s.uSavedErrorCode = pVCpu->trpm.s.uActiveErrorCode;
+ pVCpu->trpm.s.uSavedCR2 = pVCpu->trpm.s.uActiveCR2;
+ pVCpu->trpm.s.cbSavedInstr = pVCpu->trpm.s.cbInstr;
+}
+
+
+/**
+ * Restore a saved trap.
+ *
+ * Multiple restores of a saved trap is possible.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ */
+VMMDECL(void) TRPMRestoreTrap(PVMCPU pVCpu)
+{
+ pVCpu->trpm.s.uActiveVector = pVCpu->trpm.s.uSavedVector;
+ pVCpu->trpm.s.enmActiveType = pVCpu->trpm.s.enmSavedType;
+ pVCpu->trpm.s.uActiveErrorCode = pVCpu->trpm.s.uSavedErrorCode;
+ pVCpu->trpm.s.uActiveCR2 = pVCpu->trpm.s.uSavedCR2;
+ pVCpu->trpm.s.cbInstr = pVCpu->trpm.s.cbSavedInstr;
+}
+
+
+#ifdef VBOX_WITH_RAW_MODE_NOT_R0
+/**
+ * Forward trap or interrupt to the guest's handler
+ *
+ *
+ * @returns VBox status code.
+ * or does not return at all (when the trap is actually forwarded)
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param pRegFrame Pointer to the register frame for the trap.
+ * @param iGate Trap or interrupt gate number
+ * @param cbInstr Instruction size (only relevant for software interrupts)
+ * @param enmError TRPM_TRAP_HAS_ERRORCODE or TRPM_TRAP_NO_ERRORCODE.
+ * @param enmType TRPM event type
+ * @param iOrgTrap The original trap.
+ * @internal
+ */
+VMMDECL(int) TRPMForwardTrap(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t iGate, uint32_t cbInstr,
+ TRPMERRORCODE enmError, TRPMEVENT enmType, int32_t iOrgTrap)
+{
+ AssertReturn(VM_IS_RAW_MODE_ENABLED(pVCpu->CTX_SUFF(pVM)), VERR_TRPM_HM_IPE);
+#ifdef TRPM_FORWARD_TRAPS_IN_GC
+ PVM pVM = pVCpu->CTX_SUFF(pVM);
+ X86EFLAGS eflags;
+ Assert(pVM->cCpus == 1);
+
+ STAM_PROFILE_ADV_START(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
+
+# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
+ if (pRegFrame->eflags.Bits.u1VM)
+ Log(("TRPMForwardTrap-VM: eip=%04X:%04X iGate=%d\n", pRegFrame->cs.Sel, pRegFrame->eip, iGate));
+ else
+ Log(("TRPMForwardTrap: eip=%04X:%08X iGate=%d\n", pRegFrame->cs.Sel, pRegFrame->eip, iGate));
+
+ switch (iGate) {
+ case X86_XCPT_PF:
+ if (pRegFrame->eip == pVCpu->trpm.s.uActiveCR2)
+ {
+ RTGCPTR pCallerGC;
+# ifdef IN_RC
+ int rc = MMGCRamRead(pVM, &pCallerGC, (void *)pRegFrame->esp, sizeof(pCallerGC));
+# else
+ int rc = PGMPhysSimpleReadGCPtr(pVCpu, &pCallerGC, (RTGCPTR)pRegFrame->esp, sizeof(pCallerGC));
+# endif
+ if (RT_SUCCESS(rc))
+ Log(("TRPMForwardTrap: caller=%RGv\n", pCallerGC));
+ }
+ RT_FALL_THRU();
+ case X86_XCPT_DF:
+ case X86_XCPT_TS:
+ case X86_XCPT_NP:
+ case X86_XCPT_SS:
+ case X86_XCPT_GP:
+ case X86_XCPT_AC:
+ Assert(enmError == TRPM_TRAP_HAS_ERRORCODE || enmType == TRPM_SOFTWARE_INT);
+ break;
+
+ default:
+ Assert(enmError == TRPM_TRAP_NO_ERRORCODE);
+ break;
+ }
+# endif /* VBOX_STRICT || LOG_ENABLED */
+#ifdef IN_RC
+ AssertReturn(CPUMIsGuestInRawMode(pVCpu), VINF_EM_RESCHEDULE);
+#endif
+
+ /* Retrieve the eflags including the virtualized bits. */
+ /* Note: hackish as the cpumctxcore structure doesn't contain the right value */
+ eflags.u32 = CPUMRawGetEFlags(pVCpu);
+
+ /* VMCPU_FF_INHIBIT_INTERRUPTS should be cleared upfront or don't call this function at all for dispatching hardware interrupts. */
+ Assert(enmType != TRPM_HARDWARE_INT || !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
+
+ /*
+ * If it's a real guest trap and the guest's page fault handler is marked as safe for GC execution, then we call it directly.
+ * Well, only if the IF flag is set.
+ */
+ /** @todo if the trap handler was modified and marked invalid, then we should *now* go back to the host context and install a new patch. */
+ if ( pVM->trpm.s.aGuestTrapHandler[iGate]
+ && (eflags.Bits.u1IF)
+#ifndef VBOX_RAW_V86
+ && !(eflags.Bits.u1VM) /** @todo implement when needed (illegal for same privilege level transfers). */
+#endif
+ && !PATMIsPatchGCAddr(pVM, pRegFrame->eip)
+ )
+ {
+ uint16_t cbIDT;
+ RTGCPTR GCPtrIDT = (RTGCPTR)CPUMGetGuestIDTR(pVCpu, &cbIDT);
+ uint32_t cpl;
+ VBOXIDTE GuestIdte;
+ RTGCPTR pIDTEntry;
+ int rc;
+
+ Assert(PATMAreInterruptsEnabledByCtx(pVM, CPUMCTX_FROM_CORE(pRegFrame)));
+ Assert(!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_TRPM_SYNC_IDT | VMCPU_FF_SELM_SYNC_TSS));
+
+ if (GCPtrIDT && iGate * sizeof(VBOXIDTE) >= cbIDT)
+ goto failure;
+
+ /* Get the current privilege level. */
+ cpl = CPUMGetGuestCPL(pVCpu);
+
+ /*
+ * BIG TODO: The checks are not complete. see trap and interrupt dispatching section in Intel docs for details
+ * All very obscure, but still necessary.
+ * Currently only some CS & TSS selector checks are missing.
+ *
+ */
+ pIDTEntry = (RTGCPTR)((RTGCUINTPTR)GCPtrIDT + sizeof(VBOXIDTE) * iGate);
+#ifdef IN_RC
+ rc = MMGCRamRead(pVM, &GuestIdte, (void *)(uintptr_t)pIDTEntry, sizeof(GuestIdte));
+#else
+ rc = PGMPhysSimpleReadGCPtr(pVCpu, &GuestIdte, pIDTEntry, sizeof(GuestIdte));
+#endif
+ if (RT_FAILURE(rc))
+ {
+ /* The page might be out of sync. */ /** @todo might cross a page boundary) */
+ Log(("Page %RGv out of sync -> prefetch and try again\n", pIDTEntry));
+ rc = PGMPrefetchPage(pVCpu, pIDTEntry); /** @todo r=bird: rainy day: this isn't entirely safe because of access bit virtualiziation and CSAM. */
+ if (rc != VINF_SUCCESS)
+ {
+ Log(("TRPMForwardTrap: PGMPrefetchPage failed with rc=%Rrc\n", rc));
+ goto failure;
+ }
+#ifdef IN_RC
+ rc = MMGCRamRead(pVM, &GuestIdte, (void *)(uintptr_t)pIDTEntry, sizeof(GuestIdte));
+#else
+ rc = PGMPhysSimpleReadGCPtr(pVCpu, &GuestIdte, pIDTEntry, sizeof(GuestIdte));
+#endif
+ }
+ if ( RT_SUCCESS(rc)
+ && GuestIdte.Gen.u1Present
+ && (GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32 || GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
+ && (GuestIdte.Gen.u2DPL == 3 || GuestIdte.Gen.u2DPL == 0)
+ && (GuestIdte.Gen.u16SegSel & 0xfffc) /* must not be zero */
+ && (enmType == TRPM_TRAP || enmType == TRPM_HARDWARE_INT || cpl <= GuestIdte.Gen.u2DPL) /* CPL <= DPL if software int */
+ )
+ {
+ RTGCPTR pHandler, dummy;
+ RTGCPTR pTrapStackGC;
+
+ pHandler = (RTGCPTR)VBOXIDTE_OFFSET(GuestIdte);
+
+ /* Note: SELMValidateAndConvertCSAddr checks for code type, memory type, selector validity. */
+ /** @todo dpl <= cpl else GPF */
+
+ /* Note: don't use current eflags as we might be in V86 mode and the IDT always contains protected mode selectors */
+ X86EFLAGS fakeflags;
+ fakeflags.u32 = 0;
+
+ rc = SELMValidateAndConvertCSAddr(pVCpu, fakeflags, 0, GuestIdte.Gen.u16SegSel, NULL, pHandler, &dummy);
+ if (rc == VINF_SUCCESS)
+ {
+ VBOXGDTR gdtr = {0, 0};
+ bool fConforming = false;
+ int idx = 0;
+ uint32_t dpl;
+ uint32_t ss_r0;
+ uint32_t esp_r0;
+ X86DESC Desc;
+ RTGCPTR pGdtEntry;
+
+ CPUMGetGuestGDTR(pVCpu, &gdtr);
+ Assert(gdtr.pGdt && gdtr.cbGdt > GuestIdte.Gen.u16SegSel);
+
+ if (!gdtr.pGdt)
+ goto failure;
+
+ pGdtEntry = gdtr.pGdt + (GuestIdte.Gen.u16SegSel >> X86_SEL_SHIFT) * sizeof(X86DESC);
+#ifdef IN_RC
+ rc = MMGCRamRead(pVM, &Desc, (void *)(uintptr_t)pGdtEntry, sizeof(Desc));
+#else
+ rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, pGdtEntry, sizeof(Desc));
+#endif
+ if (RT_FAILURE(rc))
+ {
+ /* The page might be out of sync. */ /** @todo might cross a page boundary) */
+ Log(("Page %RGv out of sync -> prefetch and try again\n", pGdtEntry));
+ rc = PGMPrefetchPage(pVCpu, pGdtEntry); /** @todo r=bird: rainy day: this isn't entirely safe because of access bit virtualiziation and CSAM. */
+ if (rc != VINF_SUCCESS)
+ {
+ Log(("PGMPrefetchPage failed with rc=%Rrc\n", rc));
+ goto failure;
+ }
+#ifdef IN_RC
+ rc = MMGCRamRead(pVM, &Desc, (void *)(uintptr_t)pGdtEntry, sizeof(Desc));
+#else
+ rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, pGdtEntry, sizeof(Desc));
+#endif
+ if (RT_FAILURE(rc))
+ {
+ Log(("MMGCRamRead failed with %Rrc\n", rc));
+ goto failure;
+ }
+ }
+
+ if (Desc.Gen.u4Type & X86_SEL_TYPE_CONF)
+ {
+ Log(("Conforming code selector\n"));
+ fConforming = true;
+ }
+ /** @todo check descriptor type!! */
+
+ dpl = Desc.Gen.u2Dpl;
+
+ if (!fConforming && dpl < cpl) /* to inner privilege level */
+ {
+ rc = SELMGetRing1Stack(pVM, &ss_r0, &esp_r0);
+ if (RT_FAILURE(rc))
+ goto failure;
+
+ Assert((ss_r0 & X86_SEL_RPL) == 1);
+
+ if ( !esp_r0
+ || !ss_r0
+ || (ss_r0 & X86_SEL_RPL) != ((dpl == 0) ? 1 : dpl)
+ || SELMToFlatBySelEx(pVCpu, fakeflags, ss_r0, (RTGCPTR)esp_r0, SELMTOFLAT_FLAGS_CPL1,
+ (PRTGCPTR)&pTrapStackGC, NULL) != VINF_SUCCESS
+ )
+ {
+ Log(("Invalid ring 0 stack %04X:%08RX32\n", ss_r0, esp_r0));
+ goto failure;
+ }
+ }
+ else
+ if (fConforming || dpl == cpl) /* to the same privilege level */
+ {
+ ss_r0 = pRegFrame->ss.Sel;
+ esp_r0 = pRegFrame->esp;
+
+ if ( eflags.Bits.u1VM /* illegal */
+ || SELMToFlatBySelEx(pVCpu, fakeflags, ss_r0, (RTGCPTR)esp_r0, SELMTOFLAT_FLAGS_CPL1,
+ (PRTGCPTR)&pTrapStackGC, NULL) != VINF_SUCCESS)
+ {
+ AssertMsgFailed(("Invalid stack %04X:%08RX32??? (VM=%d)\n", ss_r0, esp_r0, eflags.Bits.u1VM));
+ goto failure;
+ }
+ }
+ else
+ {
+ Log(("Invalid cpl-dpl combo %d vs %d\n", cpl, dpl));
+ goto failure;
+ }
+ /*
+ * Build trap stack frame on guest handler's stack
+ */
+ uint32_t *pTrapStack;
+#ifdef IN_RC
+ Assert(eflags.Bits.u1VM || (pRegFrame->ss.Sel & X86_SEL_RPL) != 0);
+ /* Check maximum amount we need (10 when executing in V86 mode) */
+ rc = PGMVerifyAccess(pVCpu, (RTGCUINTPTR)pTrapStackGC - 10*sizeof(uint32_t), 10 * sizeof(uint32_t), X86_PTE_RW);
+ pTrapStack = (uint32_t *)(uintptr_t)pTrapStackGC;
+#else
+ Assert(eflags.Bits.u1VM || (pRegFrame->ss.Sel & X86_SEL_RPL) == 0 || (pRegFrame->ss.Sel & X86_SEL_RPL) == 3 || (EMIsRawRing1Enabled(pVM) && (pRegFrame->ss.Sel & X86_SEL_RPL) == 1));
+ /* Check maximum amount we need (10 when executing in V86 mode) */
+ if ((pTrapStackGC >> PAGE_SHIFT) != ((pTrapStackGC - 10*sizeof(uint32_t)) >> PAGE_SHIFT)) /* fail if we cross a page boundary */
+ goto failure;
+ PGMPAGEMAPLOCK PageMappingLock;
+ rc = PGMPhysGCPtr2CCPtr(pVCpu, pTrapStackGC, (void **)&pTrapStack, &PageMappingLock);
+ if (RT_FAILURE(rc))
+ {
+ AssertRC(rc);
+ goto failure;
+ }
+#endif
+ if (rc == VINF_SUCCESS)
+ {
+ /** if eflags.Bits.u1VM then push gs, fs, ds, es */
+ if (eflags.Bits.u1VM)
+ {
+ Log(("TRAP%02X: (VM) Handler %04X:%RGv Stack %04X:%08X RPL=%d CR2=%08X\n", iGate, GuestIdte.Gen.u16SegSel, pHandler, ss_r0, esp_r0, (pRegFrame->ss.Sel & X86_SEL_RPL), pVCpu->trpm.s.uActiveCR2));
+ pTrapStack[--idx] = pRegFrame->gs.Sel;
+ pTrapStack[--idx] = pRegFrame->fs.Sel;
+ pTrapStack[--idx] = pRegFrame->ds.Sel;
+ pTrapStack[--idx] = pRegFrame->es.Sel;
+
+ /* clear ds, es, fs & gs in current context */
+ pRegFrame->ds.Sel = pRegFrame->es.Sel = pRegFrame->fs.Sel = pRegFrame->gs.Sel = 0;
+ }
+ else
+ Log(("TRAP%02X: Handler %04X:%RGv Stack %04X:%08X RPL=%d CR2=%08X\n", iGate, GuestIdte.Gen.u16SegSel, pHandler, ss_r0, esp_r0, (pRegFrame->ss.Sel & X86_SEL_RPL), pVCpu->trpm.s.uActiveCR2));
+
+ if (!fConforming && dpl < cpl)
+ {
+#ifdef IN_RC /* Only in RC we still see tracing of our ring modifications. */
+ if ( (pRegFrame->ss.Sel & X86_SEL_RPL) == 1
+ && !eflags.Bits.u1VM)
+ pTrapStack[--idx] = pRegFrame->ss.Sel & ~1; /* Mask away traces of raw ring 0 execution (ring 1). */
+ else if ( EMIsRawRing1Enabled(pVM)
+ && (pRegFrame->ss.Sel & X86_SEL_RPL) == 2)
+ pTrapStack[--idx] = (pRegFrame->ss.Sel & ~2) | 1; /* Mask away traces of raw ring 1 execution (ring 2). */
+ else
+#endif /* IN_RC */
+ pTrapStack[--idx] = pRegFrame->ss.Sel;
+
+ pTrapStack[--idx] = pRegFrame->esp;
+ }
+
+ /* Note: We use the eflags copy, that includes the virtualized bits! */
+ /* Note: Not really necessary as we grab include those bits in the trap/irq handler trampoline */
+ pTrapStack[--idx] = eflags.u32;
+
+#ifdef IN_RC /* Only in RC mode we still see tracing of our ring modifications */
+ if ( (pRegFrame->cs.Sel & X86_SEL_RPL) == 1
+ && !eflags.Bits.u1VM)
+ pTrapStack[--idx] = pRegFrame->cs.Sel & ~1; /* Mask away traces of raw ring execution (ring 1). */
+ else if ( EMIsRawRing1Enabled(pVM)
+ && (pRegFrame->cs.Sel & X86_SEL_RPL) == 2)
+ pTrapStack[--idx] = (pRegFrame->cs.Sel & ~2) | 1; /* Mask away traces of raw ring 1 execution (ring 2). */
+ else
+#endif /* IN_RC */
+ pTrapStack[--idx] = pRegFrame->cs.Sel;
+
+ if (enmType == TRPM_SOFTWARE_INT)
+ {
+ Assert(cbInstr);
+ pTrapStack[--idx] = pRegFrame->eip + cbInstr; /* return address = next instruction */
+ }
+ else
+ pTrapStack[--idx] = pRegFrame->eip;
+
+ if (enmError == TRPM_TRAP_HAS_ERRORCODE)
+ {
+ pTrapStack[--idx] = pVCpu->trpm.s.uActiveErrorCode;
+ }
+
+ Assert(esp_r0 > -idx*sizeof(uint32_t));
+ /* Adjust ESP accordingly */
+ esp_r0 += idx*sizeof(uint32_t);
+
+ /* Mask away dangerous flags for the trap/interrupt handler. */
+ eflags.u32 &= ~(X86_EFL_TF | X86_EFL_VM | X86_EFL_RF | X86_EFL_NT);
+#ifdef DEBUG
+ if (DBGFIsStepping(pVCpu))
+ eflags.u32 |= X86_EFL_TF;
+#endif
+
+ /* Turn off interrupts for interrupt gates. */
+ if (GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
+ eflags.Bits.u1IF = 0;
+
+ CPUMRawSetEFlags(pVCpu, eflags.u32);
+
+#ifdef DEBUG
+ for (int j = idx; j < 0; j++)
+ LogFlow(("Stack %RRv pos %02d: %08x\n", &pTrapStack[j], j, pTrapStack[j]));
+
+ Log4(("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
+ "eip=%08x esp=%08x ebp=%08x iopl=%d\n"
+ "cs=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n",
+ pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx, pRegFrame->esi, pRegFrame->edi,
+ pRegFrame->eip, pRegFrame->esp, pRegFrame->ebp, eflags.Bits.u2IOPL,
+ pRegFrame->cs.Sel, pRegFrame->ds.Sel, pRegFrame->es.Sel,
+ pRegFrame->fs.Sel, pRegFrame->gs.Sel, eflags.u32));
+#endif
+
+ Log(("TRPM: PATM Handler %RRv Adjusted stack %08X new EFLAGS=%08X/%08x idx=%d dpl=%d cpl=%d\n",
+ pVM->trpm.s.aGuestTrapHandler[iGate], esp_r0, eflags.u32, CPUMRawGetEFlags(pVCpu), idx, dpl, cpl));
+
+ /* Make sure the internal guest context structure is up-to-date. */
+ if (iGate == X86_XCPT_PF)
+ CPUMSetGuestCR2(pVCpu, pVCpu->trpm.s.uActiveCR2);
+
+#ifdef IN_RC
+ /* paranoia */
+ Assert(pRegFrame->eflags.Bits.u1IF == 1);
+ eflags.Bits.u1IF = 1;
+ Assert(pRegFrame->eflags.Bits.u2IOPL == 0);
+ eflags.Bits.u2IOPL = 0;
+
+ Assert(eflags.Bits.u1IF);
+ Assert(eflags.Bits.u2IOPL == 0);
+ STAM_COUNTER_INC(&pVM->trpm.s.CTX_SUFF(paStatForwardedIRQ)[iGate]);
+ STAM_PROFILE_ADV_STOP(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
+ if (iOrgTrap >= 0 && iOrgTrap < (int)RT_ELEMENTS(pVM->trpm.s.aStatGCTraps))
+ STAM_PROFILE_ADV_STOP(&pVM->trpm.s.aStatGCTraps[iOrgTrap], o);
+
+ PGMRZDynMapReleaseAutoSet(pVCpu);
+ CPUMGCCallGuestTrapHandler(pRegFrame, GuestIdte.Gen.u16SegSel | 1, pVM->trpm.s.aGuestTrapHandler[iGate],
+ eflags.u32, ss_r0, (RTRCPTR)esp_r0);
+ /* does not return */
+#else
+
+ Assert(!CPUMIsGuestInRawMode(pVCpu));
+ pRegFrame->eflags.u32 = eflags.u32;
+ pRegFrame->eip = pVM->trpm.s.aGuestTrapHandler[iGate];
+ pRegFrame->cs.Sel = GuestIdte.Gen.u16SegSel;
+ pRegFrame->esp = esp_r0;
+ pRegFrame->ss.Sel = ss_r0 & ~X86_SEL_RPL; /* set rpl to ring 0 */
+ STAM_PROFILE_ADV_STOP(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
+ PGMPhysReleasePageMappingLock(pVM, &PageMappingLock);
+ NOREF(iOrgTrap);
+ return VINF_SUCCESS;
+#endif
+ }
+ else
+ Log(("TRAP%02X: PGMVerifyAccess %RGv failed with %Rrc -> forward to REM\n", iGate, pTrapStackGC, rc));
+ }
+ else
+ Log(("SELMValidateAndConvertCSAddr failed with %Rrc\n", rc));
+ }
+ else
+ Log(("MMRamRead %RGv size %d failed with %Rrc\n", (RTGCUINTPTR)GCPtrIDT + sizeof(VBOXIDTE) * iGate, sizeof(GuestIdte), rc));
+ }
+ else
+ {
+ Log(("Refused to forward trap: eflags=%08x IF=%d\n", eflags.u32, eflags.Bits.u1IF));
+#ifdef VBOX_WITH_STATISTICS
+ if (pVM->trpm.s.aGuestTrapHandler[iGate] == TRPM_INVALID_HANDLER)
+ STAM_COUNTER_INC(&pVM->trpm.s.StatForwardFailNoHandler);
+ else if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
+ STAM_COUNTER_INC(&pVM->trpm.s.StatForwardFailPatchAddr);
+#endif
+ }
+failure:
+ STAM_COUNTER_INC(&pVM->trpm.s.CTX_SUFF_Z(StatForwardFail));
+ STAM_PROFILE_ADV_STOP(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
+
+ Log(("TRAP%02X: forwarding to REM (ss rpl=%d eflags=%08X VMIF=%d handler=%08X\n", iGate, pRegFrame->ss.Sel & X86_SEL_RPL, pRegFrame->eflags.u32, PATMAreInterruptsEnabledByCtx(pVM, CPUMCTX_FROM_CORE(pRegFrame)), pVM->trpm.s.aGuestTrapHandler[iGate]));
+#endif
+ return VINF_EM_RAW_GUEST_TRAP;
+}
+#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
+
+
+/**
+ * Raises a cpu exception which doesn't take an error code.
+ *
+ * This function may or may not dispatch the exception before returning.
+ *
+ * @returns VBox status code fit for scheduling.
+ * @retval VINF_EM_RAW_GUEST_TRAP if the exception was left pending.
+ * @retval VINF_TRPM_XCPT_DISPATCHED if the exception was raised and dispatched for raw-mode execution.
+ * @retval VINF_EM_RESCHEDULE_REM if the exception was dispatched and cannot be executed in raw-mode.
+ *
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param pCtxCore The CPU context core.
+ * @param enmXcpt The exception.
+ */
+VMMDECL(int) TRPMRaiseXcpt(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt)
+{
+ LogFlow(("TRPMRaiseXcptErr: cs:eip=%RTsel:%RX32 enmXcpt=%#x\n", pCtxCore->cs.Sel, pCtxCore->eip, enmXcpt));
+ NOREF(pCtxCore);
+/** @todo dispatch the trap. */
+ pVCpu->trpm.s.uActiveVector = enmXcpt;
+ pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
+ pVCpu->trpm.s.uActiveErrorCode = 0xdeadbeef;
+ pVCpu->trpm.s.uActiveCR2 = 0xdeadface;
+ pVCpu->trpm.s.cbInstr = UINT8_MAX;
+ return VINF_EM_RAW_GUEST_TRAP;
+}
+
+
+/**
+ * Raises a cpu exception with an errorcode.
+ *
+ * This function may or may not dispatch the exception before returning.
+ *
+ * @returns VBox status code fit for scheduling.
+ * @retval VINF_EM_RAW_GUEST_TRAP if the exception was left pending.
+ * @retval VINF_TRPM_XCPT_DISPATCHED if the exception was raised and dispatched for raw-mode execution.
+ * @retval VINF_EM_RESCHEDULE_REM if the exception was dispatched and cannot be executed in raw-mode.
+ *
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param pCtxCore The CPU context core.
+ * @param enmXcpt The exception.
+ * @param uErr The error code.
+ */
+VMMDECL(int) TRPMRaiseXcptErr(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt, uint32_t uErr)
+{
+ LogFlow(("TRPMRaiseXcptErr: cs:eip=%RTsel:%RX32 enmXcpt=%#x uErr=%RX32\n", pCtxCore->cs.Sel, pCtxCore->eip, enmXcpt, uErr));
+ NOREF(pCtxCore);
+/** @todo dispatch the trap. */
+ pVCpu->trpm.s.uActiveVector = enmXcpt;
+ pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
+ pVCpu->trpm.s.uActiveErrorCode = uErr;
+ pVCpu->trpm.s.uActiveCR2 = 0xdeadface;
+ pVCpu->trpm.s.cbInstr = UINT8_MAX;
+ return VINF_EM_RAW_GUEST_TRAP;
+}
+
+
+/**
+ * Raises a cpu exception with an errorcode and CR2.
+ *
+ * This function may or may not dispatch the exception before returning.
+ *
+ * @returns VBox status code fit for scheduling.
+ * @retval VINF_EM_RAW_GUEST_TRAP if the exception was left pending.
+ * @retval VINF_TRPM_XCPT_DISPATCHED if the exception was raised and dispatched for raw-mode execution.
+ * @retval VINF_EM_RESCHEDULE_REM if the exception was dispatched and cannot be executed in raw-mode.
+ *
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param pCtxCore The CPU context core.
+ * @param enmXcpt The exception.
+ * @param uErr The error code.
+ * @param uCR2 The CR2 value.
+ */
+VMMDECL(int) TRPMRaiseXcptErrCR2(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt, uint32_t uErr, RTGCUINTPTR uCR2)
+{
+ LogFlow(("TRPMRaiseXcptErr: cs:eip=%RTsel:%RX32 enmXcpt=%#x uErr=%RX32 uCR2=%RGv\n", pCtxCore->cs.Sel, pCtxCore->eip, enmXcpt, uErr, uCR2));
+ NOREF(pCtxCore);
+/** @todo dispatch the trap. */
+ pVCpu->trpm.s.uActiveVector = enmXcpt;
+ pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
+ pVCpu->trpm.s.uActiveErrorCode = uErr;
+ pVCpu->trpm.s.uActiveCR2 = uCR2;
+ pVCpu->trpm.s.cbInstr = UINT8_MAX;
+ return VINF_EM_RAW_GUEST_TRAP;
+}
+
+
+#ifdef VBOX_WITH_RAW_MODE
+/**
+ * Clear guest trap/interrupt gate handler
+ *
+ * @returns VBox status code.
+ * @param pVM The cross context VM structure.
+ * @param iTrap Interrupt/trap number.
+ */
+VMMDECL(int) trpmClearGuestTrapHandler(PVM pVM, unsigned iTrap)
+{
+ AssertReturn(VM_IS_RAW_MODE_ENABLED(pVM), VERR_TRPM_HM_IPE);
+ AssertMsgReturn(iTrap < RT_ELEMENTS(pVM->trpm.s.aIdt), ("Illegal gate number %d!\n", iTrap), VERR_INVALID_PARAMETER);
+
+ if (ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iTrap))
+# ifdef IN_RING3
+ trpmR3ClearPassThroughHandler(pVM, iTrap);
+# else
+ AssertFailed();
+# endif
+
+ pVM->trpm.s.aGuestTrapHandler[iTrap] = TRPM_INVALID_HANDLER;
+ return VINF_SUCCESS;
+}
+#endif /* VBOX_WITH_RAW_MODE */
+