Index: /trunk/include/VBox/vmm/iem.h
===================================================================
--- /trunk/include/VBox/vmm/iem.h	(revision 37033)
+++ /trunk/include/VBox/vmm/iem.h	(revision 37034)
@@ -28,4 +28,5 @@
 
 #include <VBox/types.h>
+#include <VBox/vmm/trpm.h>
 
 
@@ -38,5 +39,6 @@
 
 
-VMMDECL(VBOXSTRICTRC) IEMExecOne(PVMCPU pVCpu);
+VMMDECL(VBOXSTRICTRC)       IEMExecOne(PVMCPU pVCpu);
+VMM_INT_DECL(VBOXSTRICTRC)  IEMInjectTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2);
 
 #if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 37033)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 37034)
@@ -1251,4 +1251,11 @@
 
 static VBOXSTRICTRC iemRaiseSelectorInvalidAccess(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess)
+{
+    AssertFailed(/** @todo implement this */);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static VBOXSTRICTRC iemRaiseSelectorNotPresentWithErr(PIEMCPU pIemCpu, uint16_t uErr)
 {
     AssertFailed(/** @todo implement this */);
@@ -4535,37 +4542,5 @@
         RTGCPTR     uCr2;
         int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2); AssertRC(rc2);
-        Log(("Injecting trap %#x\n", u8TrapNo));
-
-        uint32_t    fFlags;
-        switch (enmType)
-        {
-            case TRPM_HARDWARE_INT:
-                fFlags = IEM_XCPT_FLAGS_T_EXT_INT;
-                uErrCode = uCr2 = 0;
-                break;
-            case TRPM_SOFTWARE_INT:
-                fFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
-                uErrCode = uCr2 = 0;
-                break;
-            case TRPM_TRAP:
-                fFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
-                if (u8TrapNo == X86_XCPT_PF)
-                    fFlags |= IEM_XCPT_FLAGS_CR2;
-                switch (u8TrapNo)
-                {
-                    case X86_XCPT_DF:
-                    case X86_XCPT_TS:
-                    case X86_XCPT_NP:
-                    case X86_XCPT_SS:
-                    case X86_XCPT_PF:
-                    case X86_XCPT_AC:
-                        fFlags |= IEM_XCPT_FLAGS_ERR;
-                        break;
-                }
-                TRPMHasTrap(pVCpu)
-                break;
-            IEM_NOT_REACHED_DEFAULT_CASE_RET();
-        }
-        iemCImpl_RaiseXcptOrInt(pIemCpu, 0, u8TrapNo, fFlags, (uint16_t)uErrCode, uCr2);
+        IEMInjectTrap(pVCpu, u8TrapNo, enmType, (uint16_t)uErrCode, uCr2);
         if (!IEM_VERIFICATION_ENABLED(pIemCpu))
             TRPMResetTrap(pVCpu);
@@ -5338,2 +5313,57 @@
 }
 
