diff --git a/hypervisor/arch/x86/interrupt.c b/hypervisor/arch/x86/interrupt.c index 40ffd2839..9952a3df1 100644 --- a/hypervisor/arch/x86/interrupt.c +++ b/hypervisor/arch/x86/interrupt.c @@ -293,6 +293,18 @@ int acrn_do_intr_process(struct vcpu *vcpu) if (bitmap_test_and_clear(ACRN_REQUEST_TMR_UPDATE, pending_intr_bits)) vioapic_update_tmr(vcpu); + /* handling cancelled event injection when vcpu is switched out */ + if (vcpu->arch_vcpu.inject_event_pending) { + exec_vmwrite(VMX_ENTRY_EXCEPTION_EC, + vcpu->arch_vcpu.inject_info.error_code); + + exec_vmwrite(VMX_ENTRY_INT_INFO_FIELD, + vcpu->arch_vcpu.inject_info.intr_info); + + vcpu->arch_vcpu.inject_event_pending = false; + goto INTR_WIN; + } + /* handling pending vector injection: * there are many reason inject failed, we need re-inject again */ @@ -380,6 +392,30 @@ INTR_WIN: return ret; } +void cancel_event_injection(struct vcpu *vcpu) +{ + uint32_t intinfo; + + intinfo = exec_vmread(VMX_ENTRY_INT_INFO_FIELD); + + /* + * If event is injected, we clear VMX_ENTRY_INT_INFO_FIELD, + * save injection info, and mark inject event pending. + * The event will be re-injected in next acrn_do_intr_process + * call. + */ + if (intinfo & VMX_INT_INFO_VALID) { + vcpu->arch_vcpu.inject_event_pending = true; + + if (intinfo & (EXCEPTION_ERROR_CODE_VALID << 8)) + vcpu->arch_vcpu.inject_info.error_code = + exec_vmread(VMX_ENTRY_EXCEPTION_EC); + + vcpu->arch_vcpu.inject_info.intr_info = intinfo; + exec_vmwrite(VMX_ENTRY_INT_INFO_FIELD, 0); + } +} + int exception_handler(struct vcpu *vcpu) { uint32_t intinfo, int_err_code; diff --git a/hypervisor/common/schedule.c b/hypervisor/common/schedule.c index c2923423f..94948cbca 100644 --- a/hypervisor/common/schedule.c +++ b/hypervisor/common/schedule.c @@ -147,6 +147,9 @@ static void context_switch_out(struct vcpu *vcpu) if (vcpu == NULL) return; + /* cancel event(int, gp, nmi and exception) injection */ + cancel_event_injection(vcpu); + atomic_store_rel_32(&vcpu->running, 0); /* do prev vcpu context switch out */ /* For now, we don't need to invalid ept. diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index 0d347ecf6..e13df9d3b 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -185,6 +185,11 @@ struct run_context { #define NORMAL_WORLD 0 #define SECURE_WORLD 1 +struct event_injection_info { + uint32_t intr_info; + uint32_t error_code; +}; + struct vcpu_arch { int cur_context; struct run_context contexts[NR_WORLD]; @@ -221,6 +226,8 @@ struct vcpu_arch { /* interrupt injection information */ uint64_t pending_intr; + bool inject_event_pending; + struct event_injection_info inject_info; /* per vcpu lapic */ void *vlapic; diff --git a/hypervisor/include/arch/x86/irq.h b/hypervisor/include/arch/x86/irq.h index 854e0403d..d0172c166 100644 --- a/hypervisor/include/arch/x86/irq.h +++ b/hypervisor/include/arch/x86/irq.h @@ -161,4 +161,6 @@ int interrupt_win_exiting_handler(struct vcpu *vcpu); int external_interrupt_handler(struct vcpu *vcpu); int acrn_do_intr_process(struct vcpu *vcpu); int interrupt_init(uint32_t logical_id); + +void cancel_event_injection(struct vcpu *vcpu); #endif /* IRQ_H */