summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2023-05-08 07:17:30 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2023-05-08 07:17:30 +0000
commitdca13206f0b913976e054a3edf6790732a308310 (patch)
tree47db0f613ddcca65f42f149f4729302af9c2d6f8 /src
parent49e713b6c442c8a7af6fa25dde02a071a38f26fc (diff)
downloadVirtualBox-svn-dca13206f0b913976e054a3edf6790732a308310.tar.gz
VMM: Nested VMX: bugref:10318 Separate injection of events between guest and nested-guest, far fewer checks, better readability at slight cost of duplication.
Fixed priority of NMI-window and interrupt-window VM-exits as they can occur regardless of whether an interrupt is pending. Fixed NMI issue with SMP nested Hyper-V enabled Windows Server 2008 R2 guest by clearing VMCPU_FF_INTERRUPT_NMI on virtual NMI-exit. Fixed vmxHCExitNmiWindowNested to call vmxHCExitNmiWindow rather than vmxHCExitIntWindow when the nested-hypervisor intercept wasn't set. git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@99653 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src')
-rw-r--r--src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h306
-rw-r--r--src/VBox/VMM/VMMR0/HMVMXR0.cpp9
-rw-r--r--src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp2
3 files changed, 238 insertions, 79 deletions
diff --git a/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h b/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h
index 1d2c99731c2..66378b75b6f 100644
--- a/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h
+++ b/src/VBox/VMM/VMMAll/VMXAllTemplate.cpp.h
@@ -3039,6 +3039,7 @@ DECLINLINE(void) vmxHCSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
| RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
| RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
+ Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
}
@@ -3054,6 +3055,7 @@ DECLINLINE(void) vmxHCSetPendingXcptNmi(PVMCPUCC pVCpu)
| RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
| RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
vmxHCSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
+ Log4Func(("NMI pending injection\n"));
}
@@ -4373,16 +4375,22 @@ static VBOXSTRICTRC vmxHCCheckForceFlags(PVMCPUCC pVCpu, bool fIsNestedGuest, bo
* Please note the priority of these events are specified and important.
* See Intel spec. 29.4.3.2 "APIC-Write Emulation".
* See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
+ *
+ * Interrupt-window and NMI-window VM-exits for the nested-guest need not be
+ * handled here. They'll be handled by the hardware while executing the nested-guest
+ * or by us when we injecting events that are not part of VM-entry of the nested-guest.
*/
if (fIsNestedGuest)
{
- /* Pending nested-guest APIC-write. */
+ /* Pending nested-guest APIC-write (may or may not cause a VM-exit). */
if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
{
Log4Func(("Pending nested-guest APIC-write\n"));
VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
- return rcStrict;
+ if ( rcStrict == VINF_SUCCESS
+ && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
+ return rcStrict;
}
/* Pending nested-guest monitor-trap flag (MTF). */
@@ -4515,6 +4523,7 @@ static void vmxHCSetIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
AssertRC(rc);
}
+ Log4Func(("Enabled interrupt-window exiting\n"));
} /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
}
@@ -4532,6 +4541,7 @@ DECLINLINE(void) vmxHCClearIntWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsI
pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
AssertRC(rc);
+ Log4Func(("Disabled interrupt-window exiting\n"));
}
}
@@ -4552,7 +4562,7 @@ static void vmxHCSetNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
AssertRC(rc);
- Log4Func(("Setup NMI-window exiting\n"));
+ Log4Func(("Enabled NMI-window exiting\n"));
}
} /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
}
@@ -4571,6 +4581,7 @@ DECLINLINE(void) vmxHCClearNmiWindowExitVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsI
pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
int rc = VMX_VMCS_WRITE_32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
AssertRC(rc);
+ Log4Func(("Disabled NMI-window exiting\n"));
}
}
@@ -4851,7 +4862,7 @@ static VBOXSTRICTRC vmxHCInjectEventVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo,
* @param fIsNestedGuest Flag whether the evaluation happens for a nested guest.
* @param pfIntrState Where to store the VT-x guest-interruptibility state.
*/
-static VBOXSTRICTRC vmxHCEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNestedGuest, uint32_t *pfIntrState)
+static VBOXSTRICTRC vmxHCEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t *pfIntrState)
{
Assert(pfIntrState);
Assert(!TRPMHasTrap(pVCpu));
@@ -4875,40 +4886,30 @@ static VBOXSTRICTRC vmxHCEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcs
* NMIs.
* NMIs take priority over external interrupts.
*/
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
- PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
-#endif
if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
{
- /*
- * For a guest, the FF always indicates the guest's ability to receive an NMI.
- *
- * For a nested-guest, the FF always indicates the outer guest's ability to
- * receive an NMI while the guest-interruptibility state bit depends on whether
- * the nested-hypervisor is using virtual-NMIs.
- */
if (!CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
{
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
- if ( fIsNestedGuest
- && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
- return IEMExecVmxVmexitXcptNmi(pVCpu);
-#endif
+ /* Finally, inject the NMI and we're done. */
vmxHCSetPendingXcptNmi(pVCpu);
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
- Log4Func(("NMI pending injection\n"));
-
- /* We've injected the NMI, bail. */
+ vmxHCClearNmiWindowExitVmcs(pVCpu, pVmcsInfo);
return VINF_SUCCESS;
}
- if (!fIsNestedGuest)
- vmxHCSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
+
+ /*
+ * Setup NMI-window exiting and also clear any interrupt-window exiting that might
+ * still be active. This can happen if we got VM-exits that were higher priority
+ * than an interrupt-window VM-exit.
+ */
+ vmxHCSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
+ vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
}
+ else
+ Assert(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT));
/*
* External interrupts (PIC/APIC).
- * Once PDMGetInterrupt() returns a valid interrupt we -must- deliver it.
- * We cannot re-request the interrupt from the controller again.
*/
if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
&& !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
@@ -4917,51 +4918,21 @@ static VBOXSTRICTRC vmxHCEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcs
int rc = vmxHCImportGuestStateEx(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
AssertRC(rc);
- /*
- * We must not check EFLAGS directly when executing a nested-guest, use
- * CPUMIsGuestPhysIntrEnabled() instead as EFLAGS.IF does not control the blocking of
- * external interrupts when "External interrupt exiting" is set. This fixes a nasty
- * SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued by
- * other VM-exits (like a preemption timer), see @bugref{9562#c18}.
- *
- * See Intel spec. 25.4.1 "Event Blocking".
- */
- if (CPUMIsGuestPhysIntrEnabled(pVCpu))
+ if (pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF)
{
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
- if ( fIsNestedGuest
- && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
- {
- VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
- if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
- return rcStrict;
- }
-#endif
+ /*
+ * Once PDMGetInterrupt() returns an interrupt we -must- deliver it.
+ * We cannot re-request the interrupt from the controller again.
+ */
uint8_t u8Interrupt;
rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
if (RT_SUCCESS(rc))
- {
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
- if ( fIsNestedGuest
- && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
- {
- VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
- Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
- return rcStrict;
- }
-#endif
vmxHCSetPendingExtInt(pVCpu, u8Interrupt);
- Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
- }
else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
{
STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchTprMaskedIrq);
-
- if ( !fIsNestedGuest
- && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
+ if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
vmxHCApicSetTprThreshold(pVCpu, pVmcsInfo, u8Interrupt >> 4);
- /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
-
/*
* If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
* APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
@@ -4971,30 +4942,215 @@ static VBOXSTRICTRC vmxHCEvaluatePendingEvent(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcs
else
STAM_COUNTER_INC(&VCPU_2_VMXSTATS(pVCpu).StatSwitchGuestIrq);
- /* We've injected the interrupt or taken necessary action, bail. */
+ /* We must clear interrupt-window exiting for the same reason mentioned above for NMIs. */
+ vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
return VINF_SUCCESS;
}
- if (!fIsNestedGuest)
- vmxHCSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
+
+ /* Setup interrupt-window exiting. */
+ vmxHCSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
+ Assert(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT));
+ }
+ else
+ {
+ vmxHCClearIntWindowExitVmcs(pVCpu, pVmcsInfo);
+ Assert(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT));
}
}
- else if (!fIsNestedGuest)
+ else
{
/*
- * An event is being injected or we are in an interrupt shadow. Check if another event is
- * pending. If so, instruct VT-x to cause a VM-exit as soon as the guest is ready to accept
- * the pending event.
+ * An event is being injected or we are in an interrupt shadow.
+ * If another event is pending currently, instruct VT-x to cause a VM-exit as
+ * soon as the guest is ready to accept it.
*/
if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
vmxHCSetNmiWindowExitVmcs(pVCpu, pVmcsInfo);
- else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
- && !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
- vmxHCSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
+ else
+ {
+ Assert(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT));
+ if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
+ && !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction)
+ vmxHCSetIntWindowExitVmcs(pVCpu, pVmcsInfo);
+ else
+ Assert(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT));
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+/**
+ * Evaluates the event to be delivered to the nested-guest and sets it as the
+ * pending event.
+ *
+ * Toggling of interrupt force-flags here is safe since we update TRPM on premature
+ * exits to ring-3 before executing guest code, see vmxHCExitToRing3(). We must
+ * NOT restore these force-flags.
+ *
+ * @returns Strict VBox status code (i.e. informational status codes too).
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param pVmcsInfo The VMCS information structure.
+ * @param pfIntrState Where to store the VT-x guest-interruptibility state.
+ *
+ * @remarks The guest must be in VMX non-root mode.
+ */
+static VBOXSTRICTRC vmxHCEvaluatePendingEventNested(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t *pfIntrState)
+{
+ PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
+
+ Assert(pfIntrState);
+ Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
+ Assert(!TRPMHasTrap(pVCpu));
+
+ /*
+ * Compute/update guest-interruptibility state related FFs.
+ * The FFs will be used below while evaluating events to be injected.
+ */
+ *pfIntrState = vmxHCGetGuestIntrStateAndUpdateFFs(pVCpu);
+
+ /*
+ * If we are injecting an event, we must not setup any interrupt/NMI-window
+ * exiting or we would get into an infinite VM-exit loop. An event that's
+ * already pending has already performed all necessary checks.
+ */
+ if (VCPU_2_VMXSTATE(pVCpu).Event.fPending)
+ return VINF_SUCCESS;
+
+ /*
+ * An event injected by VMLAUNCH/VMRESUME instruction emulation should've been
+ * made pending (TRPM to HM event) and would be handled above if we resumed
+ * execution in HM. If somehow we fell back to emulation after the
+ * VMLAUNCH/VMRESUME instruction, it would have been handled in iemRaiseXcptOrInt
+ * (calling iemVmxVmexitEvent). Thus, if we get here the nested-hypervisor's VMX
+ * intercepts should be active and any events pending here have been generated
+ * while executing the guest in VMX non-root mode after virtual VM-entry completed.
+ */
+ Assert(CPUMIsGuestVmxInterceptEvents(pCtx));
+
+ /*
+ * Interrupt shadows can also block NMIs. If we are in an interrupt shadow there's
+ * nothing more to do here.
+ *
+ * See Intel spec. 24.4.2 "Guest Non-Register State".
+ * See Intel spec. 25.4.1 "Event Blocking".
+ */
+ if (!CPUMIsInInterruptShadowWithUpdate(&pVCpu->cpum.GstCtx))
+ { /* likely */ }
+ else
+ return VINF_SUCCESS;
+
+ /** @todo SMI. SMIs take priority over NMIs. */
+
+ /*
+ * NMIs.
+ * NMIs take priority over external interrupts.
+ *
+ * NMI blocking is in effect after delivering an NMI until the execution of IRET.
+ * Only when there isn't any NMI blocking can an NMI-window VM-exit or delivery of an NMI happen.
+ */
+ if (!CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx))
+ {
+ /*
+ * Nested-guest NMI-window exiting.
+ * The NMI-window exit must happen regardless of whether an NMI is pending
+ * provided virtual-NMI blocking is not in effect.
+ *
+ * See Intel spec. 25.2 "Other Causes Of VM Exits".
+ */
+ if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_NMI_WINDOW)
+ && !CPUMIsGuestVmxVirtNmiBlocking(pCtx))
+ {
+ Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT));
+ return IEMExecVmxVmexit(pVCpu, VMX_EXIT_NMI_WINDOW, 0 /* u64ExitQual */);
+ }
+
+ /*
+ * For a nested-guest, the FF always indicates the outer guest's ability to
+ * receive an NMI while the guest-interruptibility state bit depends on whether
+ * the nested-hypervisor is using virtual-NMIs.
+ *
+ * It is very important that we also clear the force-flag if we are causing
+ * an NMI VM-exit as it is the responsibility of the nested-hypervisor to deal
+ * with re-injecting or discarding the NMI. This fixes the bug that showed up
+ * with SMP Windows Server 2008 R2 with Hyper-V enabled, see @bugref{10318#c19}.
+ */
+ if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI))
+ {
+ if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
+ return IEMExecVmxVmexitXcptNmi(pVCpu);
+ vmxHCSetPendingXcptNmi(pVCpu);
+ return VINF_SUCCESS;
+ }
}
- /* else: for nested-guests, NMI/interrupt-window exiting will be picked up when merging VMCS controls. */
+ /*
+ * Nested-guest interrupt-window exiting.
+ *
+ * We must cause the interrupt-window exit regardless of whether an interrupt is pending
+ * provided virtual interrupts are enabled.
+ *
+ * See Intel spec. 25.2 "Other Causes Of VM Exits".
+ * See Intel spec. 26.7.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
+ */
+ if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_INT_WINDOW)
+ && CPUMIsGuestVmxVirtIntrEnabled(pCtx))
+ {
+ Assert(CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT));
+ return IEMExecVmxVmexit(pVCpu, VMX_EXIT_INT_WINDOW, 0 /* u64ExitQual */);
+ }
+
+ /*
+ * External interrupts (PIC/APIC).
+ *
+ * When "External interrupt exiting" is set the VM-exit happens regardless of RFLAGS.IF.
+ * When it isn't set, RFLAGS.IF controls delivery of the interrupt as always.
+ * This fixes a nasty SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued
+ * by other VM-exits (like a preemption timer), see @bugref{9562#c18}.
+ *
+ * See Intel spec. 25.4.1 "Event Blocking".
+ */
+ if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
+ && !VCPU_2_VMXSTATE(pVCpu).fSingleInstruction
+ && CPUMIsGuestVmxPhysIntrEnabled(pCtx))
+ {
+ Assert(!DBGFIsStepping(pVCpu));
+
+ /* Nested-guest external interrupt VM-exit. */
+ if ( CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)
+ && !CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_ACK_EXT_INT))
+ {
+ VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
+ Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
+ return rcStrict;
+ }
+
+ /*
+ * Fetch the external interrupt from the interrupt controller.
+ * Once PDMGetInterrupt() returns an interrupt we -must- deliver it or pass it to
+ * the nested-hypervisor. We cannot re-request the interrupt from the controller again.
+ */
+ uint8_t u8Interrupt;
+ int rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
+ if (RT_SUCCESS(rc))
+ {
+ /* Nested-guest external interrupt VM-exit when the "acknowledge interrupt on exit" is enabled. */
+ if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
+ {
+ Assert(CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_ACK_EXT_INT));
+ VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
+ Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
+ return rcStrict;
+ }
+ vmxHCSetPendingExtInt(pVCpu, u8Interrupt);
+ return VINF_SUCCESS;
+ }
+ }
return VINF_SUCCESS;
}
+#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
/**
@@ -7662,7 +7818,7 @@ HMVMX_EXIT_NSRC_DECL vmxHCExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransi
AssertRC(rc);
}
- /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
+ /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready. */
vmxHCClearNmiWindowExitVmcs(pVCpu, pVmcsInfo);
/* Evaluate and deliver pending events and resume guest execution. */
@@ -10060,7 +10216,7 @@ HMVMX_EXIT_NSRC_DECL vmxHCExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmx
if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
- return vmxHCExitIntWindow(pVCpu, pVmxTransient);
+ return vmxHCExitNmiWindow(pVCpu, pVmxTransient);
}
diff --git a/src/VBox/VMM/VMMR0/HMVMXR0.cpp b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
index d729b0aa516..2a16c319997 100644
--- a/src/VBox/VMM/VMMR0/HMVMXR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
@@ -5923,10 +5923,12 @@ static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransie
vmxHCTrpmTrapToPendingEvent(pVCpu);
uint32_t fIntrState;
- rcStrict = vmxHCEvaluatePendingEvent(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->fIsNestedGuest,
- &fIntrState);
-
#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+ if (!pVmxTransient->fIsNestedGuest)
+ rcStrict = vmxHCEvaluatePendingEvent(pVCpu, pVmxTransient->pVmcsInfo, &fIntrState);
+ else
+ rcStrict = vmxHCEvaluatePendingEventNested(pVCpu, pVmxTransient->pVmcsInfo, &fIntrState);
+
/*
* While evaluating pending events if something failed (unlikely) or if we were
* preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
@@ -5940,6 +5942,7 @@ static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransie
return VINF_VMX_VMEXIT;
}
#else
+ rcStrict = vmxHCEvaluatePendingEvent(pVCpu, pVmxTransient->pVmcsInfo, &fIntrState);
Assert(rcStrict == VINF_SUCCESS);
#endif
diff --git a/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp b/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp
index e12a7efc8c1..a4922ef081b 100644
--- a/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp
+++ b/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp
@@ -3738,7 +3738,7 @@ static VBOXSTRICTRC nemR3DarwinPreRunGuest(PVM pVM, PVMCPU pVCpu, PVMXTRANSIENT
vmxHCTrpmTrapToPendingEvent(pVCpu);
uint32_t fIntrState;
- rcStrict = vmxHCEvaluatePendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, false /*fIsNestedGuest*/, &fIntrState);
+ rcStrict = vmxHCEvaluatePendingEvent(pVCpu, &pVCpu->nem.s.VmcsInfo, &fIntrState);
/*
* Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus