Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 66700)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 66701)
@@ -5808,4 +5808,54 @@
 
 /**
+ * Gets the IEM exception flags for the specified vector and IDT vectoring /
+ * VM-exit interruption info type.
+ *
+ * @returns The IEM exception flags.
+ * @param   uVector         The event vector.
+ * @param   uVmxVectorType  The VMX event type.
+ */
+static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxVectorType)
+{
+    uint32_t fIemXcptFlags;
+    switch (uVmxVectorType)
+    {
+        case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
+        case VMX_IDT_VECTORING_INFO_TYPE_NMI:
+            fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
+            break;
+
+        case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
+            fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
+            break;
+
+        case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
+            fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
+            break;
+
+        case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
+        {
+            fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
+            if (uVector == X86_XCPT_BP)
+                fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
+            else if (uVector == X86_XCPT_OF)
+                fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
+            else
+            {
+                fIemXcptFlags = 0;
+                AssertMsgFailed(("Unexpected vector for software int. uVector=%#x", uVector));
+            }
+            break;
+        }
+
+        default:
+            fIemXcptFlags = 0;
+            AssertMsgFailed(("Unexpected vector type! uVmxVectorType=%#x uVector=%#x", uVmxVectorType, uVector));
+            break;
+    }
+    return fIemXcptFlags;
+}
+
+
+/**
  * Handle a condition that occurred while delivering an event through the guest
  * IDT.
@@ -5838,5 +5888,149 @@
         uint32_t uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
         uint32_t uIdtVector     = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
-
+#if 1
+        /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
+        IEMXCPTRAISE     enmRaise;
+        IEMXCPTRAISEINFO fRaiseInfo;
+        if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
+        {
+            uint32_t const uExitVectorType  = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uExitIntInfo);
+            uint32_t const fIdtVectorFlags  = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
+            uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
+            AssertMsg(   uExitVectorType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
+                      || uExitVectorType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI,
+                      ("hmR0VmxCheckExitDueToEventDelivery: Unexpected VM-exit interruption info. type %#x!\n", uExitVectorType));
+            enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector,
+                                                &fRaiseInfo);
+        }
+        else
+        {
+            /*
+             * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
+             * interruption-information will not be valid as it's not an exception and we end up here.
+             *
+             * If the event was an external interrupt or hardare exception (incl. NMI) it is sufficient to
+             * reflect this event to the guest after handling the VM-exit.
+             *
+             * If the event was a software interrupt (generated with INT n) or a software exception (generated
+             * by INT3/INTO) or a privileged software exception (generated by INT1), we can handle the VM-exit
+             * and continue guest execution which will re-execute the instruction rather than re-injecting the
+             * event, as that can cause premature trips to ring-3 before injection and involve TRPM which
+             * currently has no way of storing that the exceptions were caused by these special instructions.
+             */
+            if (   uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
+                || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
+                || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT)
+                enmRaise = IEMXCPTRAISE_PREV_EVENT;
+            else
+                enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
+            fRaiseInfo = IEMXCPTRAISEINFO_NONE;
+        }
+
+        /*
+         * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
+         * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
+         * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
+         * subsequent VM-entry would fail.
+         *
+         * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
+         */
+        if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
+            && uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
+            && (   enmRaise   == IEMXCPTRAISE_PREV_EVENT
+                || fRaiseInfo == IEMXCPTRAISEINFO_NMI_PF)
+            && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
+        {
+            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
+        }
+
+        switch (enmRaise)
+        {
+            case IEMXCPTRAISE_CURRENT_XCPT:
+            {
+                /*
+                 * Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF().
+                 */
+                if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
+                    pVmxTransient->fVectoringPF = true;
+
+                /*
+                 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
+                 * second #PF as a guest #PF (and not a nested #PF) and needs to be converted into a #DF.
+                 */
+                if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
+                    pVmxTransient->fVectoringDoublePF = true;
+
+                Assert(rcStrict == VINF_SUCCESS);
+                break;
+            }
+
+            case IEMXCPTRAISE_PREV_EVENT:
+            {
+                /*
+                 * Re-raise the previous (first) exception/interrupt as delivery caused a premature VM-exit.
+                 */
+                Assert(   uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
+                       && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
+                       && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
+
+                uint32_t u32ErrCode;
+                if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
+                {
+                    rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
+                    AssertRCReturn(rc2, rc2);
+                    u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
+                }
+                else
+                    u32ErrCode = 0;
+
+                /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
+                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
+                hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
+                                       0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
+
+                Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
+                      pVCpu->hm.s.Event.u32ErrCode));
+                Assert(rcStrict == VINF_SUCCESS);
+                break;
+            }
+
+            case IEMXCPTRAISE_DOUBLE_FAULT:
+            {
+                STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
+                hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
+
+                Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
+                      pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
+                rcStrict = VINF_HM_DOUBLE_FAULT;
+                break;
+            }
+
+            case IEMXCPTRAISE_TRIPLE_FAULT:
+            {
+                Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
+                      uExitVector));
+                rcStrict = VINF_EM_RESET;
+                break;
+            }
+
+            case IEMXCPTRAISE_CPU_HANG:
+            {
+                Log4(("IDT: vcpu[%RU32] Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", pVCpu->idCpu, fRaiseInfo));
+                rcStrict = VERR_EM_GUEST_CPU_HANG;
+                break;
+            }
+
+            case IEMXCPTRAISE_REEXEC_INSTR:
+                Assert(rcStrict == VINF_SUCCESS);
+                break;
+
+            default:
+            {
+                AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
+                rcStrict = VERR_VMX_IPE_2;
+                break;
+            }
+        }
+#else
         typedef enum
         {
@@ -5983,4 +6177,5 @@
                 break;
         }
+#endif
     }
     else if (   VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo)
