Index: trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp	(revision 75830)
@@ -2649,24 +2649,50 @@
 
 /**
- * Gets whether the guest or nested-guest's are ready to receive physical
- * interrupts.
- *
- * This function assumes there is no global
- *
- * @returns @c true if interrupts can be injected into the guest (or nested-guest),
- *          @c false otherwise.
+ * Returns whether the guest has physical interrupts enabled.
+ *
+ * @returns @c true if interrupts are enabled, @c false otherwise.
  * @param   pVCpu       The cross context virtual CPU structure.
- */
-DECLINLINE(bool) CPUMIsGuestPhysIntrsEnabled(PVMCPU pVCpu)
-{
-    Assert(pVCpu->cpum.s.Guest.hwvirt.fGif);
-    if (   !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.s.Guest)
-        && !CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.s.Guest))
-        return RT_BOOL(pVCpu->cpum.s.Guest.rflags.Bits.u1IF);
+ *
+ * @remarks Warning! This function does -not- take into account the global-interrupt
+ *          flag (GIF).
+ */
+VMM_INT_DECL(bool) CPUMIsGuestPhysIntrEnabled(PVMCPU pVCpu)
+{
+    if (!CPUMIsGuestInNestedHwvirtMode(&pVCpu->cpum.s.Guest))
+    {
+#ifdef VBOX_WITH_RAW_MODE_NOT_R0
+        uint32_t const fEFlags = !pVCpu->cpum.s.fRawEntered ? pVCpu->cpum.s.Guest.eflags.u : CPUMRawGetEFlags(pVCpu);
+#else
+        uint32_t const fEFlags = pVCpu->cpum.s.Guest.eflags.u;
+#endif
+        return RT_BOOL(fEFlags & X86_EFL_IF);
+    }
 
     if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.s.Guest))
-        return CPUMCanVmxNstGstTakePhysIntr(pVCpu, &pVCpu->cpum.s.Guest);
-
-    return CPUMCanSvmNstGstTakePhysIntr(pVCpu, &pVCpu->cpum.s.Guest);
+        return CPUMIsGuestVmxPhysIntrEnabled(pVCpu, &pVCpu->cpum.s.Guest);
+
+    Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.s.Guest));
+    return CPUMIsGuestSvmPhysIntrEnabled(pVCpu, &pVCpu->cpum.s.Guest);
+}
+
+
+/**
+ * Returns whether the nested-guest has virtual interrupts enabled.
+ *
+ * @returns @c true if interrupts are enabled, @c false otherwise.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ *
+ * @remarks Warning! This function does -not- take into account the global-interrupt
+ *          flag (GIF).
+ */
+VMM_INT_DECL(bool) CPUMIsGuestVirtIntrEnabled(PVMCPU pVCpu)
+{
+    Assert(CPUMIsGuestInNestedHwvirtMode(&pVCpu->cpum.s.Guest));
+
+    if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.s.Guest))
+        return CPUMIsGuestVmxVirtIntrEnabled(pVCpu, &pVCpu->cpum.s.Guest);
+
+    Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.s.Guest));
+    return CPUMIsGuestSvmVirtIntrEnabled(pVCpu, &pVCpu->cpum.s.Guest);
 }
 
@@ -2681,28 +2707,38 @@
 {
 #if 1
-    if (pVCpu->cpum.s.Guest.hwvirt.fGif)
+    /* Global-interrupt flag blocks pretty much everything we care about here. */
+    if (CPUMGetGuestGif(&pVCpu->cpum.s.Guest))
     {
-        /** @todo r=ramshankar: What about virtual-interrupt delivery to nested-guests? */
-        if (CPUMIsGuestPhysIntrsEnabled(pVCpu))
+        /*
+         * Physical interrupts are primarily blocked using EFLAGS. However, we cannot access
+         * it directly here. If and how EFLAGS are used depends on the context (nested-guest
+         * or raw-mode). Hence we use the function below which handles the details.
+         */
+        if (    CPUMIsGuestPhysIntrEnabled(pVCpu)
+            && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_BLOCK_NMIS | VMCPU_FF_INHIBIT_INTERRUPTS))
         {
-            if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_BLOCK_NMIS | VMCPU_FF_INHIBIT_INTERRUPTS))
+            if (   !CPUMIsGuestInNestedHwvirtMode(&pVCpu->cpum.s.Guest)
+                ||  CPUMIsGuestVirtIntrEnabled(pVCpu))
                 return CPUMINTERRUPTIBILITY_UNRESTRAINED;
 
