Index: /trunk/include/VBox/vmm/trpm.h
===================================================================
--- /trunk/include/VBox/vmm/trpm.h	(revision 45530)
+++ /trunk/include/VBox/vmm/trpm.h	(revision 45531)
@@ -73,11 +73,14 @@
 VMMDECL(RTGCUINT)   TRPMGetErrorCode(PVMCPU pVCpu);
 VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu);
+VMMDECL(uint8_t)    TRPMGetInstrLength(PVMCPU pVCpu);
 VMMDECL(int)        TRPMResetTrap(PVMCPU pVCpu);
 VMMDECL(int)        TRPMAssertTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType);
+VMMDECL(int)        TRPMAssertXcptPF(PVMCPU pVCpu, RTGCUINTPTR uCR2, RTGCUINT uErrorCode);
 VMMDECL(void)       TRPMSetErrorCode(PVMCPU pVCpu, RTGCUINT uErrorCode);
 VMMDECL(void)       TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2);
+VMMDECL(void)       TRPMSetInstrLength(PVMCPU pVCpu, uint8_t cbInstr);
 VMMDECL(bool)       TRPMIsSoftwareInterrupt(PVMCPU pVCpu);
 VMMDECL(bool)       TRPMHasTrap(PVMCPU pVCpu);
-VMMDECL(int)        TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType, PRTGCUINT puErrorCode, PRTGCUINTPTR puCR2);
+VMMDECL(int)        TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType, PRTGCUINT puErrorCode, PRTGCUINTPTR puCR2, uint8_t *pu8InstrLen);
 VMMDECL(void)       TRPMSaveTrap(PVMCPU pVCpu);
 VMMDECL(void)       TRPMRestoreTrap(PVMCPU pVCpu);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 45531)
@@ -7565,5 +7565,5 @@
         RTGCUINT    uErrCode;
         RTGCPTR     uCr2;
-        int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2); AssertRC(rc2);
+        int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrCode, &uCr2, NULL /* pu8InstLen */); AssertRC(rc2);
         IEMInjectTrap(pVCpu, u8TrapNo, enmType, (uint16_t)uErrCode, uCr2);
         if (!IEM_VERIFICATION_ENABLED(pIemCpu))
Index: /trunk/src/VBox/VMM/VMMAll/TRPMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/TRPMAll.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMAll/TRPMAll.cpp	(revision 45531)
@@ -51,5 +51,5 @@
  * @param   pEnmType                Where to store the trap type
  */
-VMMDECL(int)  TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *pEnmType)
+VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *pEnmType)
 {
     /*
@@ -78,5 +78,5 @@
  * @param   pVCpu                   Pointer to the VMCPU.
  */
-VMMDECL(uint8_t)  TRPMGetTrapNo(PVMCPU pVCpu)
+VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu)
 {
     AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
@@ -94,5 +94,5 @@
  * @param   pVCpu                   Pointer to the VMCPU.
  */
-VMMDECL(RTGCUINT)  TRPMGetErrorCode(PVMCPU pVCpu)
+VMMDECL(RTGCUINT) TRPMGetErrorCode(PVMCPU pVCpu)
 {
     AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
@@ -100,11 +100,11 @@
     switch (pVCpu->trpm.s.uActiveVector)
     {
-        case 0x0a:
-        case 0x0b:
-        case 0x0c:
-        case 0x0d:
-        case 0x0e:
-        case 0x11:
-        case 0x08:
+        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:
@@ -132,4 +132,22 @@
     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                   Pointer to the VMCPU.
+ */
+VMMDECL(uint8_t) TRPMGetInstrLength(PVMCPU pVCpu)
+{
+    AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
+    return pVCpu->trpm.s.cbInstr;
+}
+
 
 
@@ -173,5 +191,5 @@
  * @param   enmType             Trap type.
  */
-VMMDECL(int)  TRPMAssertTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType)
+VMMDECL(int) TRPMAssertTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType)
 {
     Log2(("TRPMAssertTrap: u8TrapNo=%02x type=%d\n", u8TrapNo, enmType));
@@ -190,4 +208,38 @@
     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               Pointer to the VMCPU.
+ * @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;
 }
@@ -204,5 +256,5 @@
  * @param   uErrorCode          The new error code.
  */
-VMMDECL(void)  TRPMSetErrorCode(PVMCPU pVCpu, RTGCUINT uErrorCode)
+VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, RTGCUINT uErrorCode)
 {
     Log2(("TRPMSetErrorCode: uErrorCode=%RGv\n", uErrorCode)); /** @todo RTGCUINT mess! */
@@ -227,6 +279,6 @@
 
 /**
- * Sets the error code of the current trap.
- * (This function is for use in trap handlers and such.)
+ * 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
@@ -236,10 +288,33 @@
  * @param   uCR2                The new fault address (cr2 register).
  */
-VMMDECL(void)  TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2)
+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 == 0xe, ("Not trap 0e!\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               Pointer to the VMCPU.
+ * @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;
 }
 
@@ -269,5 +344,5 @@
  * @param   pVCpu               Pointer to the VMCPU.
  */
