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 | KVM_X86_OP(load_eoi_exitmap) | 82 | KVM_X86_OP(load_eoi_exitmap) |
| 83 | KVM_X86_OP(set_virtual_apic_mode) | 83 | KVM_X86_OP(set_virtual_apic_mode) |
| 84 | KVM_X86_OP_NULL(set_apic_access_page_addr) | 84 | KVM_X86_OP_NULL(set_apic_access_page_addr) |
| 85 | KVM_X86_OP(deliver_posted_interrupt) | 85 | KVM_X86_OP(deliver_interrupt) |
| 86 | KVM_X86_OP_NULL(sync_pir_to_irr) | 86 | KVM_X86_OP_NULL(sync_pir_to_irr) |
| 87 | KVM_X86_OP(set_tss_addr) | 87 | KVM_X86_OP(set_tss_addr) |
| 88 | KVM_X86_OP(set_identity_map_addr) | 88 | KVM_X86_OP(set_identity_map_addr) |
| @@ -1409,7 +1409,8 @@ struct kvm_x86_ops { · 1408 unmodified lines | |||
| 1409 | void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); | 1409 | void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); |
| 1410 | void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu); | 1410 | void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu); |
| 1411 | void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu); | 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 | int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); | 1414 | int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); |
| 1414 | int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); | 1415 | int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); |
| 1415 | int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr); | 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 | apic->regs + APIC_TMR); | 1096 | apic->regs + APIC_TMR); |
| 1097 | } | 1097 | } |
| 1098 | 1098 | ||
| 1099 | if (static_call(kvm_x86_deliver_posted_interrupt)(vcpu, vector)) { | 1099 | static_call(kvm_x86_deliver_interrupt)(apic, delivery_mode, |
| 1100 | kvm_lapic_set_irr(vector, apic); | 1100 | trig_mode, vector); |
| 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 | } | ||
| 1107 | break; | 1101 | break; |
| 1108 | 1102 | ||
| 1109 | case APIC_DM_REMRD: | 1103 | case APIC_DM_REMRD: |
| @@ -3291,6 +3291,21 @@ static void svm_set_irq(struct kvm_vcpu *vcpu) · 3290 unmodified lines | |||
| 3291 | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; | 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 | static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) | 3309 | static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) |
| 3295 | { | 3310 | { |
| 3296 | struct vcpu_svm *svm = to_svm(vcpu); | 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 | .pmu_ops = &amd_pmu_ops, | 4560 | .pmu_ops = &amd_pmu_ops, |
| 4546 | .nested_ops = &svm_nested_ops, | 4561 | .nested_ops = &svm_nested_ops, |
| 4547 | 4562 | ||
| 4548 | .deliver_posted_interrupt = svm_deliver_avic_intr, | 4563 | .deliver_interrupt = svm_deliver_interrupt, |
| 4549 | .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt, | 4564 | .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt, |
| 4550 | .update_pi_irte = svm_update_pi_irte, | 4565 | .update_pi_irte = svm_update_pi_irte, |
| 4551 | .setup_mce = svm_setup_mce, | 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 | return 0; | 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 | * Set up the vmcs's constant host-state fields, i.e., host-state fields that | 4060 | * Set up the vmcs's constant host-state fields, i.e., host-state fields that |
| 4046 | * will not change in the lifetime of the guest. | 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 | .hwapic_isr_update = vmx_hwapic_isr_update, | 7781 | .hwapic_isr_update = vmx_hwapic_isr_update, |
| 7767 | .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt, | 7782 | .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt, |
| 7768 | .sync_pir_to_irr = vmx_sync_pir_to_irr, | 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 | .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt, | 7785 | .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt, |
| 7771 | 7786 | ||
| 7772 | .set_tss_addr = vmx_set_tss_addr, | 7787 | .set_tss_addr = vmx_set_tss_addr, |