-            /** @todo does blocking NMIs mean interrupts are also inhibited? */
-            if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
-            {
-                if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
-                    return CPUMINTERRUPTIBILITY_INT_INHIBITED;
-                return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
-            }
-            AssertFailed();
+            /* Physical interrupts are enabled, but nested-guest virtual interrupts are disabled. */
+            return CPUMINTERRUPTIBILITY_VIRT_INT_DISABLED;
+        }
+
+        /*
+         * Blocking the delivery of NMIs during an interrupt shadow is CPU implementation
+         * specific. Therefore, in practice, we can't deliver an NMI in an interrupt shadow.
+         * However, there is some uncertainity regarding the converse, i.e. whether
+         * NMI-blocking until IRET blocks delivery of physical interrupts.
+         *
+         * See Intel spec. 25.4.1 "Event Blocking".
+         */
+        if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
             return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
-        }
-        else
-        {
-            if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
-                return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
-            return CPUMINTERRUPTIBILITY_INT_DISABLED;
-        }
+
+        if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
+            return CPUMINTERRUPTIBILITY_INT_INHIBITED;
+
+        return CPUMINTERRUPTIBILITY_INT_DISABLED;
     }
     return CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT;
@@ -2751,5 +2787,5 @@
  * @param   pCtx    The guest-CPU context.
  */
-VMM_INT_DECL(bool) CPUMCanVmxNstGstTakePhysIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
+VMM_INT_DECL(bool) CPUMIsGuestVmxPhysIntrEnabled(PVMCPU pVCpu, PCCPUMCTX pCtx)
 {
 #ifdef IN_RC
@@ -2759,5 +2795,4 @@
     RT_NOREF(pVCpu);
     Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
-    Assert(pCtx->hwvirt.fGif);  /* Always true on Intel. */
 
     return RT_BOOL(pCtx->eflags.u & X86_EFL_IF);
@@ -2765,7 +2800,8 @@
 }
 
+
 /**
  * Checks whether the VMX nested-guest is in a state to receive virtual interrupts
- * (those injected with the "virtual-interrupt delivery" feature).
+ * (those injected with the "virtual interrupt delivery" feature).
  *
  * @returns VBox status code.
@@ -2775,5 +2811,5 @@
  * @param   pCtx    The guest-CPU context.
  */
-VMM_INT_DECL(bool) CPUMCanVmxNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
+VMM_INT_DECL(bool) CPUMIsGuestVmxVirtIntrEnabled(PVMCPU pVCpu, PCCPUMCTX pCtx)
 {
 #ifdef IN_RC
@@ -2783,5 +2819,4 @@
     RT_NOREF2(pVCpu, pCtx);
     Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
-    Assert(pCtx->hwvirt.fGif);  /* Always true on Intel. */
 
     if (   (pCtx->eflags.u & X86_EFL_IF)
@@ -2794,14 +2829,13 @@
 
 /**
- * Checks whether the SVM nested-guest is in a state to receive physical (APIC)
- * interrupts.
- *
- * @returns VBox status code.
- * @retval  true if it's ready, false otherwise.
- *
+ * Checks whether the SVM nested-guest has physical interrupts enabled.
+ *
+ * @returns true if interrupts are enabled, false otherwise.
  * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
  * @param   pCtx    The guest-CPU context.
- */
-VMM_INT_DECL(bool) CPUMCanSvmNstGstTakePhysIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
+ *
+ * @remarks This does -not- take into account the global-interrupt flag.
+ */
+VMM_INT_DECL(bool) CPUMIsGuestSvmPhysIntrEnabled(PVMCPU pVCpu, PCCPUMCTX pCtx)
 {
     /** @todo Optimization: Avoid this function call and use a pointer to the
@@ -2812,5 +2846,4 @@
 #else
     Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
-    Assert(pCtx->hwvirt.fGif);
 
     X86EFLAGS fEFlags;
@@ -2835,5 +2868,5 @@
  * @param   pCtx    The guest-CPU context.
  */
-VMM_INT_DECL(bool) CPUMCanSvmNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
+VMM_INT_DECL(bool) CPUMIsGuestSvmVirtIntrEnabled(PVMCPU pVCpu, PCCPUMCTX pCtx)
 {
 #ifdef IN_RC
@@ -2842,5 +2875,4 @@
 #else
     Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
-    Assert(pCtx->hwvirt.fGif);
 
     PCSVMVMCBCTRL pVmcbCtrl    = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl;
@@ -2863,10 +2895,10 @@
 
 /**
- * Gets the pending SVM nested-guest interrupt.
+ * Gets the pending SVM nested-guest interruptvector.
  *
  * @returns The nested-guest interrupt to inject.
  * @param   pCtx            The guest-CPU context.
  */
-VMM_INT_DECL(uint8_t) CPUMGetSvmNstGstInterrupt(PCCPUMCTX pCtx)
+VMM_INT_DECL(uint8_t) CPUMGetGuestSvmVirtIntrVector(PCCPUMCTX pCtx)
 {
 #ifdef IN_RC
Index: trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75830)
@@ -14292,9 +14292,9 @@
     /** @todo Can we centralize this under CPUMCanInjectInterrupt()? */
 #if defined(VBOX_WITH_NESTED_HWVIRT_SVM)
-    bool fIntrEnabled = pVCpu->cpum.GstCtx.hwvirt.fGif;
+    bool fIntrEnabled = CPUMGetGuestGif(&pVCpu->cpum.GstCtx);
     if (fIntrEnabled)
     {
         if (CPUMIsGuestInSvmNestedHwVirtMode(IEM_GET_CTX(pVCpu)))
-            fIntrEnabled = CPUMCanSvmNstGstTakePhysIntr(pVCpu, IEM_GET_CTX(pVCpu));
+            fIntrEnabled = CPUMIsGuestSvmPhysIntrEnabled(pVCpu, IEM_GET_CTX(pVCpu));
         else
             fIntrEnabled = pVCpu->cpum.GstCtx.eflags.Bits.u1IF;
Index: trunk/src/VBox/VMM/VMMAll/IEMAllCImplSvmInstr.cpp.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllCImplSvmInstr.cpp.h	(revision 75829)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllCImplSvmInstr.cpp.h	(revision 75830)
@@ -139,7 +139,7 @@
 
         /*
-         * Disable the global interrupt flag to prevent interrupts during the 'atomic' world switch.
-         */
-        pVCpu->cpum.GstCtx.hwvirt.fGif = false;
+         * Disable the global-interrupt flag to prevent interrupts during the 'atomic' world switch.
+         */
+        CPUMSetGuestGif(&pVCpu->cpum.GstCtx, false);
 
         /*
@@ -757,7 +757,7 @@
 
         /*
-         * Clear global interrupt flags to allow interrupts in the guest.
-         */
-        pVCpu->cpum.GstCtx.hwvirt.fGif = true;
+         * Set the global-interrupt flag to allow interrupts in the guest.
+         */
+        CPUMSetGuestGif(&pVCpu->cpum.GstCtx, true);
 
         /*
@@ -1242,5 +1242,5 @@
     }
 
-    pVCpu->cpum.GstCtx.hwvirt.fGif = false;
+    CPUMSetGuestGif(&pVCpu->cpum.GstCtx, false);
     iemRegAddToRipAndClearRF(pVCpu, cbInstr);
 
@@ -1271,5 +1271,5 @@
     }
 
-    pVCpu->cpum.GstCtx.hwvirt.fGif = true;
+    CPUMSetGuestGif(&pVCpu->cpum.GstCtx, true);
     iemRegAddToRipAndClearRF(pVCpu, cbInstr);
 
Index: trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 75830)
@@ -2457,5 +2457,5 @@
         Assert(pVCpu->CTX_SUFF(pVM)->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_VGIF);    /* Hardware supports it. */
         Assert(HMSvmIsVGifActive(pVCpu->CTX_SUFF(pVM)));                                        /* VM has configured it. */
-        pVmcb->ctrl.IntCtrl.n.u1VGif = pCtx->hwvirt.fGif;
+        pVmcb->ctrl.IntCtrl.n.u1VGif = CPUMGetGuestGif(pCtx);
     }
 #endif
@@ -2810,5 +2810,5 @@
                 Assert(!CPUMIsGuestInSvmNestedHwVirtMode(pCtx));    /* We don't yet support passing VGIF feature to the guest. */
                 Assert(HMSvmIsVGifActive(pVCpu->CTX_SUFF(pVM)));    /* VM has configured it. */
-                pCtx->hwvirt.fGif = pVmcbCtrl->IntCtrl.n.u1VGif;
+                CPUMSetGuestGif(pCtx, pVmcbCtrl->IntCtrl.n.u1VGif);
             }
         }
@@ -3743,5 +3743,5 @@
     Assert(pVmcb);
 
-    bool const fGif        = pCtx->hwvirt.fGif;
+    bool const fGif        = CPUMGetGuestGif(pCtx);
     bool const fIntShadow  = hmR0SvmIsIntrShadowActive(pVCpu);
     bool const fBlockNmi   = VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
@@ -3803,5 +3803,5 @@
         if (    fGif
             && !fIntShadow
-            &&  CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx))
+            &&  CPUMIsGuestSvmPhysIntrEnabled(pVCpu, pCtx))
         {
             if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, pCtx, SVM_CTRL_INTERCEPT_INTR))
@@ -3863,9 +3863,5 @@
     Assert(pVmcb);
 
-#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
-    bool const fGif       = pCtx->hwvirt.fGif;
-#else
-    bool const fGif       = true;
-#endif
+    bool const fGif       = CPUMGetGuestGif(pCtx);
     bool const fIntShadow = hmR0SvmIsIntrShadowActive(pVCpu);
     bool const fBlockInt  = !(pCtx->eflags.u32 & X86_EFL_IF);
@@ -3974,5 +3970,5 @@
          */
         if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
-            fAllowInt = CPUMCanSvmNstGstTakePhysIntr(pVCpu, pCtx) || CPUMCanSvmNstGstTakeVirtIntr(pVCpu, pCtx);
+            fAllowInt = CPUMIsGuestSvmPhysIntrEnabled(pVCpu, pCtx) || CPUMIsGuestSvmVirtIntrEnabled(pVCpu, pCtx);
         else
             fAllowInt = RT_BOOL(pCtx->eflags.u32 & X86_EFL_IF);
Index: trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 75830)
@@ -618,4 +618,6 @@
 {
     Assert(!TRPMHasTrap(pVCpu));
+    Assert(   enmInterruptibility > CPUMINTERRUPTIBILITY_INVALID
+           && enmInterruptibility < CPUMINTERRUPTIBILITY_END);
 
     /*
@@ -625,5 +627,5 @@
         && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI  | VMCPU_FF_INTERRUPT_NMI))
     {
-        if (enmInterruptibility <= CPUMINTERRUPTIBILITY_INT_INHIBITED)
+        if (enmInterruptibility <= CPUMINTERRUPTIBILITY_UNRESTRAINED)
         {
             uint8_t u8Interrupt = 0;
@@ -659,4 +661,17 @@
         }
     }
+    /*
+     * Nested-guest virtual interrupt.
+     */
+    else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST))
+    {
+        if (enmInterruptibility < CPUMINTERRUPTIBILITY_VIRT_INT_DISABLED)
+        {
+            /** @todo NSTVMX: NSTSVM: Remember, we might have to check and perform VM-exits
+             *        here before injecting the virtual interrupt. See emR3ForcedActions
+             *        for details. */
+            return VINF_EM_HALT;
+        }
+    }
 
     if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UNHALT))
@@ -730,6 +745,5 @@
                            | VMCPU_FF_REQUEST                 | VMCPU_FF_DBGF                 | VMCPU_FF_HM_UPDATE_CR3
                            | VMCPU_FF_HM_UPDATE_PAE_PDPES     | VMCPU_FF_PGM_SYNC_CR3         | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
-                           | VMCPU_FF_TO_R3                   | VMCPU_FF_IOM                  | VMCPU_FF_INTERRUPT_NESTED_GUEST /*?*/
-                           | VMCPU_FF_VMX_PREEMPT_TIMER /*?*/ | VMCPU_FF_VMX_APIC_WRITE /*?*/ | VMCPU_FF_VMX_MTF /*?*/
+                           | VMCPU_FF_TO_R3                   | VMCPU_FF_IOM
 #ifdef VBOX_WITH_RAW_MODE
                            | VMCPU_FF_TRPM_SYNC_IDT           | VMCPU_FF_SELM_SYNC_TSS        | VMCPU_FF_SELM_SYNC_GDT
@@ -746,5 +760,5 @@
     if (   pVCpu->vmm.s.fMayHaltInRing0
         && !TRPMHasTrap(pVCpu)
-        && (   enmInterruptibility <= CPUMINTERRUPTIBILITY_INT_INHIBITED
+        && (   enmInterruptibility == CPUMINTERRUPTIBILITY_UNRESTRAINED
             || uMWait > 1))
     {
@@ -758,6 +772,11 @@
                 APICUpdatePendingInterrupts(pVCpu);
 
-            if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
-                                         | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_UNHALT))
+            /*
+             * Flags that wake up from the halted state.
+             */
+            uint64_t const fIntMask = VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_INTERRUPT_NESTED_GUEST
+                                    | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_UNHALT;
+
+            if (VMCPU_FF_IS_ANY_SET(pVCpu, fIntMask))
                 return vmmR0DoHaltInterrupt(pVCpu, uMWait, enmInterruptibility);
             ASMNopPause();
@@ -775,6 +794,5 @@
                     APICUpdatePendingInterrupts(pVCpu);
 
-                if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
-                                             | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_UNHALT))
+                if (VMCPU_FF_IS_ANY_SET(pVCpu, fIntMask))
                     return vmmR0DoHaltInterrupt(pVCpu, uMWait, enmInterruptibility);
 
@@ -813,6 +831,5 @@
                             }
                             ASMNopPause();
-                            if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
-                                                    | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_UNHALT))
+                            if (VMCPU_FF_IS_ANY_SET(pVCpu, fIntMask))
                             {
                                 STAM_REL_COUNTER_INC(&pVCpu->vmm.s.StatR0HaltExecFromSpin);
@@ -853,6 +870,5 @@
                             if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
                                 APICUpdatePendingInterrupts(pVCpu);
-                            if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
-                                                         | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_UNHALT))
+                            if (VMCPU_FF_IS_ANY_SET(pVCpu, fIntMask))
                             {
                                 STAM_REL_COUNTER_INC(&pVCpu->vmm.s.StatR0HaltExecFromBlock);
Index: trunk/src/VBox/VMM/VMMR3/CPUM.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/CPUM.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMR3/CPUM.cpp	(revision 75830)
@@ -1955,5 +1955,5 @@
      * Hardware virtualization state.
      */
-    pCtx->hwvirt.fGif = true;
+    CPUMSetGuestGif(pCtx, true);
     Assert(!pVM->cpum.ro.GuestFeatures.fVmx || !pVM->cpum.ro.GuestFeatures.fSvm);   /* Paranoia. */
     if (pVM->cpum.ro.GuestFeatures.fVmx)
Index: trunk/src/VBox/VMM/VMMR3/EM.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/EM.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMR3/EM.cpp	(revision 75830)
@@ -1712,197 +1712,91 @@
 
 /**
- * Helper for emR3ForcedActions() for injecting interrupts into the
- * guest.
+ * Helper for emR3ForcedActions() for VMX interrupt-window VM-exits.
  *
  * @returns VBox status code.
- * @param   pVCpu               The cross context virtual CPU structure.
- * @param   pfWakeupPending     Where to store whether a wake up from HLT state is
- *                              pending.
- * @param   pfInjected          Where to store whether an interrupt was injected.
- */
-DECLINLINE(int) emR3GstInjectIntr(PVMCPU pVCpu, bool *pfWakeupPending, bool *pfInjected)
-{
-    CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RFLAGS);
-    *pfWakeupPending = false;
-    *pfInjected      = false;
-
-    if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
+ * @param   pVCpu       The cross context virtual CPU structure.
+ */
+static int emR3VmxNstGstIntrWindowExit(PVMCPU pVCpu)
+{
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+    Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
+    if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
+    {
+        CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK);
+        VBOXSTRICTRC rcStrict = IEMExecVmxVmexitIntWindow(pVCpu);
+        if (RT_SUCCESS(rcStrict))
+        {
+            Assert(rcStrict != VINF_PGM_CHANGE_MODE);
+            Assert(rcStrict != VINF_VMX_VMEXIT);
+            return VBOXSTRICTRC_VAL(rcStrict);
+        }
+        AssertMsgFailed(("Interrupt-window Vm-exit failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
+        return VINF_EM_TRIPLE_FAULT;
+    }
+#else
+    RT_NOREF(pVCpu);
+#endif
+    return VINF_NO_CHANGE;
+}
+
+
+/**
+ * Helper for emR3ForcedActions() for SVM interrupt intercept.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ */
+static int emR3SvmNstGstIntrIntercept(PVMCPU pVCpu)
+{
 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
-        && pVCpu->cpum.GstCtx.hwvirt.fGif
-#endif
-#ifdef VBOX_WITH_RAW_MODE
-        && !PATMIsPatchGCAddr(pVCpu->CTX_SUFF(pVM), pVCpu->cpum.GstCtx.eip)
-#endif
-        && pVCpu->cpum.GstCtx.eflags.Bits.u1IF)
-    {
-        Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
-        /* Note: it's important to make sure the return code from TRPMR3InjectEvent isn't ignored! */
-        /** @todo this really isn't nice, should properly handle this */
-        CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
-        int rc2 = TRPMR3InjectEvent(pVCpu->CTX_SUFF(pVM), pVCpu, TRPM_HARDWARE_INT);
-        Assert(rc2 != VINF_VMX_VMEXIT && rc2 != VINF_SVM_VMEXIT);
-        Log(("EM: TRPMR3InjectEvent -> %d\n", rc2));
-        *pfWakeupPending = true;
-        *pfInjected      = true;
-        return rc2;
-    }
-
+    Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx));
+    if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_INTR))
+    {
+        CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
+        VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);
+        if (RT_SUCCESS(rcStrict))
+        {
+            Assert(rcStrict != VINF_PGM_CHANGE_MODE);
+            Assert(rcStrict != VINF_SVM_VMEXIT);
+            return VBOXSTRICTRC_VAL(rcStrict);
+        }
+        AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
+        return VINF_EM_TRIPLE_FAULT;
+    }
+#else
+    NOREF(pVCpu);
+#endif
     return VINF_NO_CHANGE;
 }
 
 
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-/**
- * Helper for emR3ForcedActions() for injecting interrupts into the
- * VMX nested-guest.
+/**
+ * Helper for emR3ForcedActions() for SVM virtual interrupt intercept.
  *
  * @returns VBox status code.
- * @param   pVCpu               The cross context virtual CPU structure.
- * @param   pfWakeupPending     Where to store whether a wake up from HLT state is
- *                              pending.
- * @param   pfInjected          Where to store whether an interrrupt was injected.
- */
-static int emR3VmxNstGstInjectIntr(PVMCPU pVCpu, bool *pfWakeupPending, bool *pfInjected)
-{
-    Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
-    *pfWakeupPending = false;
-    *pfInjected      = false;
-
-    /** @todo NSTVMX: Interrupt-window VM-exits currently only trigger when an
-     *        interrupt is pending but in reality it should happen as soon as the
-     *        guest is ready to receive interrupts even if no interrupt is pending.
-     *        Doing it before checking the VMCPU_FF_INTERRUPT_APIC or
-     *        VMCPU_FF_INTERRUPT_PIC here doesn't help as the caller already checks for
-     *        it earlier as part of the high-priority pre-mask anyway. */
-    if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
-        && CPUMCanVmxNstGstTakePhysIntr(pVCpu, &pVCpu->cpum.GstCtx))
-    {
-        Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
-        Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
-        if (CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
-        {
-            CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK);
-            VBOXSTRICTRC rcStrict = IEMExecVmxVmexitIntWindow(pVCpu);
-            if (RT_SUCCESS(rcStrict))
-            {
-                *pfWakeupPending = true;
-                Assert(rcStrict != VINF_PGM_CHANGE_MODE);
-                if (rcStrict == VINF_VMX_VMEXIT)
-                    return VINF_SUCCESS;
-                return VBOXSTRICTRC_VAL(rcStrict);
-            }
-            AssertMsgFailed(("Interrupt-window Vm-exit failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
-            return VINF_EM_TRIPLE_FAULT;
-        }
-
-        int rc = emR3GstInjectIntr(pVCpu, pfWakeupPending, pfInjected);
-        if (rc == VINF_VMX_VMEXIT)
-            rc = VINF_SUCCESS;
-        return rc;
-    }
-
-    /** @todo NSTVMX: Virtual interrupt injection, virtual-interrupt delivery. */
-
+ * @param   pVCpu       The cross context virtual CPU structure.
+ */
+static int emR3SvmNstGstVirtIntrIntercept(PVMCPU pVCpu)
+{
+#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
+    if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_VINTR))
+    {
+        CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
+        VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);
+        if (RT_SUCCESS(rcStrict))
+        {
+            Assert(rcStrict != VINF_PGM_CHANGE_MODE);
+            Assert(rcStrict != VINF_SVM_VMEXIT);
+            return VBOXSTRICTRC_VAL(rcStrict);
+        }
+        AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
+        return VINF_EM_TRIPLE_FAULT;
+    }
+#else
+    NOREF(pVCpu);
+#endif
     return VINF_NO_CHANGE;
 }
