KVM: x86: check PIR even for vCPUs with disabled APICv
The IRTE for an assigned device can trigger a POSTED_INTR_VECTOR even if APICv is disabled on the vCPU that receives it. In that case, the interrupt will just cause a vmexit and leave the ON bit set together with the PIR bit corresponding to the interrupt. Right now, the interrupt would not be delivered until APICv is re-enabled. However, fixing this is just a matter of always doing the PIR->IRR synchronization, even if the vCPU has temporarily disabled APICv. This is not a problem for performance, or if anything it is an improvement. First, in the common case where vcpu->arch.apicv_active is true, one fewer check has to be performed. Second, static_call_cond will elide the function call if APICv is not present or disabled. Finally, in the case for AMD hardware we can remove the sync_pir_to_irr callback: it is only needed for apic_has_interrupt_for_ppr, and that function already has a fallback for !APICv. Cc: stable@vger.kernel.org Co-developed-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Sean Christopherson <seanjc@google.com> Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: David Matlack <dmatlack@google.com> Message-Id: <20211123004311.2954158-4-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Родитель
7e1901f6c8
Коммит
37c4dbf337
|
@ -707,7 +707,7 @@ static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
|
||||||
static int apic_has_interrupt_for_ppr(struct kvm_lapic *apic, u32 ppr)
|
static int apic_has_interrupt_for_ppr(struct kvm_lapic *apic, u32 ppr)
|
||||||
{
|
{
|
||||||
int highest_irr;
|
int highest_irr;
|
||||||
if (apic->vcpu->arch.apicv_active)
|
if (kvm_x86_ops.sync_pir_to_irr)
|
||||||
highest_irr = static_call(kvm_x86_sync_pir_to_irr)(apic->vcpu);
|
highest_irr = static_call(kvm_x86_sync_pir_to_irr)(apic->vcpu);
|
||||||
else
|
else
|
||||||
highest_irr = apic_find_highest_irr(apic);
|
highest_irr = apic_find_highest_irr(apic);
|
||||||
|
|
|
@ -4651,7 +4651,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
||||||
.load_eoi_exitmap = svm_load_eoi_exitmap,
|
.load_eoi_exitmap = svm_load_eoi_exitmap,
|
||||||
.hwapic_irr_update = svm_hwapic_irr_update,
|
.hwapic_irr_update = svm_hwapic_irr_update,
|
||||||
.hwapic_isr_update = svm_hwapic_isr_update,
|
.hwapic_isr_update = svm_hwapic_isr_update,
|
||||||
.sync_pir_to_irr = kvm_lapic_find_highest_irr,
|
|
||||||
.apicv_post_state_restore = avic_post_state_restore,
|
.apicv_post_state_restore = avic_post_state_restore,
|
||||||
|
|
||||||
.set_tss_addr = svm_set_tss_addr,
|
.set_tss_addr = svm_set_tss_addr,
|
||||||
|
|
|
@ -4472,8 +4472,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||||
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
|
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_lapic_state *s)
|
struct kvm_lapic_state *s)
|
||||||
{
|
{
|
||||||
if (vcpu->arch.apicv_active)
|
static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
|
||||||
static_call(kvm_x86_sync_pir_to_irr)(vcpu);
|
|
||||||
|
|
||||||
return kvm_apic_get_state(vcpu, s);
|
return kvm_apic_get_state(vcpu, s);
|
||||||
}
|
}
|
||||||
|
@ -9571,8 +9570,7 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
|
||||||
if (irqchip_split(vcpu->kvm))
|
if (irqchip_split(vcpu->kvm))
|
||||||
kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
|
kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
|
||||||
else {
|
else {
|
||||||
if (vcpu->arch.apicv_active)
|
static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
|
||||||
static_call(kvm_x86_sync_pir_to_irr)(vcpu);
|
|
||||||
if (ioapic_in_kernel(vcpu->kvm))
|
if (ioapic_in_kernel(vcpu->kvm))
|
||||||
kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
|
kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
|
||||||
}
|
}
|
||||||
|
@ -9842,10 +9840,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This handles the case where a posted interrupt was
|
* This handles the case where a posted interrupt was
|
||||||
* notified with kvm_vcpu_kick.
|
* notified with kvm_vcpu_kick. Assigned devices can
|
||||||
|
* use the POSTED_INTR_VECTOR even if APICv is disabled,
|
||||||
|
* so do it even if APICv is disabled on this vCPU.
|
||||||
*/
|
*/
|
||||||
if (kvm_lapic_enabled(vcpu) && vcpu->arch.apicv_active)
|
if (kvm_lapic_enabled(vcpu))
|
||||||
static_call(kvm_x86_sync_pir_to_irr)(vcpu);
|
static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
|
||||||
|
|
||||||
if (kvm_vcpu_exit_request(vcpu)) {
|
if (kvm_vcpu_exit_request(vcpu)) {
|
||||||
vcpu->mode = OUTSIDE_GUEST_MODE;
|
vcpu->mode = OUTSIDE_GUEST_MODE;
|
||||||
|
@ -9889,8 +9889,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||||
if (likely(exit_fastpath != EXIT_FASTPATH_REENTER_GUEST))
|
if (likely(exit_fastpath != EXIT_FASTPATH_REENTER_GUEST))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (kvm_lapic_enabled(vcpu) && vcpu->arch.apicv_active)
|
if (kvm_lapic_enabled(vcpu))
|
||||||
static_call(kvm_x86_sync_pir_to_irr)(vcpu);
|
static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu);
|
||||||
|
|
||||||
if (unlikely(kvm_vcpu_exit_request(vcpu))) {
|
if (unlikely(kvm_vcpu_exit_request(vcpu))) {
|
||||||
exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED;
|
exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче