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
Unified · Split
| @@ -82,7 +82,7 @@ KVM_X86_OP_NULL(guest_apic_has_interrupt) · 81 unmodified lines | ||
| 82 | 82 | KVM_X86_OP(load_eoi_exitmap) |
| 83 | 83 | KVM_X86_OP(set_virtual_apic_mode) |
| 84 | 84 | KVM_X86_OP_NULL(set_apic_access_page_addr) |
| 85 | −KVM_X86_OP(deliver_posted_interrupt) | |
| 85 | +KVM_X86_OP(deliver_interrupt) | |
| 86 | 86 | KVM_X86_OP_NULL(sync_pir_to_irr) |
| 87 | 87 | KVM_X86_OP(set_tss_addr) |
| 88 | 88 | KVM_X86_OP(set_identity_map_addr) |
| @@ -1409,7 +1409,8 @@ struct kvm_x86_ops { · 1408 unmodified lines | ||
| 1409 | 1409 | void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); |
| 1410 | 1410 | void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu); |
| 1411 | 1411 | 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); | |
| 1413 | 1414 | int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); |
| 1414 | 1415 | int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); |
| 1415 | 1416 | int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr); |
| @@ -1096,14 +1096,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · 1095 unmodified lines | ||
| 1096 | 1096 | apic->regs + APIC_TMR); |
| 1097 | 1097 | } |
| 1098 | 1098 | |
| 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); | |
| 1107 | 1101 | break; |
| 1108 | 1102 | |
| 1109 | 1103 | case APIC_DM_REMRD: |
| @@ -3291,6 +3291,21 @@ static void svm_set_irq(struct kvm_vcpu *vcpu) · 3290 unmodified lines | ||
| 3291 | 3291 | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; |
| 3292 | 3292 | } |
| 3293 | 3293 | |
| 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 | + | |
| 3294 | 3309 | static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) |
| 3295 | 3310 | { |
| 3296 | 3311 | struct vcpu_svm *svm = to_svm(vcpu); |
| @@ -4545,7 +4560,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { · 1248 unmodified lines | ||
| 4545 | 4560 | .pmu_ops = &amd_pmu_ops, |
| 4546 | 4561 | .nested_ops = &svm_nested_ops, |
| 4547 | 4562 | |
| 4548 | − .deliver_posted_interrupt = svm_deliver_avic_intr, | |
| 4563 | + .deliver_interrupt = svm_deliver_interrupt, | |
| 4549 | 4564 | .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt, |
| 4550 | 4565 | .update_pi_irte = svm_update_pi_irte, |
| 4551 | 4566 | .setup_mce = svm_setup_mce, |
| @@ -4041,6 +4041,21 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector) · 4040 unmodified lines | ||
| 4041 | 4041 | return 0; |
| 4042 | 4042 | } |
| 4043 | 4043 | |
| 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 | + | |
| 4044 | 4059 | /* |
| 4045 | 4060 | * Set up the vmcs's constant host-state fields, i.e., host-state fields that |
| 4046 | 4061 | * will not change in the lifetime of the guest. |
| @@ -7766,7 +7781,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { · 3719 unmodified lines | ||
| 7766 | 7781 | .hwapic_isr_update = vmx_hwapic_isr_update, |
| 7767 | 7782 | .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt, |
| 7768 | 7783 | .sync_pir_to_irr = vmx_sync_pir_to_irr, |
| 7769 | − .deliver_posted_interrupt = vmx_deliver_posted_interrupt, | |
| 7784 | + .deliver_interrupt = vmx_deliver_interrupt, | |
| 7770 | 7785 | .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt, |
| 7771 | 7786 | |
| 7772 | 7787 | .set_tss_addr = vmx_set_tss_addr, |