-#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
-
-#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
-/**
- * Helper for emR3ForcedActions() for injecting interrupts into the
- * SVM nested-guest.
- *
- * @returns VBox status code.
- * @param   pVCpu               The cross context virtual CPU structure.
- * @param   pfWakeupPending     Where to store whether a wake up from HLT state is
- *                              pending.
- * @param   pfInjected          Where to store whether an interrupt was injected.
- */
-static int emR3SvmNstGstInjectIntr(PVMCPU pVCpu, bool *pfWakeupPending, bool *pfInjected)
-{
-    Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx));
-    *pfWakeupPending = false;
-    *pfInjected      = false;
-
-    PVM  pVM  = pVCpu->CTX_SUFF(pVM);
-    bool fGif = pVCpu->cpum.GstCtx.hwvirt.fGif;
-#ifdef VBOX_WITH_RAW_MODE
-    fGif &= !PATMIsPatchGCAddr(pVM, pVCpu->cpum.GstCtx.eip);
-#endif
-    if (fGif)
-    {
-        if (CPUMCanSvmNstGstTakePhysIntr(pVCpu, &pVCpu->cpum.GstCtx))
-        {
-            Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
-            if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
-            {
-                if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_INTR))
-                {
-                    CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
-                    VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_INTR, 0, 0);
-                    if (RT_SUCCESS(rcStrict))
-                    {
-                        /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
-                         *        doesn't intercept HLT but intercepts INTR? */
-                        Assert(rcStrict != VINF_PGM_CHANGE_MODE);
-                        if (rcStrict == VINF_SVM_VMEXIT)
-                            rcStrict = VINF_SUCCESS;
-                        *pfWakeupPending = true;
-                        return VBOXSTRICTRC_VAL(rcStrict);
-                    }
-
-                    AssertMsgFailed(("INTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
-                    return VINF_EM_TRIPLE_FAULT;
-                }
-
-                CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
-                /** @todo this really isn't nice, should properly handle this */
-                int rc = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT);
-                Assert(rc != VINF_PGM_CHANGE_MODE);
-                if (rc == VINF_SVM_VMEXIT)
-                    rc = VINF_SUCCESS;
-                *pfWakeupPending = true;
-                *pfInjected      = true;
-                return rc;
-            }
-        }
-
-        if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
-            && CPUMCanSvmNstGstTakeVirtIntr(pVCpu, &pVCpu->cpum.GstCtx))
-        {
-            if (CPUMIsGuestSvmCtrlInterceptSet(pVCpu, &pVCpu->cpum.GstCtx, SVM_CTRL_INTERCEPT_VINTR))
-            {
-                CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK);
-                VBOXSTRICTRC rcStrict = IEMExecSvmVmexit(pVCpu, SVM_EXIT_VINTR, 0, 0);
-                if (RT_SUCCESS(rcStrict))
-                {
-                    /** @todo r=ramshankar: Do we need to signal a wakeup here? If a nested-guest
-                     *        doesn't intercept HLT but intercepts VINTR? */
-                    Assert(rcStrict != VINF_PGM_CHANGE_MODE);
-                    if (rcStrict == VINF_SVM_VMEXIT)
-                        rcStrict = VINF_SUCCESS;
-                    *pfWakeupPending = true;
-                    return VBOXSTRICTRC_VAL(rcStrict);
-                }
-
-                AssertMsgFailed(("VINTR #VMEXIT failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
-                return VINF_EM_TRIPLE_FAULT;
-            }
-
-            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
-            uint8_t const uNstGstVector = CPUMGetSvmNstGstInterrupt(&pVCpu->cpum.GstCtx);
-            AssertMsg(uNstGstVector > 0 && uNstGstVector <= X86_XCPT_LAST, ("Invalid VINTR vector %#x\n", uNstGstVector));
-            TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);
-            Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));
-
-            *pfWakeupPending = true;
-            *pfInjected      = true;
-            return VINF_EM_RESCHEDULE;
-        }
-    }
-
-    return VINF_SUCCESS;
-}
-#endif  /* VBOX_WITH_NESTED_HWVIRT_SVM */
+
 
 /**
@@ -2227,33 +2121,69 @@
         {
             Assert(!HMR3IsEventPending(pVCpu));
-
-            bool fInjected;
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-            if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
-                rc2 = emR3VmxNstGstInjectIntr(pVCpu, &fWakeupPending, &fInjected);
-            else
-#endif
-#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
-            if (CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx))
-                rc2 = emR3SvmNstGstInjectIntr(pVCpu, &fWakeupPending, &fInjected);
-            else
-#endif
+            bool fGif = CPUMGetGuestGif(&pVCpu->cpum.GstCtx);
+#ifdef VBOX_WITH_RAW_MODE
+            fGif &= !PATMIsPatchGCAddr(pVM, pVCpu->cpum.GstCtx.eip);
+#endif
+            if (fGif)
             {
-                rc2 = emR3GstInjectIntr(pVCpu, &fWakeupPending, &fInjected);
-            }
-            if (rc2 != VINF_NO_CHANGE)
-            {
-                if (   pVM->em.s.fIemExecutesAll
-                    && (   rc2 == VINF_EM_RESCHEDULE_REM
-                        || rc2 == VINF_EM_RESCHEDULE_HM
-                        || rc2 == VINF_EM_RESCHEDULE_RAW))
+                /* In VMX, virtual interrupt takes priority over physical interrupts. */
+                if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
+                    && CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
+                    && CPUMIsGuestVmxVirtIntrEnabled(pVCpu, &pVCpu->cpum.GstCtx))
                 {
-                    rc2 = VINF_EM_RESCHEDULE;
+                    /** @todo NSTVMX: virtual interrupt delivery. */
+                    rc2 = VINF_NO_CHANGE;
                 }
