Index: /trunk/include/VBox/vmm/iem.h
===================================================================
--- /trunk/include/VBox/vmm/iem.h	(revision 66685)
+++ /trunk/include/VBox/vmm/iem.h	(revision 66686)
@@ -38,4 +38,59 @@
  * @{
  */
+
+/** @name IEMXCPTRAISEINFO_XXX - Extra info. on a recursive exception situation.
+ *
+ * This is primarily used by HM for working around a PGM limitation (see
+ * @bugref{6607}) and special NMI/IRET handling. In the future, this may be
+ * used for diagnostics.
+ *
+ * @{
+ */
+typedef uint32_t IEMXCPTRAISEINFO;
+/** Pointer to a IEMXCPTINFO type. */
+typedef IEMXCPTRAISEINFO *PIEMXCPTRAISEINFO;
+/** No addition info. available. */
+#define IEMXCPTRAISEINFO_NONE                    RT_BIT_32(0)
+/** Delivery of a \#AC caused another \#AC. */
+#define IEMXCPTRAISEINFO_AC_AC                   RT_BIT_32(1)
+/** Delivery of a \#PF caused another \#PF. */
+#define IEMXCPTRAISEINFO_PF_PF                   RT_BIT_32(2)
+/** Delivery of a \#PF caused some contributory exception. */
+#define IEMXCPTRAISEINFO_PF_CONTRIBUTORY_XCPT    RT_BIT_32(3)
+/** Delivery of an external interrupt caused an exception. */
+#define IEMXCPTRAISEINFO_EXT_INT_XCPT            RT_BIT_32(4)
+/** Delivery of an software interrupt caused an exception. */
+#define IEMXCPTRAISEINFO_EXT_INT_PF              RT_BIT_32(5)
+/** Delivery of an external interrupt caused a \#PF. */
+#define IEMXCPTRAISEINFO_SOFT_INT_XCPT           RT_BIT_32(6)
+/** Delivery of an NMI caused a \#PF. */
+#define IEMXCPTRAISEINFO_NMI_PF                  RT_BIT_32(7)
+/** Can re-execute the instruction at CS:RIP. */
+#define IEMXCPTRAISEINFO_CAN_REEXEC_INSTR        RT_BIT_32(8)
+/** @} */
+
+
+/** @name IEMXCPTRAISE_XXX - Ways to handle a recursive exception condition.
+ * @{ */
+typedef enum IEMXCPTRAISE
+{
+    /** Raise the current (second) exception. */
+    IEMXCPTRAISE_CURRENT_XCPT = 0,
+    /** Re-raise the previous (first) event (for HM, unused by IEM). */
+    IEMXCPTRAISE_PREV_EVENT,
+    /** Re-execute instruction at CS:RIP (for HM, unused by IEM). */
+    IEMXCPTRAISE_REEXEC_INSTR,
+    /** Raise a \#DF exception. */
+    IEMXCPTRAISE_DOUBLE_FAULT,
+    /** Raise a triple fault. */
+    IEMXCPTRAISE_TRIPLE_FAULT,
+    /** Cause a CPU hang. */
+    IEMXCPTRAISE_CPU_HANG,
+    /** Invalid sequence of events. */
+    IEMXCPTRAISE_INVALID = 0x7fffffff
+} IEMXCPTRAISE;
+/** Pointer to a IEMXCPTRAISE type. */
+typedef IEMXCPTRAISE *PIEMXCPTRAISE;
+/** @} */
 
 
@@ -66,4 +121,8 @@
 /** Generated by a DRx instruction breakpoint and RF should be cleared. */
 #define IEM_XCPT_FLAGS_DRx_INSTR_BP     RT_BIT_32(6)
+/** Generated by the icebp instruction. */
+#define IEM_XCPT_FLAGS_ICEBP_INSTR      RT_BIT_32(7)
+/** Generated by the overflow instruction. */
+#define IEM_XCPT_FLAGS_OF_INSTR         RT_BIT_32(8)
 /** @}  */
 
@@ -139,4 +198,6 @@
 VMM_INT_DECL(bool)          IEMGetCurrentXcpt(PVMCPU pVCpu, uint8_t *puVector, uint32_t *pfFlags, uint32_t *puErr,
                                               uint64_t *puCr2);
+VMM_INT_DECL(IEMXCPTRAISE)  IEMEvaluateRecursiveXcpt(PVMCPU pVCpu, uint32_t fPrevFlags, uint8_t uPrevVector, uint32_t fCurFlags,
+                                                     uint8_t uCurVector, PIEMXCPTRAISEINFO pXcptRaiseInfo);
 
 /** @name Given Instruction Interpreters
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 66685)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 66686)
@@ -215,4 +215,14 @@
 /** Pointer to a selector descriptor table entry. */
 typedef IEMSELDESC *PIEMSELDESC;
+
+/**
+ * CPU exception classes.
+ */
+typedef enum IEMXCPTCLASS
+{
+    IEMXCPTCLASS_BENIGN,
+    IEMXCPTCLASS_CONTRIBUTORY,
+    IEMXCPTCLASS_PAGE_FAULT
+} IEMXCPTCLASS;
 
 
@@ -3212,8 +3222,124 @@
  */
 
-/* Currently used only with nested hw.virt. */
-#ifdef VBOX_WITH_NESTED_HWVIRT
-/**
- * Initiates a CPU shutdown sequence.
+/**
+ * Gets the exception class for the specified exception vector.
+ *  
+ * @returns The class of the specified exception.
+ * @param   uVector       The exception vector. 
+ */
+IEM_STATIC IEMXCPTCLASS iemGetXcptClass(uint8_t uVector)
+{
+    Assert(uVector <= X86_XCPT_LAST);
+    switch (uVector)
+    {
+        case X86_XCPT_DE:
+        case X86_XCPT_TS:
+        case X86_XCPT_NP:
+        case X86_XCPT_SS:
+        case X86_XCPT_GP:
+        case X86_XCPT_SX:   /* AMD only */
+            return IEMXCPTCLASS_CONTRIBUTORY;
+
+        case X86_XCPT_PF:
+        case X86_XCPT_VE:   /* Intel only */
+            return IEMXCPTCLASS_PAGE_FAULT;
+    }
+    return IEMXCPTCLASS_BENIGN;
+}
+
+
+/**
+ * Evaluates how to handle an exception caused during delivery of another event
+ * (exception / interrupt).
+ *  
+ * @returns How to handle the recursive exception. 
+ * @param   pVCpu               The cross context virtual CPU structure of the
+ *                              calling thread.
+ * @param   fPrevFlags          The flags of the previous event.
+ * @param   uPrevVector         The vector of the previous event.
+ * @param   fCurFlags           The flags of the current exception.
+ * @param   uCurVector          The vector of the current exception.
+ * @param   pfXcptRaiseInfo     Where to store additional information about the
+ *                              exception condition. Optional.
+ */
+VMM_INT_DECL(IEMXCPTRAISE) IEMEvaluateRecursiveXcpt(PVMCPU pVCpu, uint32_t fPrevFlags, uint8_t uPrevVector, uint32_t fCurFlags,
+                                                    uint8_t uCurVector, PIEMXCPTRAISEINFO pfXcptRaiseInfo)
+{
+    /*
+     * Only CPU exceptions can be raised while delivering other events, software interrupt
+     * (INTn/INT3/INTO/ICEBP) generated exceptions cannot occur as the current (second) exception.
+     */
+    AssertReturn(fCurFlags & IEM_XCPT_FLAGS_T_CPU_XCPT, IEMXCPTRAISE_INVALID);
+    Assert(pVCpu);
+
+    IEMXCPTRAISE     enmRaise   = IEMXCPTRAISE_CURRENT_XCPT;
+    IEMXCPTRAISEINFO fRaiseInfo = IEMXCPTRAISEINFO_NONE;
+    if (fPrevFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
+    {
+        IEMXCPTCLASS enmPrevXcptClass = iemGetXcptClass(uPrevVector);
+        if (enmPrevXcptClass != IEMXCPTCLASS_BENIGN)
+        {
+            IEMXCPTCLASS enmCurXcptClass  = iemGetXcptClass(uCurVector);
+            if (   enmPrevXcptClass == IEMXCPTCLASS_PAGE_FAULT
+                && (   enmCurXcptClass == IEMXCPTCLASS_PAGE_FAULT
+                    || enmCurXcptClass == IEMXCPTCLASS_CONTRIBUTORY))
+            {
+                enmRaise = IEMXCPTRAISE_DOUBLE_FAULT;
+                if (enmCurXcptClass == IEMXCPTCLASS_PAGE_FAULT)
+                    fRaiseInfo = IEMXCPTRAISEINFO_PF_PF;
+                else
+                    fRaiseInfo = IEMXCPTRAISEINFO_PF_CONTRIBUTORY_XCPT;
+                Log2(("IEMEvaluateRecursiveXcpt: Vectoring page fault. uPrevVector=%#x uCurVector=%#x uCr2=%#RX64\n", uPrevVector,
+                      uCurVector, IEM_GET_CTX(pVCpu)->cr2));
+            }
+            else if (   enmPrevXcptClass == IEMXCPTCLASS_CONTRIBUTORY
+                     && enmCurXcptClass  == IEMXCPTCLASS_CONTRIBUTORY)
+            {
+                enmRaise = IEMXCPTRAISE_DOUBLE_FAULT;
+                Log2(("IEMEvaluateRecursiveXcpt: uPrevVector=%u uCurVector=%u -> #DF\n", uPrevVector, uCurVector));
+            }
+            else if (   uPrevVector == X86_XCPT_DF
+                     && (   enmCurXcptClass == IEMXCPTCLASS_CONTRIBUTORY
+                         || enmCurXcptClass == IEMXCPTCLASS_PAGE_FAULT))
+            {
+                enmRaise = IEMXCPTRAISE_TRIPLE_FAULT;
+                Log2(("IEMEvaluateRecursiveXcpt: #DF handler raised a %#x exception -> triple fault\n", uCurVector));
+            }
+        }
+        else
+        {
+            if (   uPrevVector == X86_XCPT_NMI
+                && uCurVector  == X86_XCPT_PF)
+            {
+                fRaiseInfo = IEMXCPTRAISEINFO_NMI_PF;
+                Log2(("IEMEvaluateRecursiveXcpt: NMI delivery caused a page fault\n"));
+            }
+            else if (   uPrevVector == X86_XCPT_AC
+                     && uCurVector  == X86_XCPT_AC)
+            {
+                enmRaise   = IEMXCPTRAISE_CPU_HANG;
+                fRaiseInfo = IEMXCPTRAISEINFO_AC_AC;
+                Log2(("IEMEvaluateRecursiveXcpt: Recursive #AC - Bad guest\n"));
+            }
+        }
+    }
+    else if (fPrevFlags & IEM_XCPT_FLAGS_T_EXT_INT)
+    {
+        fRaiseInfo = IEMXCPTRAISEINFO_EXT_INT_XCPT;
+        if (uCurVector == X86_XCPT_PF)
+            fRaiseInfo |= IEMXCPTRAISEINFO_EXT_INT_PF;
+    }
+    else
+        fRaiseInfo = IEMXCPTRAISEINFO_SOFT_INT_XCPT;
+
+    if (pfXcptRaiseInfo)
+        *pfXcptRaiseInfo = fRaiseInfo;
+    return enmRaise; 
+}
+
+
+/**
+ * Enters the CPU shutdown state initiated by a triple fault or other
+ * unrecoverable conditions.
  *
  * @returns Strict VBox status code.
@@ -3230,7 +3356,83 @@
 
     RT_NOREF_PV(pVCpu);
-    /** @todo Probably need a separate error code and handling for this to
-     *        distinguish it from the regular triple fault. */
     return VINF_EM_TRIPLE_FAULT;
+}
+
+
+#ifdef VBOX_WITH_NESTED_HWVIRT
+IEM_STATIC VBOXSTRICTRC iemHandleSvmNstGstEventIntercept(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t u8Vector, uint32_t fFlags,
+                                                         uint32_t uErr, uint64_t uCr2)
+{
+    Assert(IEM_IS_SVM_ENABLED(pVCpu));
+
+    /*
+     * Handle nested-guest SVM exception and software interrupt intercepts,
+     * see AMD spec. 15.12 "Exception Intercepts".
+     *
+     *   - NMI intercepts have their own exit code and do not cause SVM_EXIT_EXCEPTION_2 #VMEXITs.
+     *   - External interrupts and software interrupts (INTn instruction) do not check the exception intercepts
+     *     even when they use a vector in the range 0 to 31.
+     *   - ICEBP should not trigger #DB intercept, but its own intercept.
+     *   - For #PF exceptions, its intercept is checked before CR2 is written by the exception.
+     */
+    /* Check NMI intercept */
+    if (   u8Vector == X86_XCPT_NMI
+        && (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
+        && IEM_IS_SVM_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_NMI))
+    {
+        Log2(("iemHandleSvmNstGstEventIntercept: NMI intercept -> #VMEXIT\n"));
+        IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_NMI, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
+    }
+
+    /* Check ICEBP intercept. */
+    if (   (fFlags & IEM_XCPT_FLAGS_ICEBP_INSTR)
+        && IEM_IS_SVM_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_ICEBP))
+    {
+        Log2(("iemHandleSvmNstGstEventIntercept: ICEBP intercept -> #VMEXIT\n"));
+        IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_ICEBP, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
+    }
+
+    /* Check CPU exception intercepts. */
+    if (   (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT)
+        && IEM_IS_SVM_XCPT_INTERCEPT_SET(pVCpu, u8Vector))
+    {
+        Assert(u8Vector <= X86_XCPT_LAST);
+        uint64_t const uExitInfo1 = fFlags & IEM_XCPT_FLAGS_ERR ? uErr : 0;
+        uint64_t const uExitInfo2 = fFlags & IEM_XCPT_FLAGS_CR2 ? uCr2 : 0;
+        if (   IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssist
+            && u8Vector == X86_XCPT_PF
+            && !(uErr & X86_TRAP_PF_ID))
+        {
+            /** @todo Nested-guest SVM - figure out fetching op-code bytes from IEM. */
+#ifdef IEM_WITH_CODE_TLB
+#else
+            uint8_t const offOpCode = pVCpu->iem.s.offOpcode;
+            uint8_t const cbCurrent = pVCpu->iem.s.cbOpcode - pVCpu->iem.s.offOpcode;
+            if (   cbCurrent > 0
+                && cbCurrent < sizeof(pCtx->hwvirt.svm.VmcbCtrl.abInstr))
+            {
+                Assert(cbCurrent <= sizeof(pVCpu->iem.s.abOpcode));
+                memcpy(&pCtx->hwvirt.svm.VmcbCtrl.abInstr[0], &pVCpu->iem.s.abOpcode[offOpCode], cbCurrent);
+            }
+#endif
+        }
+        Log2(("iemHandleSvmNstGstEventIntercept: Xcpt intercept. u8Vector=%#x uExitInfo1=%#RX64, uExitInfo2=%#RX64 -> #VMEXIT\n",
+             u8Vector, uExitInfo1, uExitInfo2));
+        IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_EXCEPTION_0 + u8Vector, uExitInfo1, uExitInfo2);
+    }
+
+    /* Check software interrupt (INTn) intercepts. */
+    if (   (fFlags & (  IEM_XCPT_FLAGS_T_SOFT_INT
+                      | IEM_XCPT_FLAGS_BP_INSTR
+                      | IEM_XCPT_FLAGS_ICEBP_INSTR
+                      | IEM_XCPT_FLAGS_OF_INSTR)) == IEM_XCPT_FLAGS_T_SOFT_INT
+        && IEM_IS_SVM_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_INTN))
+    {
+        uint64_t const uExitInfo1 = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssist ? u8Vector : 0;
+        Log2(("iemHandleSvmNstGstEventIntercept: Software INT intercept (u8Vector=%#x) -> #VMEXIT\n", u8Vector));
+        IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_SWINT, uExitInfo1, 0 /* uExitInfo2 */);
+    }
+
+    return VINF_HM_INTERCEPT_NOT_ACTIVE;
 }
 #endif