-VMMDECL(bool)  TRPMHasTrap(PVMCPU pVCpu)
+VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu)
 {
     return pVCpu->trpm.s.uActiveVector != ~0U;
@@ -286,6 +361,9 @@
  *                                  ~0U is stored if the trap has no error code.
  * @param   puCR2                   Where to store the CR2 associated with a trap 0E.
- */
-VMMDECL(int)  TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *pEnmType, PRTGCUINT puErrorCode, PRTGCUINTPTR puCR2)
+ * @param   pu8InstrLen             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 *pu8InstrLen)
 {
     /*
@@ -303,5 +381,6 @@
     if (puCR2)
         *puCR2          = pVCpu->trpm.s.uActiveCR2;
-
+    if (pu8InstrLen)
+        *pu8InstrLen    = pVCpu->trpm.s.cbInstr;
     return VINF_SUCCESS;
 }
@@ -323,4 +402,5 @@
     pVCpu->trpm.s.uSavedErrorCode     = pVCpu->trpm.s.uActiveErrorCode;
     pVCpu->trpm.s.uSavedCR2           = pVCpu->trpm.s.uActiveCR2;
+    pVCpu->trpm.s.cbSavedInstr        = pVCpu->trpm.s.cbInstr;
 }
 
@@ -339,4 +419,5 @@
     pVCpu->trpm.s.uActiveErrorCode    = pVCpu->trpm.s.uSavedErrorCode;
     pVCpu->trpm.s.uActiveCR2          = pVCpu->trpm.s.uSavedCR2;
+    pVCpu->trpm.s.cbInstr             = pVCpu->trpm.s.cbSavedInstr;
 }
 
@@ -788,4 +869,5 @@
     pVCpu->trpm.s.uActiveErrorCode         = 0xdeadbeef;
     pVCpu->trpm.s.uActiveCR2               = 0xdeadface;
+    pVCpu->trpm.s.cbInstr                  = UINT8_MAX;
     return VINF_EM_RAW_GUEST_TRAP;
 }
@@ -815,4 +897,5 @@
     pVCpu->trpm.s.uActiveErrorCode         = uErr;
     pVCpu->trpm.s.uActiveCR2               = 0xdeadface;
+    pVCpu->trpm.s.cbInstr                  = UINT8_MAX;
     return VINF_EM_RAW_GUEST_TRAP;
 }
@@ -843,4 +926,5 @@
     pVCpu->trpm.s.uActiveErrorCode         = uErr;
     pVCpu->trpm.s.uActiveCR2               = uCR2;
+    pVCpu->trpm.s.cbInstr                  = UINT8_MAX;
     return VINF_EM_RAW_GUEST_TRAP;
 }
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 45531)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-2013 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -112,5 +112,5 @@
 #define VMX_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE  RT_BIT(5)
 
-/*
+/**
  * Exception bitmap mask for real-mode guests (real-on-v86). We need to intercept all exceptions manually (except #PF).
  * #NM is also handled spearetely, see hmR0VmxLoadGuestControlRegs(). #PF need not be intercepted even in real-mode if
@@ -125,5 +125,5 @@
                                    | RT_BIT(X86_XCPT_XF))
 
-/* Maximum VM-instruction error number. */
+/** Maximum VM-instruction error number. */
 #define VMX_INSTR_ERROR_MAX     28
 
@@ -206,5 +206,5 @@
 static void               hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr);
 static int                hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo,
-                                                 uint32_t cbInstr, uint32_t u32ErrCode);
+                                                 uint32_t cbInstr, uint32_t u32ErrCode, uint32_t *puIntrState);
 #if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
 static int                hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
@@ -269,5 +269,4 @@
 *   Global Variables                                                           *
 *******************************************************************************/
-/** @todo Move this to hm_vmx.h. */
 /**
  * VM-exit handler.
@@ -282,7 +281,10 @@
 typedef DECLCALLBACK(int) FNVMEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
 /** Pointer to VM-exit handler. */
-typedef FNVMEXITHANDLER *PFNVMEXITHANDLER;
-
-static const PFNVMEXITHANDLER s_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
+typedef FNVMEXITHANDLER *const PFNVMEXITHANDLER;
+
+/**
+ * VMX_EXIT dispatch table.
+ */
+static const PFNVMEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
 {
  /* 00  VMX_EXIT_XCPT_NMI                */  hmR0VmxExitXcptNmi,
@@ -348,5 +350,6 @@
 };
 
-static const char* const s_apszVmxInstrErrors[VMX_INSTR_ERROR_MAX + 1] =
+#ifdef VBOX_STRICT
+static const char* const g_apszVmxInstrErrors[VMX_INSTR_ERROR_MAX + 1] =
 {
     /*  0 */ "(Not Used)",
@@ -380,5 +383,5 @@
     /* 28 */ "Invalid operand to INVEPT/INVVPID."
 };
-
+#endif
 
 /**
@@ -845,8 +848,8 @@
 {
     /* Setup the main VM exit handlers. */
-    AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(s_apfnVMExitHandlers));
-#ifdef DEBUG
-    for (unsigned i = 0; i < RT_ELEMENTS(s_apfnVMExitHandlers); i++)
-        Assert(s_apfnVMExitHandlers[i]);
+    AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
+#ifdef VBOX_STRICT
+    for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
+        Assert(g_apfnVMExitHandlers[i]);
 #endif
     return VINF_SUCCESS;
@@ -2475,8 +2478,7 @@
 
 /**
- * Loads the guest's interruptibility-state ("interrupt shadow" as AMD calls it)
- * into the guest-state area in the VMCS.
- *
- * @param   pVM         Pointer to the VM.
+ * Gets the guest's interruptibility-state ("interrupt shadow" as AMD calls it).
+ *
+ * @returns
  * @param   pVCpu       Pointer to the VMCPU.
  * @param   pMixedCtx   Pointer to the guest-CPU context. The data may be
@@ -2485,6 +2487,7 @@
  *
  * @remarks No-long-jump zone!!!
- */
-DECLINLINE(void) hmR0VmxLoadGuestIntrState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+ * @remarks Has side-effects with VMCPU_FF_INHIBIT_INTERRUPTS force-flag.
+ */
+DECLINLINE(uint32_t) hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
 {
     /*
@@ -2496,6 +2499,6 @@
     {
         /* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
-        AssertMsg((pVCpu->hm.s.vmx.fUpdatedGuestState & (VMX_UPDATED_GUEST_RIP | VMX_UPDATED_GUEST_RFLAGS)),
-                  ("%#x\n", pVCpu->hm.s.vmx.fUpdatedGuestState));
+        AssertMsg((pVCpu->hm.s.vmx.fUpdatedGuestState & (VMX_UPDATED_GUEST_RIP | VMX_UPDATED_GUEST_RFLAGS))
+                   == (VMX_UPDATED_GUEST_RIP | VMX_UPDATED_GUEST_RFLAGS), ("%#x\n", pVCpu->hm.s.vmx.fUpdatedGuestState));
         if (pMixedCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
         {
@@ -2503,5 +2506,4 @@
              * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
              * VT-x the flag's condition to be cleared is met and thus the cleared state is correct.
-             * hmR0VmxInjectPendingInterrupt() relies on us clearing this flag here.
              */
             VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
@@ -2512,9 +2514,23 @@
             uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS;
     }
-
-    Assert(!(uIntrState & 0xfffffff0));                             /* Bits 31:4 MBZ. */
+    return uIntrState;
+}
+
+
+/**
+ * Loads the guest's interruptibility-state into the guest-state area in the
+ * VMCS.
+ *
+ * @returns VBox status code.
+ * @param pVCpu         Pointer to the VMCPU.
+ * @param uIntrState    The interruptibility-state to set.
+ */
+DECLINLINE(int) hmR0VmxLoadGuestIntrState(PVMCPU pVCpu, uint32_t uIntrState)
+{
+    AssertMsg(!(uIntrState & 0xfffffff0), ("%#x\n", uIntrState));   /* Bits 31:4 MBZ. */
     Assert((uIntrState & 0x3) != 0x3);                              /* Block-by-STI and MOV SS cannot be simultaneously set. */
     int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, uIntrState);
-    AssertRC(rc);
+    AssertRCReturn(rc, rc);
+    return rc;
 }
 