+                /* In SVM, physical interrupts take priority over virtual interrupts. */
+                else if (   VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
+                         && CPUMIsGuestPhysIntrEnabled(pVCpu))
+                {
+                    bool fInjected = false;
+                    Assert(pVCpu->em.s.enmState != EMSTATE_WAIT_SIPI);
+
+                    if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
+                        rc2 = emR3VmxNstGstIntrWindowExit(pVCpu);
+                    else if (CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx))
+                        rc2 = emR3SvmNstGstIntrIntercept(pVCpu);
+                    else
+                        rc2 = VINF_NO_CHANGE;
+
+                    if (rc2 == VINF_NO_CHANGE)
+                    {
+                        CPUM_IMPORT_EXTRN_RET(pVCpu, IEM_CPUMCTX_EXTRN_XCPT_MASK);
+                        /** @todo this really isn't nice, should properly handle this */
+                        rc2 = TRPMR3InjectEvent(pVM, pVCpu, TRPM_HARDWARE_INT, &fInjected);
+                        fWakeupPending = true;
+                        if (   pVM->em.s.fIemExecutesAll
+                            && (   rc2 == VINF_EM_RESCHEDULE_REM
+                                || rc2 == VINF_EM_RESCHEDULE_HM
+                                || rc2 == VINF_EM_RESCHEDULE_RAW))
+                        {
+                            rc2 = VINF_EM_RESCHEDULE;
+                        }
+                    }
 #ifdef VBOX_STRICT