@@ -5253,57 +5455,19 @@
     {
         /*
-         * Handle nested-guest SVM exception and software interrupt intercepts,
-         * see AMD spec. 15.12 "Exception Intercepts".
-         *
-         *   - NMI intercepts have their own exit code and do not cause SVM_EXIT_EXCEPTION_2 #VMEXITs.
-         *   - External interrupts and software interrupts (INTn instruction) do not check the exception intercepts
-         *     even when they use a vector in the range 0 to 31.
-         *   - ICEBP should not trigger #DB intercept, but its own intercept, so we catch it early in iemOp_int1.
-         *   - For #PF exceptions, its intercept is checked before CR2 is written by the exception.
+         * If the event is being injected as part of VMRUN, it isn't subject to event
+         * intercepts in the nested-guest. However, secondary exceptions that occur
+         * during injection of any event -are- subject to exception intercepts.
+         * See AMD spec. 15.20 "Event Injection".
          */
-        /* Check NMI intercept */
-        if (   u8Vector == X86_XCPT_NMI
-            && IEM_IS_SVM_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_NMI))
-        {
-            Log(("iemRaiseXcptOrInt: NMI intercept -> #VMEXIT\n"));
-            IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_NMI, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
-        }
-
-        /* Check CPU exception intercepts. */
-        if (   IEM_IS_SVM_XCPT_INTERCEPT_SET(pVCpu, u8Vector)
-            && (fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT))
-        {
-            Assert(u8Vector <= X86_XCPT_LAST);
-            uint64_t const uExitInfo1 = fFlags & IEM_XCPT_FLAGS_ERR ? uErr : 0;
-            uint64_t const uExitInfo2 = fFlags & IEM_XCPT_FLAGS_CR2 ? uCr2 : 0;
-            if (   IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssist
-                && u8Vector == X86_XCPT_PF
-                && !(uErr & X86_TRAP_PF_ID))
-            {
-                /** @todo Nested-guest SVM - figure out fetching op-code bytes from IEM. */
-#ifdef IEM_WITH_CODE_TLB
-#else
-                uint8_t const offOpCode = pVCpu->iem.s.offOpcode;
-                uint8_t const cbCurrent = pVCpu->iem.s.cbOpcode - pVCpu->iem.s.offOpcode;
-                if (   cbCurrent > 0
-                    && cbCurrent < sizeof(pCtx->hwvirt.svm.VmcbCtrl.abInstr))
-                {
-                    Assert(cbCurrent <= sizeof(pVCpu->iem.s.abOpcode));
-                    memcpy(&pCtx->hwvirt.svm.VmcbCtrl.abInstr[0], &pVCpu->iem.s.abOpcode[offOpCode], cbCurrent);
-                }
-#endif
-            }
-            Log(("iemRaiseXcptOrInt: Xcpt intercept (u8Vector=%#x uExitInfo1=%#RX64, uExitInfo2=%#RX64 -> #VMEXIT\n", u8Vector,
-                 uExitInfo1, uExitInfo2));
-            IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_EXCEPTION_0 + u8Vector, uExitInfo1, uExitInfo2);
-        }
-
-        /* Check software interrupt (INTn) intercepts. */
-        if (   IEM_IS_SVM_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_INTN)
-            && (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT))
-        {
-            uint64_t const uExitInfo1 = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fSvmDecodeAssist ? u8Vector : 0;
-            Log(("iemRaiseXcptOrInt: Software INT intercept (u8Vector=%#x) -> #VMEXIT\n", u8Vector));
-            IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_SWINT, uExitInfo1, 0 /* uExitInfo2 */);
+        if (!pCtx->hwvirt.svm.fInterceptEvents)
+            pCtx->hwvirt.svm.fInterceptEvents = 1;
+        else
+        {
+            /*
+             * Check and handle if the event being raised is intercepted.
+             */
+            VBOXSTRICTRC rcStrict0 = iemHandleSvmNstGstEventIntercept(pVCpu, pCtx, u8Vector, fFlags, uErr, uCr2);
+            if (rcStrict0 != VINF_HM_INTERCEPT_NOT_ACTIVE)
+                return rcStrict0;
         }
     }