+
+/**
+ * Injects a trap, fault, abort, software interrupt or external interrupt.
+ *
+ * The parameter list matches TRPMQueryTrapAll pretty closely.
+ *
+ * @returns Strict VBox status code.
+ * @param   pVCpu               The current virtual CPU.
+ * @param   u8TrapNo            The trap number.
+ * @param   enmType             What type is it (trap/fault/abort), software
+ *                              interrupt or hardware interrupt.
+ * @param   uErrCode            The error code if applicable.
+ * @param   uCr2                The CR2 value if applicable.
+ */
+VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2)
+{
+    uint32_t fFlags;
+    switch (enmType)
+    {
+        case TRPM_HARDWARE_INT:
+            Log(("IEMInjectTrap: %#4x ext\n", u8TrapNo));
+            fFlags = IEM_XCPT_FLAGS_T_EXT_INT;
+            uErrCode = uCr2 = 0;
+            break;
+
+        case TRPM_SOFTWARE_INT:
+            Log(("IEMInjectTrap: %#4x soft\n", u8TrapNo));
+            fFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
+            uErrCode = uCr2 = 0;
+            break;
+
+        case TRPM_TRAP:
+            Log(("IEMInjectTrap: %#4x trap err=%#x cr2=%#RGv\n", u8TrapNo, uErrCode, uCr2));
+            fFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
+            if (u8TrapNo == X86_XCPT_PF)
+                fFlags |= IEM_XCPT_FLAGS_CR2;
+            switch (u8TrapNo)
+            {
+                case X86_XCPT_DF:
+                case X86_XCPT_TS:
+                case X86_XCPT_NP:
+                case X86_XCPT_SS:
+                case X86_XCPT_PF:
+                case X86_XCPT_AC:
+                    fFlags |= IEM_XCPT_FLAGS_ERR;
+                    break;
+            }
+            break;
+
+        IEM_NOT_REACHED_DEFAULT_CASE_RET();
+    }
+
+    return iemCImpl_RaiseXcptOrInt(&pVCpu->iem.s, 0, u8TrapNo, fFlags, uErrCode, uCr2);
+}
+
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 37033)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 37034)
@@ -1138,14 +1138,228 @@
 
 
+/**
+ * Adjust the CPU state according to the exception being raised.
+ *
+ * @param   pCtx                The CPU context.
+ * @param   u8Vector            The exception that has been raised.
+ */
+DECLINLINE(void) iemCImpl_RaiseXcptAdjustState(PCPUMCTX pCtx, uint8_t u8Vector)
+{
+    switch (u8Vector)
+    {
+        case X86_XCPT_DB:
+            pCtx->dr[7] &= ~X86_DR7_GD;
+            break;
+        /** @todo Read the AMD and Intel exception reference... */
+    }
+}
+
+
+/**
+ * Implements exceptions and interrupts for real mode.
+ *
+ * @returns VBox strict status code.
+ * @param   pIemCpu         The IEM per CPU instance data.
+ * @param   pCtx            The CPU context.
+ * @param   cbInstr         The number of bytes to offset rIP by in the return
+ *                          address.
+ * @param   u8Vector        The interrupt / exception vector number.
+ * @param   fFlags          The flags.
+ * @param   uErr            The error value if IEM_XCPT_FLAGS_ERR is set.
+ * @param   uCr2            The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
+ */
 static VBOXSTRICTRC
-iemCImpl_RaiseXcptOrIntAgain(PIEMCPU     pIemCpu,
-                             uint8_t     u8Vector,
-                             uint32_t    fFlags,
-                             uint16_t    uErr,
-                             uint64_t    uCr2,
-                             uint8_t     u8PrevVector);
+iemCImpl_RaiseXcptOrIntInRealMode(PIEMCPU     pIemCpu,
+                                  PCPUMCTX    pCtx,
+                                  uint8_t     cbInstr,
+                                  uint8_t     u8Vector,
+                                  uint32_t    fFlags,
+                                  uint16_t    uErr,
+                                  uint64_t    uCr2)
+{
+    AssertReturn(pIemCpu->enmCpuMode == IEMMODE_16BIT, VERR_INTERNAL_ERROR_3);
+
+    /*
+     * Read the IDT entry.
+     */
+    if (pCtx->idtr.cbIdt < UINT32_C(4) * u8Vector + 3)
+    {
+        Log(("RaiseXcptOrIntInRealMode: %#x is out of bounds (%#x)\n", u8Vector, pCtx->idtr.cbIdt));
+        return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
+    }
+    RTFAR16 Idte;
+    VBOXSTRICTRC rcStrict = iemMemFetchDataU32(pIemCpu, (uint32_t *)&Idte, UINT8_MAX,
+                                               pCtx->idtr.pIdt + UINT32_C(4) * u8Vector);
+    if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
+        return rcStrict;
+
+    /*
+     * Push the stack frame.
+     */
+    uint16_t *pu16Frame;
+    uint64_t  uNewRsp;
+    rcStrict = iemMemStackPushBeginSpecial(pIemCpu, 6, (void **)&pu16Frame, &uNewRsp);
+    if (rcStrict != VINF_SUCCESS)
+        return rcStrict;
+
+    pu16Frame[2] = (uint16_t)pCtx->eflags.u;
+    pu16Frame[1] = (uint16_t)pCtx->cs;
+    pu16Frame[0] = pCtx->ip + cbInstr;
+    rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
+    if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
+        return rcStrict;
+
+    /*
+     * Load the vector address into cs:ip and make exception specific state
+     * adjustments.
+     */
+    pCtx->cs               = Idte.sel;
+    pCtx->csHid.u64Base    = (uint32_t)Idte.sel << 4;
+    /** @todo do we load attribs and limit as well? Should we check against limit like far jump? */
+    pCtx->rip              = Idte.off;
+    pCtx->eflags.Bits.u1IF = 0;
+
+    /** @todo do we actually do this in real mode? */
+    if (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
+        iemCImpl_RaiseXcptAdjustState(pCtx, u8Vector);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Implements exceptions and interrupts for protected mode.
+ *
+ * @returns VBox strict status code.
+ * @param   pIemCpu         The IEM per CPU instance data.
+ * @param   pCtx            The CPU context.
+ * @param   cbInstr         The number of bytes to offset rIP by in the return
+ *                          address.
+ * @param   u8Vector        The interrupt / exception vector number.
+ * @param   fFlags          The flags.
+ * @param   uErr            The error value if IEM_XCPT_FLAGS_ERR is set.
+ * @param   uCr2            The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
+ */
+static VBOXSTRICTRC
+iemCImpl_RaiseXcptOrIntInProtMode(PIEMCPU     pIemCpu,
+                                  PCPUMCTX    pCtx,
+                                  uint8_t     cbInstr,
+                                  uint8_t     u8Vector,
+                                  uint32_t    fFlags,
+                                  uint16_t    uErr,
+                                  uint64_t    uCr2)
+{
+    /*
+     * Read the IDT entry.
+     */
+    if (pCtx->idtr.cbIdt < UINT32_C(8) * u8Vector + 7)
+    {
+        Log(("RaiseXcptOrIntInProtMode: %#x is out of bounds (%#x)\n", u8Vector, pCtx->idtr.cbIdt));
+        return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
+    }
+    X86DESC Idte;
+    VBOXSTRICTRC rcStrict = iemMemFetchDataU64(pIemCpu, &Idte.u, UINT8_MAX,
+                                               pCtx->idtr.pIdt + UINT32_C(8) * u8Vector);
+    if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
+        return rcStrict;
+
+    /*
+     * Check the descriptor type, DPL and such.
+     * ASSUMES this is done in the same order as described for selectors.
+     */
+    if (Idte.Gate.u1DescType)
+    {
+        Log(("RaiseXcptOrIntInProtMode %#x - not system selector (%#x) -> #GP\n", u8Vector, Idte.Gate.u4Type));
+        return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
+    }
+    uint32_t fEflToClear = X86_EFL_TF | X86_EFL_NT | X86_EFL_RF | X86_EFL_VM;
+    switch (Idte.Gate.u4Type)
+    {
+        case X86_SEL_TYPE_SYS_UNDEFINED:
+        case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
+        case X86_SEL_TYPE_SYS_LDT:
+        case X86_SEL_TYPE_SYS_286_TSS_BUSY:
+        case X86_SEL_TYPE_SYS_286_CALL_GATE:
+        case X86_SEL_TYPE_SYS_UNDEFINED2:
+        case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
+        case X86_SEL_TYPE_SYS_UNDEFINED3:
+        case X86_SEL_TYPE_SYS_386_TSS_BUSY:
+        case X86_SEL_TYPE_SYS_386_CALL_GATE:
+        case X86_SEL_TYPE_SYS_UNDEFINED4:
+        {
+            /** @todo check what actually happens when the type is wrong...
+             *        esp. call gates. */
+            Log(("RaiseXcptOrIntInProtMode %#x - invalid type (%#x) -> #GP\n", u8Vector, Idte.Gate.u4Type));
+            return iemRaiseGeneralProtectionFault(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
+        }
+
+        case X86_SEL_TYPE_SYS_286_INT_GATE:
+        case X86_SEL_TYPE_SYS_386_INT_GATE:
+            fEflToClear |= X86_EFL_IF;
+            break;
+
+        case X86_SEL_TYPE_SYS_TASK_GATE:
+        case X86_SEL_TYPE_SYS_286_TRAP_GATE:
+        case X86_SEL_TYPE_SYS_386_TRAP_GATE:
+            break;
+
+        IEM_NOT_REACHED_DEFAULT_CASE_RET();
+    }
+
+    /* Check DPL against CPL if applicable. */
+    if (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
+    {
+#if 0 /** @todo continue here */
+        if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
+        {
+            Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
+                 iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
+            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+        }
+#endif
+    }
+
+    /* Is it there? */
+    if (!Idte.Gate.u1Present)
+    {
+        Log(("RaiseXcptOrIntInProtMode %#x - not present -> #NP\n", u8Vector));
+        return iemRaiseSelectorNotPresentWithErr(pIemCpu, X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT));
+    }
+
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Implements exceptions and interrupts for long mode.
+ *
+ * @returns VBox strict status code.
+ * @param   pIemCpu         The IEM per CPU instance data.
+ * @param   pCtx            The CPU context.
+ * @param   cbInstr         The number of bytes to offset rIP by in the return
+ *                          address.
+ * @param   u8Vector        The interrupt / exception vector number.
+ * @param   fFlags          The flags.
+ * @param   uErr            The error value if IEM_XCPT_FLAGS_ERR is set.
+ * @param   uCr2            The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
+ */
+static VBOXSTRICTRC
+iemCImpl_RaiseXcptOrIntInLongMode(PIEMCPU     pIemCpu,
+                                  PCPUMCTX    pCtx,
+                                  uint8_t     cbInstr,
+                                  uint8_t     u8Vector,
+                                  uint32_t    fFlags,
+                                  uint16_t    uErr,
+                                  uint64_t    uCr2)
+{
+    AssertMsgFailed(("long mode exception / interrupt dispatching\n"));
+    return VERR_NOT_IMPLEMENTED;
+}
+
 
 /**
  * Implements exceptions and interrupts.
+ *
+ * All exceptions and interrupts goes thru this function!
  *
  * @returns VBox strict status code.
@@ -1166,81 +1380,35 @@
                         uint64_t    uCr2)
 {
-    /** @todo we should call TRPM to do this job.  */
+    /*
+     * Do recursion accounting.
+     */
+    uint8_t uPrevXcpt = pIemCpu->uCurXcpt;
+    if (pIemCpu->cXcptRecursions > 0)
+    {
+        /** @todo double and tripple faults. */
+        AssertReturn(pIemCpu->cXcptRecursions < 3, VERR_NOT_IMPLEMENTED);
+    }
+    pIemCpu->cXcptRecursions++;
+    pIemCpu->uCurXcpt = u8Vector;
+
+    /*
+     * Call mode specific worker function.
+     */
     VBOXSTRICTRC    rcStrict;
     PCPUMCTX        pCtx = pIemCpu->CTX_SUFF(pCtx);
-
-    /*
-     * Real mode is easy.
-     */
-    if (   pIemCpu->enmCpuMode == IEMMODE_16BIT
-        && IEM_IS_REAL_MODE(pIemCpu))
-    {
-        /* read the IDT entry. */
-        if (pCtx->idtr.cbIdt < UINT32_C(4) * u8Vector + 3)
-            return iemCImpl_RaiseXcptOrIntAgain(pIemCpu,
-                                                X86_XCPT_GP,
-                                                IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR
-                                                | (fFlags & IEM_XCPT_FLAGS_NESTING_MASK),
-                                                X86_TRAP_ERR_IDT | ((uint16_t)u8Vector << X86_TRAP_ERR_SEL_SHIFT),
-                                                0,
-                                                u8Vector);
-        RTFAR16 Idte;
-        rcStrict = iemMemFetchDataU32(pIemCpu, (uint32_t *)&Idte, UINT8_MAX, pCtx->idtr.pIdt + UINT32_C(4) * u8Vector);
-        if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
-            return rcStrict;
-
-        /* push the stack frame. */
-        uint16_t *pu16Frame;
-        uint64_t  uNewRsp;
-        rcStrict = iemMemStackPushBeginSpecial(pIemCpu, 6, (void **)&pu16Frame, &uNewRsp);
-        if (rcStrict != VINF_SUCCESS)
-            return rcStrict;
-
-        pu16Frame[2] = (uint16_t)pCtx->eflags.u;
-        pu16Frame[1] = (uint16_t)pCtx->cs;
-        pu16Frame[0] = pCtx->ip + cbInstr;
-        rcStrict = iemMemStackPushCommitSpecial(pIemCpu, pu16Frame, uNewRsp);
-        if (RT_UNLIKELY(rcStrict != VINF_SUCCESS))
-            return rcStrict;
-
-        /* load the vector address into cs:ip. */
-        pCtx->cs               = Idte.sel;
-        pCtx->csHid.u64Base    = (uint32_t)Idte.sel << 4;
-        /** @todo do we load attribs and limit as well? Should we check against limit like far jump? */
-        pCtx->rip              = Idte.off;
-        pCtx->eflags.Bits.u1IF = 0;
-        return VINF_SUCCESS;
-    }
-
-    /*
-     * continue here...
-     */
-    AssertFailed();
-    return VERR_NOT_IMPLEMENTED;
-}
-
-
-/**
- * Deals with exceptions occuring while dispatching an exception or interrupt.
- *
- * @returns VBox strict status code.
- * @param   pIemCpu         The IEM per CPU instance data.
- * @param   u8Vector        The exception vector number.
- * @param   fFlags          The flags.
- * @param   uErr            The error value if IEM_XCPT_FLAGS_ERR is set.
- * @param   uCr2            The CR2 value if IEM_XCPT_FLAGS_CR2 is set.
- * @param   u8PrevVector    The exception we tried raising.
- */
-static VBOXSTRICTRC
-iemCImpl_RaiseXcptOrIntAgain(PIEMCPU     pIemCpu,
-                             uint8_t     u8Vector,
-                             uint32_t    fFlags,
-                             uint16_t    uErr,
-                             uint64_t    uCr2,
-                             uint8_t     u8PrevVector)
-{
-    return iemCImpl_RaiseXcptOrInt(pIemCpu, 0, u8Vector, fFlags, uErr, uCr2);
-}
-
+    if (!(pCtx->cr0 & X86_CR0_PE))
+        rcStrict = iemCImpl_RaiseXcptOrIntInRealMode(pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
+    else if (pCtx->msrEFER & MSR_K6_EFER_LMA)
+        rcStrict = iemCImpl_RaiseXcptOrIntInLongMode(pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
+    else
+        rcStrict = iemCImpl_RaiseXcptOrIntInProtMode(pIemCpu, pCtx, cbInstr, u8Vector, fFlags, uErr, uCr2);
+
+    /*
+     * Unwind.
+     */
+    pIemCpu->cXcptRecursions--;
+    pIemCpu->uCurXcpt = uPrevXcpt;
+    return rcStrict;
+}
 
 
@@ -1253,4 +1421,5 @@
 IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, bool, fIsBpInstr)
 {
+    Assert(pIemCpu->cXcptRecursions == 0);
     return iemCImpl_RaiseXcptOrInt(pIemCpu,
                                    cbInstr,
Index: /trunk/src/VBox/VMM/include/IEMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 37033)
+++ /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 37034)
@@ -147,6 +147,10 @@
     bool                    fByPassHandlers;
     /** Explicit alignment padding. */
-    bool                    afAlignment0[6];
-
+    bool                    afAlignment0[4];
+
+    /** Exception / interrupt recursion depth. */
+    int8_t                  cXcptRecursions;
+    /** The current exception / interrupt . */
+    uint8_t                 uCurXcpt;
     /** The CPL. */
     uint8_t                 uCpl;