-                if (fInjected)
-                    rcIrq = rc2;
-#endif
-                UPDATE_RC();
+                    if (fInjected)
+                        rcIrq = rc2;
+#endif
+                    UPDATE_RC();
+                }
+                else if (   VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST)
+                         && CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx)
+                         && CPUMIsGuestSvmVirtIntrEnabled(pVCpu,  &pVCpu->cpum.GstCtx))
+                {
+                    rc2 = emR3SvmNstGstVirtIntrIntercept(pVCpu);
+                    if (rc2 == VINF_NO_CHANGE)
+                    {
+                        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
+                        uint8_t const uNstGstVector = CPUMGetGuestSvmVirtIntrVector(&pVCpu->cpum.GstCtx);
+                        AssertMsg(uNstGstVector > 0 && uNstGstVector <= X86_XCPT_LAST, ("Invalid VINTR %#x\n", uNstGstVector));
+                        TRPMAssertTrap(pVCpu, uNstGstVector, TRPM_HARDWARE_INT);
+                        Log(("EM: Asserting nested-guest virt. hardware intr: %#x\n", uNstGstVector));
+                        rc2 = VINF_EM_RESCHEDULE;
+                        rcIrq = rc2;
+                    }
+                    UPDATE_RC();
+                }
             }
         }
Index: trunk/src/VBox/VMM/VMMR3/TRPM.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/TRPM.cpp	(revision 75829)
+++ trunk/src/VBox/VMM/VMMR3/TRPM.cpp	(revision 75830)
@@ -1489,5 +1489,5 @@
 
 /**
- * Inject event (such as external irq or trap)
+ * Inject event (such as external irq or trap).
  *
  * @returns VBox status code.
@@ -1495,6 +1495,7 @@
  * @param   pVCpu       The cross context virtual CPU structure.
  * @param   enmEvent    Trpm event type
- */
-VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent)
+ * @param   pfInjected  Where to store whether the event was injected or not.
+ */
+VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent, bool *pfInjected)
 {
 #ifdef VBOX_WITH_RAW_MODE
@@ -1503,4 +1504,6 @@
 #endif
     Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
+    Assert(pfInjected);
+    *pfInjected = false;
 
     /* Currently only useful for external hardware interrupts. */
@@ -1602,4 +1605,5 @@
         }
 #endif
+        *pfInjected = true;
         if (!VM_IS_NEM_ENABLED(pVM))
         {