@@ -2996,5 +3012,5 @@
         return VINF_SUCCESS;
 
-#ifdef DEBUG
+#ifdef VBOX_STRICT
     /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
     if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_DEBUG)
@@ -3086,7 +3102,7 @@
 
 
-#ifdef DEBUG
-/**
- * Debug function to validate segment registers.
+#ifdef VBOX_STRICT
+/**
+ * Strict function to validate segment registers.
  */
 static void hmR0VmxValidateSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
@@ -3247,5 +3263,5 @@
     }
 }
-#endif /* DEBUG */
+#endif /* VBOX_STRICT */
 
 
@@ -3314,5 +3330,4 @@
  *
  * @remarks No-long-jump zone!!!
- * @remarks Requires RFLAGS (for debug assertions).
  */
 DECLINLINE(int) hmR0VmxLoadGuestSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
@@ -3370,5 +3385,5 @@
         AssertRCReturn(rc, rc);
 
-#ifdef DEBUG
+#ifdef VBOX_STRICT
         hmR0VmxValidateSegmentRegs(pVM, pVCpu, pCtx);
 #endif
@@ -3785,5 +3800,5 @@
                 Log(("InstrError         %#x\n", pVCpu->hm.s.vmx.lasterror.u32InstrError));
                 if (pVCpu->hm.s.vmx.lasterror.u32InstrError <= VMX_INSTR_ERROR_MAX)
-                    Log(("InstrError Desc.  \"%s\"\n", s_apszVmxInstrErrors[pVCpu->hm.s.vmx.lasterror.u32InstrError]));
+                    Log(("InstrError Desc.  \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.lasterror.u32InstrError]));
                 else
                     Log(("InstrError Desc.    Range exceeded %u\n", VMX_INSTR_ERROR_MAX));
@@ -4166,12 +4181,12 @@
 #endif
 
-#ifdef DEBUG
-    pCache->TestIn.HCPhysCpuPage= 0;
-    pCache->TestIn.HCPhysVmcs   = 0;
-    pCache->TestIn.pCache       = 0;
-    pCache->TestOut.HCPhysVmcs  = 0;
-    pCache->TestOut.pCache      = 0;
-    pCache->TestOut.pCtx        = 0;
-    pCache->TestOut.eflags      = 0;
+#ifdef VBOX_STRICT
+    pCache->TestIn.HCPhysCpuPage = 0;
+    pCache->TestIn.HCPhysVmcs    = 0;
+    pCache->TestIn.pCache        = 0;
+    pCache->TestOut.HCPhysVmcs   = 0;
+    pCache->TestOut.pCache       = 0;
+    pCache->TestOut.pCtx         = 0;
+    pCache->TestOut.eflags       = 0;
 #endif
 
@@ -4195,15 +4210,15 @@
 #endif
 
-#ifdef DEBUG
-    AssertMsg(pCache->TestIn.HCPhysCpuPage== HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
-    AssertMsg(pCache->TestIn.HCPhysVmcs   == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
-                                                                              pVCpu->hm.s.vmx.HCPhysVmcs));
-    AssertMsg(pCache->TestIn.HCPhysVmcs   == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
-                                                                          pCache->TestOut.HCPhysVmcs));
-    AssertMsg(pCache->TestIn.pCache       == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
-                                                                      pCache->TestOut.pCache));
-    AssertMsg(pCache->TestIn.pCache       == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
+#ifdef VBOX_STRICT
+    AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
+    AssertMsg(pCache->TestIn.HCPhysVmcs    == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
+                                                                               pVCpu->hm.s.vmx.HCPhysVmcs));
+    AssertMsg(pCache->TestIn.HCPhysVmcs    == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
+                                                                           pCache->TestOut.HCPhysVmcs));
+    AssertMsg(pCache->TestIn.pCache        == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
+                                                                       pCache->TestOut.pCache));
+    AssertMsg(pCache->TestIn.pCache        == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
               ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
-    AssertMsg(pCache->TestIn.pCtx         == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
+    AssertMsg(pCache->TestIn.pCtx          == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
                                                                     pCache->TestOut.pCtx));
     Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
@@ -4639,18 +4654,22 @@
  * Sets an event as a pending event to be injected into the guest.
  *
- * @param   pVCpu           Pointer to the VMCPU.
- * @param   u32IntrInfo     The VM-entry interruption-information field.
- * @param   cbInstr         The VM-entry instruction length in bytes (for software
- *                          interrupts, exceptions and privileged software
- *                          exceptions).
- * @param   u32ErrCode      The VM-entry exception error code.
- */
-DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntrInfo, uint32_t cbInstr, uint32_t u32ErrCode)
+ * @param   pVCpu               Pointer to the VMCPU.
+ * @param   u32IntrInfo         The VM-entry interruption-information field.
+ * @param   cbInstr             The VM-entry instruction length in bytes (for software
+ *                              interrupts, exceptions and privileged software
+ *                              exceptions).
+ * @param   u32ErrCode          The VM-entry exception error code.
+ * @param   GCPtrFaultAddress   The fault-address (CR2) in case it's a
+ *                              page-fault.
+ */
+DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntrInfo, uint32_t cbInstr, uint32_t u32ErrCode,
+                                        RTGCUINTPTR GCPtrFaultAddress)
 {
     Assert(!pVCpu->hm.s.Event.fPending);
-    pVCpu->hm.s.Event.fPending    = true;
-    pVCpu->hm.s.Event.u64IntrInfo = u32IntrInfo;
-    pVCpu->hm.s.Event.u32ErrCode  = u32ErrCode;
-    pVCpu->hm.s.Event.cbInstr     = cbInstr;
+    pVCpu->hm.s.Event.fPending          = true;
+    pVCpu->hm.s.Event.u64IntrInfo       = u32IntrInfo;
+    pVCpu->hm.s.Event.u32ErrCode        = u32ErrCode;
+    pVCpu->hm.s.Event.cbInstr           = cbInstr;
+    pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
 }
 
@@ -4750,5 +4769,5 @@
                 }
                 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INTR_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