@@ -5321,9 +5485,7 @@
     {
         Log(("iemRaiseXcptOrInt: %#x at %04x:%RGv cbInstr=%#x fFlags=%#x uErr=%#x uCr2=%llx; prev=%#x depth=%d flags=%#x\n",
-             u8Vector, pCtx->cs.Sel, pCtx->rip, cbInstr, fFlags, uErr, uCr2, pVCpu->iem.s.uCurXcpt, pVCpu->iem.s.cXcptRecursions + 1, fPrevXcpt));
-
-        /** @todo double and tripple faults. */
-        /** @todo When implementing \#DF, the SVM nested-guest \#DF intercepts needs
-         *        some care. See AMD spec. 15.12 "Exception Intercepts". */
+             u8Vector, pCtx->cs.Sel, pCtx->rip, cbInstr, fFlags, uErr, uCr2, pVCpu->iem.s.uCurXcpt,
+             pVCpu->iem.s.cXcptRecursions + 1, fPrevXcpt));
+
         if (pVCpu->iem.s.cXcptRecursions >= 3)
         {
@@ -5334,10 +5496,57 @@
         }
 
-        /** @todo set X86_TRAP_ERR_EXTERNAL when appropriate.
-        if (fPrevXcpt & IEM_XCPT_FLAGS_T_EXT_INT)
-        {
-        ....
-        } */
-    }
+        /*
+         * Evaluate the sequence of recurring events.
+         */
+        IEMXCPTRAISE enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fPrevXcpt, uPrevXcpt, fFlags, u8Vector,
+                                                         NULL /* pXcptRaiseInfo */);
+        if (enmRaise == IEMXCPTRAISE_CURRENT_XCPT)
+        { /* likely */ }
+        else if (enmRaise == IEMXCPTRAISE_DOUBLE_FAULT)
+        {
+            fFlags   = IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR;
+            u8Vector = X86_XCPT_DF;
+            uErr     = 0;
+            /* SVM nested-guest #DF intercepts need to be checked now. See AMD spec. 15.12 "Exception Intercepts". */
+            if (IEM_IS_SVM_XCPT_INTERCEPT_SET(pVCpu, X86_XCPT_DF))
+                IEM_RETURN_SVM_NST_GST_VMEXIT(pVCpu, SVM_EXIT_EXCEPTION_0 + X86_XCPT_DF, 0 /* uExitInfo1 */, 0 /* uExitInfo2 */);
+        }
+        else if (enmRaise == IEMXCPTRAISE_TRIPLE_FAULT)
+        {
+            Log2(("iemRaiseXcptOrInt: raising triple fault. uPrevXcpt=%#x\n", uPrevXcpt));
+            return iemInitiateCpuShutdown(pVCpu);
+        }
+        else if (enmRaise == IEMXCPTRAISE_CPU_HANG)
+        {
+            /* If a nested-guest enters an endless CPU loop condition, we'll emulate it; otherwise guru. */
+            Log2(("iemRaiseXcptOrInt: CPU hang condition detected\n"));
+            if (!CPUMIsGuestInNestedHwVirtMode(pCtx))
+                return VERR_EM_GUEST_CPU_HANG;
+        }
+        else
+        {
+            AssertMsgFailed(("Unexpected condition! enmRaise=%#x uPrevXcpt=%#x fPrevXcpt=%#x, u8Vector=%#x fFlags=%#x\n",
+                             enmRaise, uPrevXcpt, fPrevXcpt, u8Vector, fFlags));
+            return VERR_IEM_IPE_9;
+        }
+
+        /*
+         * The 'EXT' bit is set when an exception occurs during deliver of an external
+         * event (such as an interrupt or earlier exception), see Intel spec. 6.13
+         * "Error Code".
+         *
+         * For exceptions generated by software interrupts and INTO, INT3 instructions,
+         * the 'EXT' bit will not be set, see Intel Instruction reference for INT n.
+         */
+        /** @todo Would INT1/ICEBP raised \#DB set the 'EXT' bit or not? Testcase... */
+        if (   (fPrevXcpt & (IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_T_EXT_INT))
+            && (fFlags & IEM_XCPT_FLAGS_ERR)
+            && u8Vector != X86_XCPT_PF
+            && u8Vector != X86_XCPT_DF)
+        {
+            uErr |= X86_TRAP_ERR_EXTERNAL;
+        }
+    }
+
     pVCpu->iem.s.cXcptRecursions++;
     pVCpu->iem.s.uCurXcpt    = u8Vector;
