From b9229348673a961623531fa4bd1712495ccf3fe7 Mon Sep 17 00:00:00 2001 From: Conghui Chen Date: Tue, 7 Apr 2020 23:02:19 +0000 Subject: [PATCH] hv: fix for waag 2 core reboot issue Waag will send NMIs to all its cores during reboot. But currently, NMI cannot be injected to vcpu which is in HLT state. To fix the problem, need to wakeup target vcpu, and inject NMI through interrupt-window. Tracked-On: #4620 Signed-off-by: Conghui Chen --- hypervisor/arch/x86/guest/virq.c | 30 ++++++++++++++++++++++++++---- hypervisor/include/arch/x86/irq.h | 2 ++ 2 files changed, 28 insertions(+), 4 deletions(-) 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)