On Wed, 2020-11-25 at 21:19 +0000, Sean Christopherson wrote: > > --- a/arch/x86/kvm/x86.c > > +++ b/arch/x86/kvm/x86.c > > @@ -4028,7 +4028,7 @@ static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu) > > static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu) > > { > > return kvm_arch_interrupt_allowed(vcpu) && > > - !kvm_cpu_has_interrupt(vcpu) && > > + !kvm_cpu_has_injectable_intr(vcpu) && > > Interrupt window exiting explicitly has priority over virtual interrupt delivery, > so this is correct from that perspective. > > But I wonder if would make sense to be more precise so that KVM behavior is > consistent for APICv and legacy IRQ injection. If the LAPIC is in-kernel, > KVM_INTERRUPT can only be used for EXTINT; I think it should be used for injecting Xen event channel vectors too, shouldn't it? Those have their own EOI/mask mechanism and shouldn't be injected through the LAPIC (for example by simulating MSI to the appropriate APIC+vector) because the guest won't EOI them there. Although to all extents and purposes that basically means we *are* treating them like ExtINT. Not that it makes a difference to the outcome right now, although there was once a patch floating around to allow KVM_INTERRUPT even when the PIC was in-kernel, precisely for that reason. > whether or not there's an IRQ in the > LAPIC should be irrelevant when deciding to exit to userspace. Note, the > reinjection check covers vcpu->arch.interrupt.injected for the case where LAPIC > is in userspace. > > return kvm_arch_interrupt_allowed(vcpu) && > (!lapic_in_kernel(vcpu) || !kvm_cpu_has_extint(vcpu)) && > !kvm_event_needs_reinjection(vcpu) && > kvm_cpu_accept_dm_intr(vcpu); > } Makes sense. I'm putting this version through some testing and will post it later... diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f002cdb13a0b..e85e2f1c661c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1656,6 +1656,7 @@ int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end, int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end); int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); +int kvm_cpu_has_extint(struct kvm_vcpu *v); int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v); int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 99d118ffc67d..9c4ef1682b81 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -40,7 +40,7 @@ static int pending_userspace_extint(struct kvm_vcpu *v) * check if there is pending interrupt from * non-APIC source without intack. */ -static int kvm_cpu_has_extint(struct kvm_vcpu *v) +int kvm_cpu_has_extint(struct kvm_vcpu *v) { u8 accept = kvm_apic_accept_pic_intr(v); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a3fdc16cfd6f..b50ae8ba66e9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4080,12 +4080,14 @@ static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu) * if userspace requested an interrupt window, check that the * interrupt window is open. * - * No need to exit to userspace if we already have an interrupt queued. + * If there is already an event which needs reinjection or a + * pending ExtINT, allow that to be processed by the kernel + * before letting userspace have the opportunity. */ static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu) { return kvm_arch_interrupt_allowed(vcpu) && - !kvm_cpu_has_interrupt(vcpu) && + !(lapic_in_kernel(vcpu) && kvm_cpu_has_extint(vcpu)) && !kvm_event_needs_reinjection(vcpu) && kvm_cpu_accept_dm_intr(vcpu); }