-                                       0 /* cbInstr */,  u32ErrCode);
+                                       0 /* cbInstr */,  u32ErrCode, 0 /* GCPtrFaultAddress */);
                 rc = VINF_SUCCESS;
                 Log(("Pending event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntrInfo, pVCpu->hm.s.Event.u32ErrCode));
@@ -4762,5 +4781,5 @@
                 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
                 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
-                hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */);
+                hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
                 rc = VINF_VMX_DOUBLE_FAULT;
                 Log(("Pending #DF %#RX64 uIdt=%#x uExit=%#x\n", pVCpu->hm.s.Event.u64IntrInfo, uIdtVector, uExitVector));
@@ -5539,8 +5558,81 @@
 
 /**
+ * Converts any TRPM trap into a pending VMX event.
+ *
+ * @param   pVCpu           Pointer to the VMCPU.
+ */
+static void hmR0VmxUpdatePendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+{
+    if (!TRPMHasTrap(pVCpu))
+        return;
+
+    uint8_t     uVector;
+    TRPMEVENT   enmTrpmEvent;
+    RTGCUINT    uErrCode;
+    RTGCUINTPTR GCPtrFaultAddress;
+    uint8_t     cbInstr;
+
+    int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
+    AssertRC(rc);
+
+    /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntrInfo. */
+    uint32_t u32IntrInfo = uVector | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
+    uint32_t u32ErrCode  = uErrCode;
+    if (enmTrpmEvent == TRPM_TRAP)
+    {
+        switch (uVector)
+        {
+            case X86_XCPT_BP:
+            case X86_XCPT_OF:
+            {
+                /* These exceptions must be delivered as software exceptions. They have no error codes associated with them. */
+                u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+                break;
+            }
+
+            case X86_XCPT_DF:
+            case X86_XCPT_TS:
+            case X86_XCPT_NP:
+            case X86_XCPT_SS:
+            case X86_XCPT_GP:
+            case X86_XCPT_PF:
+            case X86_XCPT_AC:
+                /* These exceptions must be delivered as hardware exceptions. They have error codes associated with
+                   them which VT-x/VMM pushes to the guest stack. */
+                u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
+                /* no break! */
+            default:
+            {
+                u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+                if (uVector == X86_XCPT_PF)
+                    pMixedCtx->cr2 = TRPMGetFaultAddress(pVCpu);
+                break;
+            }
+        }
+    }
+    else if (enmTrpmEvent == TRPM_HARDWARE_INT)
+    {
+        if (uVector != X86_XCPT_NMI)
+            u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+        else
+            u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+    }
+    else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
+        u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+    else
+        AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
+
+    rc = TRPMResetTrap(pVCpu);
+    Log(("Converted TRPM trap: u32IntrInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u u32ErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
+         u32IntrInfo, enmTrpmEvent, u32ErrCode, GCPtrFaultAddress));
+    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, u32ErrCode, GCPtrFaultAddress);
+}
+
+
+/**
  * Converts any pending VMX event into a TRPM trap. Typically used when leaving
  * VT-x to execute any instruction.
  *
- * @param   pvCpu               Pointer to the VMCPU.
+ * @param   pvCpu           Pointer to the VMCPU.
  */
 static void hmR0VmxUpdateTRPMTrap(PVMCPU pVCpu)
@@ -5554,9 +5646,5 @@
 
         /* If a trap was already pending, we did something wrong! */
-        Assert(TRPMQueryTrap(pVCpu, NULL, NULL) == VERR_TRPM_NO_ACTIVE_TRAP);
-
-        /* A page-fault exception during a page-fault would become a double-fault. */
-        AssertMsg(uVectorType != VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT || uVector != X86_XCPT_PF,
-                  ("%#RX64 uVectorType=%#x uVector=%#x\n", pVCpu->hm.s.Event.u64IntrInfo, uVectorType, uVector));
+        Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
 
         TRPMEVENT enmTrapType;
@@ -5580,10 +5668,26 @@
                 break;
         }
+
         Log(("Converting pending HM event to TRPM trap uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
+
         int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
         AssertRC(rc);
         if (fErrorCodeValid)
             TRPMSetErrorCode(pVCpu, uErrorCode);
-        AssertRC(rc);
+
+        /* A page-fault exception during a page-fault would become a double-fault. */
+        if (   uVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
+            && uVector == X86_XCPT_PF)
+        {
+            TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
+        }
+        else if (   uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
+                 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT)
+        {
+            AssertMsg(   uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
+                      || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
+                      ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
+            TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
+        }
         pVCpu->hm.s.Event.fPending = false;
     }
@@ -5730,8 +5834,30 @@
 
 /**
- * Injects any pending TRPM trap into the VM by updating the VMCS.
- *
- * @returns VBox status code (informational status code included).
- * @param   pVM             Pointer to the VM.
+ * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
+ * cause a VM-exit as soon as the guest is in a state to receive interrupts.
+ *
+ * @returns VBox status code.
+ * @param pVCpu         Pointer to the VMCPU.
+ */
+DECLINLINE(void) hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu)
+{
+    if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INT_WINDOW_EXIT))
+    {
+        /* Enable interrupt-window exiting if it's not in effect already. */
+        if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INT_WINDOW_EXIT))
+        {
+            pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INT_WINDOW_EXIT;
+            int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC_CONTROLS, pVCpu->hm.s.vmx.u32ProcCtls);
+            AssertRC(rc);
+        }
+    } /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
+}
+
+
+/**
+ * Checks if there are any pending guest interrupts to be delivered and injects
+ * them into the VM by updating the VMCS.
+ *
+ * @returns VBox status code (informational status codes included).
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
@@ -5739,168 +5865,140 @@
  *                          before using them.
  */
-static int hmR0VmxInjectTRPMTrap(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
-{
-    if (!TRPMHasTrap(pVCpu))
-        return VINF_SUCCESS;
-
-    uint8_t   u8Vector     = 0;
-    TRPMEVENT enmTrpmEvent = TRPM_SOFTWARE_INT;
-    RTGCUINT  uErrCode     = 0;
-
-    int rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmTrpmEvent, &uErrCode, NULL /* puCr2 */);
-    rc    |= TRPMResetTrap(pVCpu);
-    AssertRCReturn(rc, rc);
-
-    /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntrInfo. */
-    uint32_t u32IntrInfo = u8Vector | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
-    if (enmTrpmEvent == TRPM_TRAP)
-    {
-        switch (u8Vector)
-        {
-            case X86_XCPT_BP:
-            case X86_XCPT_OF:
+static int hmR0VmxInjectEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+{
+    /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
+    uint32_t uIntrState  = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
+    const bool fBlockMovSS = (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
+    const bool fBlockSti   = (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
+
+    int rc = VINF_SUCCESS;
+    if (pVCpu->hm.s.Event.fPending)     /* First, inject any pending HM events. */
+    {
+        uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE((uint32_t)pVCpu->hm.s.Event.u64IntrInfo);
+        bool fInject = true;
+        if (uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
+        {
+            rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
+            AssertRCReturn(rc, rc);
+            const bool fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
+            if (   fBlockInt
+                || fBlockSti
+                || fBlockMovSS)
             {
-                /* These exceptions must be delivered as software exceptions. They have no error codes associated with them. */
-                u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
-                break;
+                fInject = false;
             }
-
-            case X86_XCPT_DF:
-            case X86_XCPT_TS:
-            case X86_XCPT_NP:
-            case X86_XCPT_SS:
-            case X86_XCPT_GP:
-            case X86_XCPT_PF:
-            case X86_XCPT_AC:
-                /* These exceptions must be delivered as hardware exceptions. They have error codes associated with
-                   them which VT-x/VMM pushes to the guest stack. */
-                u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
-                /* no break! */
-            default:
+        }
+        else if (   uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
+                 && (   fBlockMovSS
+                     || fBlockSti))
+        {
+            /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
+            fInject = false;
+        }
+
+        if (fInject)
+        {
+            Log(("Injecting pending event\n"));
+            rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntrInfo, pVCpu->hm.s.Event.cbInstr,
+                                        pVCpu->hm.s.Event.u32ErrCode, &uIntrState);
+            AssertRCReturn(rc, rc);
+            pVCpu->hm.s.Event.fPending = false;
+        }
+    }                                                           /** @todo SMI. SMIs take priority over NMIs. */
+    else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))    /* NMI. NMIs take priority over regular interrupts . */
+    {
+        /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
+        if (!fBlockMovSS && !fBlockSti)
+        {
+            Log(("Injecting NMI\n"));
+            RTGCUINTPTR uIntrInfo;
+            uIntrInfo  = X86_XCPT_NMI;
+            uIntrInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
+            uIntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+            rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, uIntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, &uIntrState);
+            AssertRCReturn(rc, rc);
+            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
+        }
+        else
+            hmR0VmxSetIntWindowExitVmcs(pVCpu);
+    }
+    else if (VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)))
+    {
+        /* Check if there are guest external interrupts (PIC/APIC) pending and inject them if the guest can receive them. */
+        rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
+        AssertRCReturn(rc, rc);
+        const bool fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
+        if (   !fBlockInt
+            && !fBlockSti
+            && !fBlockMovSS)
+        {
+            uint8_t u8Interrupt = 0;
+            rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
+            if (RT_SUCCESS(rc))
             {
-                u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
-                break;
+                Log(("Injecting interrupt u8Interrupt=%#x\n", u8Interrupt));
+                uint32_t u32IntrInfo = u8Interrupt | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
+                u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+                rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */,  0 /* u32ErrCode */, &uIntrState);
             }
-        }
-    }
-    else if (enmTrpmEvent == TRPM_HARDWARE_INT)
-        u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
-    else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
-        u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
-    else
-        AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
-
-    STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, uErrCode);
-}
-
-
-/**
- * Checks if there are any pending guest interrupts to be delivered and injects
- * them into the VM by updating the VMCS.
- *
- * @returns VBox status code (informational status codes included).
- * @param   pVM             Pointer to the VM.
+            else
+            {
+                /** @todo Does this actually happen? If not turn it into an assertion. */
+                Assert(!VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)));
+                STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
+                rc = VINF_SUCCESS;
+            }
+        }
+        else
+            hmR0VmxSetIntWindowExitVmcs(pVCpu);
+    }
+
+    /*
+     * There's no need to clear the entry-interruption information field here if we're not injecting anything.
+     * VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
+     */
+    hmR0VmxLoadGuestIntrState(pVCpu, uIntrState);
+    return rc;
+}
+
+
+/**
+ * Sets an invalid-opcode (#UD) exception as pending-for-injection into the VM.
+ *
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
  *                          out-of-sync. Make sure to update the required fields
  *                          before using them.
- *
- * @remarks Must be called after hmR0VmxLoadGuestIntrState().
- */
-static int hmR0VmxInjectPendingInterrupt(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
-{
-    /* First inject any pending HM interrupts. */
-    if (pVCpu->hm.s.Event.fPending)
-    {
-        Log(("Injecting pending event\n"));
-        int rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntrInfo, pVCpu->hm.s.Event.cbInstr,
-                                        pVCpu->hm.s.Event.u32ErrCode);
-        AssertRCReturn(rc, rc);
-        pVCpu->hm.s.Event.fPending = false;
-        return rc;
-    }
-
-    /** @todo SMI. SMIs take priority over NMIs. */
-
-    /* NMI. NMIs take priority over regular interrupts . */
-    if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI))
-    {
-        /* Construct an NMI interrupt and inject it into the VMCS. */
-        RTGCUINTPTR uIntrInfo;
-        uIntrInfo  = X86_XCPT_NMI;
-        uIntrInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
-        uIntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
-        Log(("Injecting NMI\n"));
-        int rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, uIntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */);
-        AssertRCReturn(rc, rc);
-        return rc;
-    }
-
-    /* We need the guests's RFLAGS for sure from this point on, make sure it is updated. */
-    int rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
-    AssertRCReturn(rc, rc);
-
-    /* If there isn't any active trap, check if we have pending interrupts and convert them to TRPM traps and deliver them. */
-    if (!TRPMHasTrap(pVCpu))
-    {
-        /* Check if there are guest external interrupts (PIC/APIC) pending. */
-        if (VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)))
-        {
-            /*
-             * If the guest can receive interrupts now (interrupts enabled and no interrupt inhibition is active) convert
-             * the PDM interrupt into a TRPM event and inject it.
-             */
-            if (   (pMixedCtx->eflags.u32 & X86_EFL_IF)
-                && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
-            {
-                uint8_t u8Interrupt = 0;
-                rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
-                if (RT_SUCCESS(rc))
-                {
-                    Log(("PDMGetInterrupt: u8Interrupt=%#x\n", u8Interrupt));
-                    /* Convert pending interrupt from PIC/APIC into TRPM and handle it below. */
-                    rc = TRPMAssertTrap(pVCpu, u8Interrupt, TRPM_HARDWARE_INT);
-                    AssertRCReturn(rc, rc);
-                }
-                else
-                {
-                    /** @todo Does this actually happen? If not turn it into an assertion. */
-                    Assert(!VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)));
-                    STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
-                }
-            }
-            else if (   !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INT_WINDOW_EXIT)
-                     && (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INT_WINDOW_EXIT))
-            {
-                /* Instruct VT-x to cause an interrupt-window exit as soon as the guest is ready to receive interrupts again. */
-                pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INT_WINDOW_EXIT;
-                rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC_CONTROLS, pVCpu->hm.s.vmx.u32ProcCtls);
-                AssertRCReturn(rc, rc);
-            }
-            /* else we will deliver interrupts whenever the guest exits next and it's in a state to receive interrupts. */
-        }
-    }
-
-    /* If interrupts can be delivered, inject it into the VM. */
-    if (   (pMixedCtx->eflags.u32 & X86_EFL_IF)
-        && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
-        && TRPMHasTrap(pVCpu))
-    {
-        Log(("Injecting TRPM trap\n"));
-        rc = hmR0VmxInjectTRPMTrap(pVM, pVCpu, pMixedCtx);
-        Assert(!TRPMHasTrap(pVCpu));
-        AssertRCReturn(rc, rc);
-    }
-
-    /*
-     * There's no need to clear the entry-interruption information field here if we're not injecting anything. VT-x clears the
-     * valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
-     */
-    return rc;
-}
-
-/**
- * Sets an invalid-opcode (#UD) exception as pending-for-injection into the VM.
+ */
+DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+{
+    /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntrInfo. */
+    uint32_t u32IntrInfo = X86_XCPT_UD | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
+    STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
+    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
+}
+
+
+/**
+ * Sets a double-fault (#DF) exception as pending-for-injection into the VM.
+ *
+ * @param   pVCpu           Pointer to the VMCPU.
+ * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
+ *                          out-of-sync. Make sure to update the required fields
+ *                          before using them.
+ */
+DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+{
+    /* Inject the double-fault. */
+    uint32_t u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
+    u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
+    u32IntrInfo         |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
+    STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
+    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo,  0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
+}
+
+
+/**
+ * Injects a double-fault (#DF) exception into the VM.
  *
  * @returns VBox status code (informational status code included).
@@ -5910,23 +6008,5 @@
  *                          before using them.
  */
