KVM: x86: Replace late check_nested_events() hack with more precise fix
Add an argument to interrupt_allowed and nmi_allowed, to checking if interrupt injection is blocked. Use the hook to handle the case where an interrupt arrives between check_nested_events() and the injection logic. Drop the retry of check_nested_events() that hack-a-fixed the same condition. Blocking injection is also a bit of a hack, e.g. KVM should do exiting and non-exiting interrupt processing in a single pass, but it's a more precise hack. The old comment is also misleading, e.g. KVM_REQ_EVENT is purely an optimization, setting it on every run loop (which KVM doesn't do) should not affect functionality, only performance. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Message-Id: <20200423022550.15113-13-sean.j.christopherson@intel.com> [Extend to SVM, add SMI and NMI. Even though NMI and SMI cannot come asynchronously right now, making the fix generic is easy and removes a special case. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
@@ -3083,13 +3083,17 @@ bool svm_nmi_blocked(struct kvm_vcpu *vcpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool svm_nmi_allowed(struct kvm_vcpu *vcpu)
|
||||
static bool svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
if (svm->nested.nested_run_pending)
|
||||
return false;
|
||||
|
||||
return !svm_nmi_blocked(vcpu);
|
||||
/* An NMI must not be injected into L2 if it's supposed to VM-Exit. */
|
||||
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
|
||||
return false;
|
||||
|
||||
return !svm_nmi_blocked(vcpu);
|
||||
}
|
||||
|
||||
static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
|
||||
@@ -3138,13 +3142,20 @@ bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
|
||||
return (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK);
|
||||
}
|
||||
|
||||
static bool svm_interrupt_allowed(struct kvm_vcpu *vcpu)
|
||||
static bool svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
if (svm->nested.nested_run_pending)
|
||||
return false;
|
||||
|
||||
return !svm_interrupt_blocked(vcpu);
|
||||
/*
|
||||
* An IRQ must not be injected into L2 if it's supposed to VM-Exit,
|
||||
* e.g. if the IRQ arrived asynchronously after checking nested events.
|
||||
*/
|
||||
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_intr(svm))
|
||||
return false;
|
||||
|
||||
return !svm_interrupt_blocked(vcpu);
|
||||
}
|
||||
|
||||
static void enable_irq_window(struct kvm_vcpu *vcpu)
|
||||
@@ -3812,12 +3823,16 @@ bool svm_smi_blocked(struct kvm_vcpu *vcpu)
|
||||
return is_smm(vcpu);
|
||||
}
|
||||
|
||||
static bool svm_smi_allowed(struct kvm_vcpu *vcpu)
|
||||
static bool svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
if (svm->nested.nested_run_pending)
|
||||
return false;
|
||||
|
||||
/* An SMI must not be injected into L2 if it's supposed to VM-Exit. */
|
||||
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_smi(svm))
|
||||
return false;
|
||||
|
||||
return !svm_smi_blocked(vcpu);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user