@@ -15223,4 +15432,6 @@
  * @param   puCr2           Where to store the CR2 associated with the event,
  *                          optional.
+ * @remarks The caller should check the flags to determine if the error code and
+ *          CR2 are valid for the event.
  */
 VMM_INT_DECL(bool) IEMGetCurrentXcpt(PVMCPU pVCpu, uint8_t *puVector, uint32_t *pfFlags, uint32_t *puErr, uint64_t *puCr2)
@@ -15233,5 +15444,4 @@
         if (pfFlags)
             *pfFlags = pVCpu->iem.s.fCurXcpt;
-        /* The caller should check the flags to determine if the error code & CR2 are valid for the event. */
         if (puErr)
             *puErr = pVCpu->iem.s.uCurXcptErr;
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 66685)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 66686)
@@ -2862,7 +2862,7 @@
  *
  * @param   u8Int       The interrupt vector number.
- * @param   fIsBpInstr  Is it the breakpoint instruction.
- */
-IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, bool, fIsBpInstr)
+ * @param   enmInt      The int instruction type.
+ */
+IEM_CIMPL_DEF_2(iemCImpl_int, uint8_t, u8Int, IEMINT, enmInt)
 {
     Assert(pVCpu->iem.s.cXcptRecursions == 0);
@@ -2870,5 +2870,5 @@
                              cbInstr,
                              u8Int,
-                             (fIsBpInstr ? IEM_XCPT_FLAGS_BP_INSTR : 0) | IEM_XCPT_FLAGS_T_SOFT_INT,
+                             IEM_XCPT_FLAGS_T_SOFT_INT | enmInt,
                              0,
                              0);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsOneByte.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsOneByte.cpp.h	(revision 66685)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsOneByte.cpp.h	(revision 66686)