-DECLINLINE(int) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
-{
-    /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntrInfo. */
-    uint32_t u32IntrInfo = X86_XCPT_UD | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
-    STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */);
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Sets a double-fault (#DF) exception as pending-for-injection into the VM.
- *
- * @param   pVCpu           Pointer to the VMCPU.
- * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
- *                          out-of-sync. Make sure to update the required fields
- *                          before using them.
- */
-DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+DECLINLINE(int) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t *puIntrState)
 {
     /* Inject the double-fault. */
@@ -5935,12 +6015,11 @@
     u32IntrInfo         |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
     STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo,  0 /* cbInstr */, 0 /* u32ErrCode */);
-}
-
-
-/**
- * Injects a double-fault (#DF) exception into the VM.
- *
- * @returns VBox status code (informational status code included).
+    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, puIntrState);
+}
+
+
+/**
+ * Sets a debug (#DB) exception as pending-for-injection into the VM.
+ *
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
@@ -5948,25 +6027,5 @@
  *                          before using them.
  */
-DECLINLINE(int) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
-{
-    /* Inject the double-fault. */
-    uint32_t u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
-    u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
-    u32IntrInfo         |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
-    STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo,  0 /* cbInstr */, 0 /* u32ErrCode */);
-}
-
-
-/**
- * Sets a debug (#DB) exception as pending-for-injection into the VM.
- *
- * @returns VBox status code (informational status code included).
- * @param   pVCpu           Pointer to the VMCPU.
- * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
- *                          out-of-sync. Make sure to update the required fields
- *                          before using them.
- */
-DECLINLINE(int) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
+DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
 {
     /* Inject the debug-exception. */
@@ -5974,6 +6033,5 @@
     u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
     STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */);
-    return VINF_SUCCESS;
+    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
 }
 
@@ -5982,5 +6040,4 @@
  * Sets an overflow (#OF) exception as pending-for-injection into the VM.
  *
- * @returns VBox status code (informational status code included).
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
@@ -5990,5 +6047,5 @@
  *                          stack.
  */
-DECLINLINE(int) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
+DECLINLINE(void) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
 {
     /* Inject the overflow exception. */
@@ -5996,6 +6053,5 @@
     u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
     STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, 0 /* u32ErrCode */);
-    return VINF_SUCCESS;
+    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
 }
 
@@ -6011,5 +6067,6 @@
  * @param   u32ErrorCode    The error code associated with the #GP.
  */
-DECLINLINE(int) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode)
+DECLINLINE(int) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
+                                    uint32_t *puIntrState)
 {
     /* Inject the general-protection fault. */
@@ -6019,12 +6076,11 @@
         u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
     STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, u32ErrorCode);
-}
-
-
-/**
- * Injects a software interrupt (INTn) into the VM.
- *
- * @returns VBox status code (informational status code included).
+    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, u32ErrorCode, puIntrState);
+}
+
+
+/**
+ * Sets a software interrupt (INTn) as pending-for-injection into the VM.
+ *
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pMixedCtx       Pointer to the guest-CPU context. The data may be
@@ -6035,5 +6091,5 @@
  *                          stack.
  */
-DECLINLINE(int) hmR0VmxInjectIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
+DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
 {
     /* Inject the INTn. */
@@ -6041,6 +6097,5 @@
     u32IntrInfo         |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
     STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
-    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, 0 /* u32ErrCode */);
-    return VINF_SUCCESS;
+    hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
 }
 
@@ -6091,11 +6146,22 @@
  *
  * @remarks No-long-jump zone!!!
+ * @remarks Requires CR0!
  */
 static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo, uint32_t cbInstr,
-                                  uint32_t u32ErrCode)
+                                  uint32_t u32ErrCode, uint32_t *puIntrState)
 {
     /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
     AssertMsg(u64IntrInfo >> 32 == 0, ("%#RX64\n", u64IntrInfo));
+    Assert(puIntrState);
     uint32_t u32IntrInfo = (uint32_t)u64IntrInfo;
+
+    const uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntrInfo);
+    const uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntrInfo);
+
+    /* Cannot inject an NMI when block-by-MOV SS is in effect. */
+    Assert(   uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
+           || !((*puIntrState) & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS));
+
+    STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
 
     /* We require CR0 to check if the guest is in real-mode. */
@@ -6103,5 +6169,4 @@
     AssertRCReturn(rc, rc);
 
-    const uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntrInfo);
     STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
 
@@ -6135,10 +6200,10 @@
                 {
                     /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
-                    return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx);
+                    return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, puIntrState);
                 }
 
                 /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
                 /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
-                return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */);
+                return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */, puIntrState);
             }
 
@@ -6179,4 +6244,14 @@
                                                 | HM_CHANGED_GUEST_RFLAGS
                                                 | HM_CHANGED_GUEST_RSP;
+
+                /* We're clearing interrupts, which means no block-by-STI interrupt-inhibition. */
+                if (*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
+                {
+                    Assert(   uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
+                           && uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
+                    Log(("Clearing inhibition due to STI.\n"));
+                    *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
+                }
+                Log(("Injecting u32IntrInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntrInfo, u32ErrCode, cbInstr));
             }
             Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET);
@@ -6199,5 +6274,4 @@
     Assert(!(u32IntrInfo & 0x7ffff000));                                /* Bits 30:12 MBZ. */
     Log(("Injecting u32IntrInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntrInfo, u32ErrCode, cbInstr));
-
     rc  = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntrInfo);
     if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntrInfo))
@@ -6205,4 +6279,6 @@
     rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
     AssertRCReturn(rc, rc);
+
+    Assert(uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT);
     return rc;
 }
@@ -6466,6 +6542,5 @@
      * This is why this is done after all possible exits-to-ring-3 paths in this code.
      */
-    hmR0VmxLoadGuestIntrState(pVM, pVCpu, pMixedCtx);
-    rc = hmR0VmxInjectPendingInterrupt(pVM, pVCpu, pMixedCtx);
+    rc = hmR0VmxInjectEvent(pVCpu, pMixedCtx);
     AssertRCReturn(rc, rc);
     return rc;
@@ -6662,4 +6737,5 @@
     int          rc     = VERR_INTERNAL_ERROR_5;
     uint32_t     cLoops = 0;
+    hmR0VmxUpdatePendingEvent(pVCpu, pCtx);
 
     for (;; cLoops++)
@@ -6704,5 +6780,5 @@
         STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
         AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
-        rc = (*s_apfnVMExitHandlers[VmxTransient.uExitReason])(pVCpu, pCtx, &VmxTransient);
+        rc = (*g_apfnVMExitHandlers[VmxTransient.uExitReason])(pVCpu, pCtx, &VmxTransient);
         STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
         if (rc != VINF_SUCCESS)
@@ -6875,4 +6951,6 @@
 {
     VMX_VALIDATE_EXIT_HANDLER_PARAMS();
+    STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
+
     int rc = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
     AssertRCReturn(rc, rc);
@@ -6883,12 +6961,21 @@
 
     if (uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
+    {
+        STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
         return VINF_EM_RAW_INTERRUPT;
+    }
 
     /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
     rc = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
     if (RT_UNLIKELY(rc == VINF_VMX_DOUBLE_FAULT))
+    {
+        STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
         return VINF_SUCCESS;
+    }
     else if (RT_UNLIKELY(rc == VINF_EM_RESET))
+    {
+        STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
         return rc;
+    }
 
     uint32_t uExitIntrInfo = pVmxTransient->uExitIntrInfo;
@@ -6935,5 +7022,6 @@
                         AssertRCReturn(rc, rc);
                         hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(uExitIntrInfo),
-                                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode,
+                                               0 /* GCPtrFaultAddress */);
                         AssertRCReturn(rc, rc);
                     }
@@ -6957,4 +7045,5 @@
         }
     }
+    STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
     return rc;
 }
@@ -6974,5 +7063,5 @@
     AssertRCReturn(rc, rc);
 
-    /* Deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectPendingInterrupt() and resume guest execution. */
+    /* Deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectEvent() and resume guest execution. */
     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
     return VINF_SUCCESS;
@@ -7562,5 +7651,5 @@
         }
     }
-#ifdef DEBUG
+#ifdef VBOX_STRICT
     else
     {
@@ -7637,5 +7726,5 @@
     /*
      * The TPR has already been updated, see hmR0VMXPostRunGuest(). RIP is also updated as part of the VM-exit by VT-x. Update
-     * the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectPendingInterrupt() and
+     * the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectEvent() and
      * resume guest execution.
      */
@@ -7927,6 +8016,5 @@
 
                         /* Set #DB to be injected into the VM and continue guest execution. */
-                        rc = hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
-                        AssertRCReturn(rc, rc);
+                        hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
                         break;
                     }
@@ -8257,7 +8345,5 @@
         uErrorCode |= X86_TRAP_PF_P;
 
-    TRPMAssertTrap(pVCpu, X86_XCPT_PF, TRPM_TRAP);
-    TRPMSetErrorCode(pVCpu, uErrorCode);
-    TRPMSetFaultAddress(pVCpu, GCPhys);
+    TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
 
     Log(("EPT violation %#x at %#RGv ErrorCode %#x CS:EIP=%04x:%#RX64\n", (uint32_t)pVmxTransient->uExitQualification, GCPhys,
@@ -8307,5 +8393,5 @@
     }
     hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                           pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                           pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
     return rc;
 }
@@ -8335,5 +8421,5 @@
 
         hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
     }
 
@@ -8386,5 +8472,5 @@
         AssertRCReturn(rc,rc);
         hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
         return rc;
     }
@@ -8426,5 +8512,5 @@
     AssertRCReturn(rc, rc);
     hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                           pVmxTransient->cbInstr, 0 /* error code */);
+                           pVmxTransient->cbInstr, 0 /* error code */, 0 /* GCPtrFaultAddress */);
     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
     return rc;
@@ -8454,5 +8540,5 @@
         Log(("#GP Gst: RIP %#RX64\n", pMixedCtx->rip));
         hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                               pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
         return rc;
 #else
@@ -8633,6 +8719,5 @@
             {
                 uint16_t uVector = pDis->Param1.uValue & 0xff;
-                rc = hmR0VmxInjectIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
-                AssertRCReturn(rc, rc);
+                hmR0VmxSetPendingIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
                 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
                 break;
@@ -8643,5 +8728,5 @@
                 if (pMixedCtx->eflags.Bits.u1OF)
                 {
-                    rc = hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
+                    hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
                     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
                 }
@@ -8683,5 +8768,5 @@
        hmR0VmxCheckExitDueToEventDelivery(). */
     hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                           pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                           pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
     return VINF_SUCCESS;
 }
@@ -8708,5 +8793,5 @@
             pMixedCtx->cr2 = pVmxTransient->uExitQualification;
             hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                                   pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode);
+                                   pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, pMixedCtx->cr2);
         }
         else
@@ -8753,10 +8838,8 @@
 #endif
 
-    TRPMAssertTrap(pVCpu, X86_XCPT_PF, TRPM_TRAP);
-    TRPMSetFaultAddress(pVCpu, pVmxTransient->uExitQualification);
-    TRPMSetErrorCode(pVCpu, pVmxTransient->uExitIntrErrorCode);
-
     rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
     AssertRCReturn(rc, rc);
+
+    TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntrErrorCode);
 
     /* Forward it to the trap handler first. */
@@ -8787,5 +8870,5 @@
             pMixedCtx->cr2 = pVmxTransient->uExitQualification;
             hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
-                                   pVmxTransient->cbInstr, uGstErrorCode);
+                                   pVmxTransient->cbInstr, uGstErrorCode, pMixedCtx->cr2);
         }
         else
Index: /trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp	(revision 45531)
@@ -675,5 +675,5 @@
     {
         uint8_t     u8Vector;
-        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, 0, 0);
+        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, NULL, NULL, NULL);
         AssertRC(rc);
     }
@@ -693,5 +693,5 @@
 
         /* If a new event is pending, then dispatch it now. */
-        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &u32ErrorCode, 0);
+        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &u32ErrorCode, NULL, NULL);
         AssertRC(rc);
         Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
Index: /trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp	(revision 45531)
@@ -1171,5 +1171,5 @@
     {
         uint8_t u8Vector;
-        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, 0, 0);
+        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, NULL, NULL, NULL);
         AssertRC(rc);
     }
@@ -1189,5 +1189,5 @@
          * If a new event is pending, dispatch it now.
          */
-        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &errCode, 0);
+        rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &errCode, NULL, NULL);
         AssertRC(rc);
         Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
Index: /trunk/src/VBox/VMM/VMMR3/EMRaw.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/EMRaw.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMR3/EMRaw.cpp	(revision 45531)
@@ -518,5 +518,5 @@
     RTGCUINT        uErrorCode;
     RTGCUINTPTR     uCR2;
-    int rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2);
+    int rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2, NULL /* pu8InstrLen */);
     if (RT_FAILURE(rc))
     {
@@ -754,5 +754,5 @@
     else
     {
-        rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2);
+        rc = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2, NULL /* pu8InstrLen */);
         if (RT_FAILURE(rc))
         {
Index: /trunk/src/VBox/VMM/VMMR3/HM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 45531)
@@ -67,5 +67,5 @@
     EXIT_REASON(VMX_EXIT_IO_SMI_IRQ         ,  5, "I/O system-management interrupt (SMI)."),
     EXIT_REASON(VMX_EXIT_SMI_IRQ            ,  6, "Other SMI."),
-    EXIT_REASON(VMX_EXIT_IRQ_WINDOW         ,  7, "Interrupt window."),
+    EXIT_REASON(VMX_EXIT_INT_WINDOW         ,  7, "Interrupt window."),
     EXIT_REASON_NIL(),
     EXIT_REASON(VMX_EXIT_TASK_SWITCH        ,  9, "Task switch."),
@@ -111,6 +111,6 @@
     EXIT_REASON(VMX_EXIT_EPT_MISCONFIG      , 49, "EPT misconfiguration. An attempt to access memory with a guest-physical address encountered a misconfigured EPT paging-structure entry."),
     EXIT_REASON(VMX_EXIT_INVEPT             , 50, "INVEPT. Guest software attempted to execute INVEPT."),
-    EXIT_REASON(VMX_EXIT_RDTSCP             , 51, "Guest software attempted to execute RDTSCP."),
-    EXIT_REASON(VMX_EXIT_PREEMPT_TIMER      , 52, "VMX-preemption timer expired. The preemption timer counted down to zero."),
+    EXIT_REASON(VMX_EXIT_RDTSCP             , 51, "RDTSCP. Guest software attempted to execute RDTSCP."),
+    EXIT_REASON(VMX_EXIT_PREEMPT_TIMER      , 52, "VMX-preemption timer expired."),
     EXIT_REASON(VMX_EXIT_INVVPID            , 53, "INVVPID. Guest software attempted to execute INVVPID."),
     EXIT_REASON(VMX_EXIT_WBINVD             , 54, "WBINVD. Guest software attempted to execute WBINVD."),
Index: /trunk/src/VBox/VMM/VMMR3/VMMGuruMeditation.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/VMMGuruMeditation.cpp	(revision 45530)
+++ /trunk/src/VBox/VMM/VMMR3/VMMGuruMeditation.cpp	(revision 45531)
@@ -300,11 +300,12 @@
             RTGCUINT        uErrorCode = 0xdeadface;
             RTGCUINTPTR     uCR2       = 0xdeadface;
-            int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2);
+            uint8_t         cbInstr    = UINT8_MAX;
+            int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2, &cbInstr);
             if (!HMIsEnabled(pVM))
             {
                 if (RT_SUCCESS(rc2))
                     pHlp->pfnPrintf(pHlp,
-                                    "!! TRAP=%02x ERRCD=%RGv CR2=%RGv EIP=%RX32 Type=%d\n",
-                                    u8TrapNo, uErrorCode, uCR2, uEIP, enmType);
+                                    "!! TRAP=%02x ERRCD=%RGv CR2=%RGv EIP=%RX32 Type=%d cbInstr=%02x\n",
+                                    u8TrapNo, uErrorCode, uCR2, uEIP, enmType, cbInstr);
                 else
                     pHlp->pfnPrintf(pHlp,
@@ -314,6 +315,6 @@
             else if (RT_SUCCESS(rc2))
                 pHlp->pfnPrintf(pHlp,
-                                "!! ACTIVE TRAP=%02x ERRCD=%RGv CR2=%RGv PC=%RGr Type=%d (Guest!)\n",
-                                u8TrapNo, uErrorCode, uCR2, CPUMGetGuestRIP(pVCpu), enmType);
+                                "!! ACTIVE TRAP=%02x ERRCD=%RGv CR2=%RGv PC=%RGr Type=%d cbInstr=%02x (Guest!)\n",
+                                u8TrapNo, uErrorCode, uCR2, CPUMGetGuestRIP(pVCpu), enmType, cbInstr);
 
             /*
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 45530)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 45531)
@@ -734,4 +734,5 @@
         uint32_t                    u32Padding; /**< Explicit alignment padding. */
         uint64_t                    u64IntrInfo;
+        RTGCUINTPTR                 GCPtrFaultAddress;
     } Event;
 
Index: /trunk/src/VBox/VMM/include/TRPMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/TRPMInternal.h	(revision 45530)
+++ /trunk/src/VBox/VMM/include/TRPMInternal.h	(revision 45531)
@@ -234,4 +234,14 @@
     /** Previous trap vector # - for debugging. */
     RTGCUINT                uPrevVector;
+
+    /** Instruction length for software interrupts and software exceptions (#BP,
+     *  #OF) */
+    uint8_t                 cbInstr;
+
+    /** Saved instruction length. */
+    uint8_t                 cbSavedInstr;
+
+    /** Padding. */
+    uint8_t                 au8Padding[2];
 } TRPMCPU;
 
Index: /trunk/src/VBox/VMM/include/TRPMInternal.mac
===================================================================
--- /trunk/src/VBox/VMM/include/TRPMInternal.mac	(revision 45530)
+++ /trunk/src/VBox/VMM/include/TRPMInternal.mac	(revision 45531)
@@ -80,4 +80,7 @@
     .uSavedCR2          RTGCPTR_RES 1
     .uPrevVector        RTGCPTR_RES 1
+    .cbInstr            resb 1
+    .cbSavedInstr       resb 1
+    .au8Padding         resb 2
 endstruc
 
