Skip to content

Commit 57dfd7b

Browse files
sean-jcbonzini
authored andcommitted
KVM: x86: Move delivery of non-APICv interrupt into vendor code
Handle non-APICv interrupt delivery in vendor code, even though it means VMX and SVM will temporarily have duplicate code. SVM's AVIC has a race condition that requires KVM to fall back to legacy interrupt injection _after_ the interrupt has been logged in the vIRR, i.e. to fix the race, SVM will need to open code the full flow anyways[*]. Refactor the code so that the SVM bug without introducing other issues, e.g. SVM would return "success" and thus invoke trace_kvm_apicv_accept_irq() even when delivery through the AVIC failed, and to opportunistically prepare for using KVM_X86_OP to fill each vendor's kvm_x86_ops struct, which will rely on the vendor function matching the kvm_x86_op pointer name. No functional change intended. [*] https://lore.kernel.org/all/20211213104634.199141-4-mlevitsk@redhat.com Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20220128005208.4008533-3-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent f6c6804 commit 57dfd7b

File tree

5 files changed

+37
-12
lines changed

5 files changed

+37
-12
lines changed

arch/x86/include/asm/kvm-x86-ops.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ KVM_X86_OP_NULL(guest_apic_has_interrupt)
8282
KVM_X86_OP(load_eoi_exitmap)
8383
KVM_X86_OP(set_virtual_apic_mode)
8484
KVM_X86_OP_NULL(set_apic_access_page_addr)
85-
KVM_X86_OP(deliver_posted_interrupt)
85+
KVM_X86_OP(deliver_interrupt)
8686
KVM_X86_OP_NULL(sync_pir_to_irr)
8787
KVM_X86_OP(set_tss_addr)
8888
KVM_X86_OP(set_identity_map_addr)

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,8 @@ struct kvm_x86_ops {
14091409
void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
14101410
void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
14111411
void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu);
1412-
int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
1412+
void (*deliver_interrupt)(struct kvm_lapic *apic, int delivery_mode,
1413+
int trig_mode, int vector);
14131414
int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu);
14141415
int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
14151416
int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr);

arch/x86/kvm/lapic.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,14 +1096,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
10961096
apic->regs + APIC_TMR);
10971097
}
10981098

1099-
if (static_call(kvm_x86_deliver_posted_interrupt)(vcpu, vector)) {
1100-
kvm_lapic_set_irr(vector, apic);
1101-
kvm_make_request(KVM_REQ_EVENT, vcpu);
1102-
kvm_vcpu_kick(vcpu);
1103-
} else {
1104-
trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
1105-
trig_mode, vector);
1106-
}
1099+
static_call(kvm_x86_deliver_interrupt)(apic, delivery_mode,
1100+
trig_mode, vector);
11071101
break;
11081102

11091103
case APIC_DM_REMRD:

arch/x86/kvm/svm/svm.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3291,6 +3291,21 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
32913291
SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
32923292
}
32933293

3294+
static void svm_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
3295+
int trig_mode, int vector)
3296+
{
3297+
struct kvm_vcpu *vcpu = apic->vcpu;
3298+
3299+
if (svm_deliver_avic_intr(vcpu, vector)) {
3300+
kvm_lapic_set_irr(vector, apic);
3301+
kvm_make_request(KVM_REQ_EVENT, vcpu);
3302+
kvm_vcpu_kick(vcpu);
3303+
} else {
3304+
trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
3305+
trig_mode, vector);
3306+
}
3307+
}
3308+
32943309
static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
32953310
{
32963311
struct vcpu_svm *svm = to_svm(vcpu);
@@ -4545,7 +4560,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
45454560
.pmu_ops = &amd_pmu_ops,
45464561
.nested_ops = &svm_nested_ops,
45474562

4548-
.deliver_posted_interrupt = svm_deliver_avic_intr,
4563+
.deliver_interrupt = svm_deliver_interrupt,
45494564
.dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt,
45504565
.update_pi_irte = svm_update_pi_irte,
45514566
.setup_mce = svm_setup_mce,

arch/x86/kvm/vmx/vmx.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4041,6 +4041,21 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
40414041
return 0;
40424042
}
40434043

4044+
static void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
4045+
int trig_mode, int vector)
4046+
{
4047+
struct kvm_vcpu *vcpu = apic->vcpu;
4048+
4049+
if (vmx_deliver_posted_interrupt(vcpu, vector)) {
4050+
kvm_lapic_set_irr(vector, apic);
4051+
kvm_make_request(KVM_REQ_EVENT, vcpu);
4052+
kvm_vcpu_kick(vcpu);
4053+
} else {
4054+
trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
4055+
trig_mode, vector);
4056+
}
4057+
}
4058+
40444059
/*
40454060
* Set up the vmcs's constant host-state fields, i.e., host-state fields that
40464061
* will not change in the lifetime of the guest.
@@ -7766,7 +7781,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
77667781
.hwapic_isr_update = vmx_hwapic_isr_update,
77677782
.guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
77687783
.sync_pir_to_irr = vmx_sync_pir_to_irr,
7769-
.deliver_posted_interrupt = vmx_deliver_posted_interrupt,
7784+
.deliver_interrupt = vmx_deliver_interrupt,
77707785
.dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
77717786

77727787
.set_tss_addr = vmx_set_tss_addr,

0 commit comments

Comments
 (0)