@@ -6507,5 +6507,5 @@
 {
     IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
-    return IEM_MC_DEFER_TO_CIMPL_2(iemCImpl_int, X86_XCPT_BP, true /*fIsBpInstr*/);
+    return IEM_MC_DEFER_TO_CIMPL_2(iemCImpl_int, X86_XCPT_BP, IEMINT_INT3);
 }
 
@@ -6518,5 +6518,5 @@
     uint8_t u8Int; IEM_OPCODE_GET_NEXT_U8(&u8Int);
     IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
-    return IEM_MC_DEFER_TO_CIMPL_2(iemCImpl_int, u8Int, false /*fIsBpInstr*/);
+    return IEM_MC_DEFER_TO_CIMPL_2(iemCImpl_int, u8Int, IEMINT_INTN);
 }
 
@@ -6531,7 +6531,7 @@
 
     IEM_MC_BEGIN(2, 0);
-    IEM_MC_ARG_CONST(uint8_t,   u8Int,      /*=*/ X86_XCPT_OF, 0);
-    IEM_MC_ARG_CONST(bool,      fIsBpInstr, /*=*/ false, 1);
-    IEM_MC_CALL_CIMPL_2(iemCImpl_int, u8Int, fIsBpInstr);
+    IEM_MC_ARG_CONST(uint8_t,   u8Int,  /*=*/ X86_XCPT_OF, 0);
+    IEM_MC_ARG_CONST(IEMINT,    enmInt, /*=*/ IEMINT_INTO, 1);
+    IEM_MC_CALL_CIMPL_2(iemCImpl_int, u8Int, enmInt);
     IEM_MC_END();
     return VINF_SUCCESS;
@@ -10590,6 +10590,5 @@
     IEMOP_HLP_MIN_386(); /** @todo does not generate #UD on 286, or so they say... */
     /** @todo testcase! */
-    IEMOP_HLP_SVM_CTRL_INTERCEPT(pVCpu, SVM_CTRL_INTERCEPT_ICEBP, SVM_EXIT_ICEBP, 0, 0);
-    return IEM_MC_DEFER_TO_CIMPL_2(iemCImpl_int, X86_XCPT_DB, false /*fIsBpInstr*/);
+    return IEM_MC_DEFER_TO_CIMPL_2(iemCImpl_int, X86_XCPT_DB, IEMINT_INT1);
 }
 
Index: /trunk/src/VBox/VMM/include/IEMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 66685)
+++ /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 66686)
@@ -137,4 +137,21 @@
 } IEMBRANCH;
 AssertCompileSize(IEMBRANCH, 4);
+
+
+/**
+ * INT instruction types.
+ */
+typedef enum IEMINT
+{
+    /** INT n instruction (opcode 0xcd imm). */
+    IEMINT_INTN  = 0,
+    /** Single byte INT3 instruction (opcode 0xcc). */
+    IEMINT_INT3  = IEM_XCPT_FLAGS_BP_INSTR,
+    /** Single byte INTO instruction (opcode 0xce). */
+    IEMINT_INTO  = IEM_XCPT_FLAGS_OF_INSTR,
+    /** Single byte INT1 (ICEBP) instruction (opcode 0xf1). */
+    IEMINT_INT1 = IEM_XCPT_FLAGS_ICEBP_INSTR
+} IEMINT;
+AssertCompileSize(IEMINT, 4);
 
 
