diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c index dfc6a88ac..4cf0f9830 100644 --- a/hypervisor/arch/x86/guest/virq.c +++ b/hypervisor/arch/x86/guest/virq.c @@ -105,6 +105,15 @@ static bool is_guest_irq_enabled(struct acrn_vcpu *vcpu) return status; } +static inline bool is_nmi_injectable(void) +{ + uint64_t guest_state; + + guest_state = exec_vmread32(VMX_GUEST_INTERRUPTIBILITY_INFO); + + return ((guest_state & (HV_ARCH_VCPU_BLOCKED_BY_STI | + HV_ARCH_VCPU_BLOCKED_BY_MOVSS | HV_ARCH_VCPU_BLOCKED_BY_NMI)) == 0UL); +} void vcpu_make_request(struct acrn_vcpu *vcpu, uint16_t eventid) { bitmap_set_lock(eventid, &vcpu->arch.pending_req); @@ -286,6 +295,7 @@ void vcpu_inject_extint(struct acrn_vcpu *vcpu) void vcpu_inject_nmi(struct acrn_vcpu *vcpu) { vcpu_make_request(vcpu, ACRN_REQUEST_NMI); + signal_event(&vcpu->events[VCPU_EVENT_VIRTUAL_INTERRUPT]); } /* Inject general protection exception(#GP) to guest */ @@ -401,11 +411,17 @@ int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu) injected = vcpu_inject_hi_exception(vcpu); if (!injected) { /* inject NMI before maskable hardware interrupt */ + if (bitmap_test_and_clear_lock(ACRN_REQUEST_NMI, pending_req_bits)) { - /* Inject NMI vector = 2 */ - exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, - VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI); - injected = true; + if (is_nmi_injectable()) { + /* Inject NMI vector = 2 */ + exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, + VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI); + injected = true; + } else { + /* keep the NMI request for next vmexit */ + bitmap_set_lock(ACRN_REQUEST_NMI, pending_req_bits); + } } else { /* handling pending vector injection: * there are many reason inject failed, we need re-inject again @@ -442,7 +458,13 @@ int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu) * deliver is disabled. */ if (!arch->irq_window_enabled) { + /* + * TODO: Currently, NMI exiting and virtual NMIs are not enabled, + * so use interrupt window to inject NMI. + * After enable virtual NMIs, we can use NMI-Window + */ if (bitmap_test(ACRN_REQUEST_EXTINT, pending_req_bits) || + bitmap_test(ACRN_REQUEST_NMI, pending_req_bits) || vlapic_has_pending_delivery_intr(vcpu)) { tmp = exec_vmread32(VMX_PROC_VM_EXEC_CONTROLS); tmp |= VMX_PROCBASED_CTLS_IRQ_WIN; diff --git a/hypervisor/include/arch/x86/irq.h b/hypervisor/include/arch/x86/irq.h index d0e6267fb..3c2ba9e4c 100644 --- a/hypervisor/include/arch/x86/irq.h +++ b/hypervisor/include/arch/x86/irq.h @@ -108,6 +108,8 @@ uint32_t alloc_irq_vector(uint32_t irq); #define HV_ARCH_VCPU_RFLAGS_RF (1UL<<16U) /* Interruptability State info */ + +#define HV_ARCH_VCPU_BLOCKED_BY_NMI (1UL<<3U) #define HV_ARCH_VCPU_BLOCKED_BY_MOVSS (1UL<<1U) #define HV_ARCH_VCPU_BLOCKED_BY_STI (1UL<<0U)