Adds KVM_EXIT_IOAPIC_EOI which allows the kernel to EOI level-triggered IOAPIC interrupts. Uses a per VCPU exit bitmap to decide whether or not the IOAPIC needs to be informed (which is identical to the EOI_EXIT_BITMAP field used by modern x86 processors, but can also be used to elide kvm IOAPIC EOI exits on older processors). [Note: A prototype using ResampleFDs found that decoupling the EOI from the VCPU's thread made it possible for the VCPU to not see a recent EOI after reentering the guest. This does not match real hardware.] Compile tested for Intel x86.
Unified · Split
| @@ -3309,6 +3309,18 @@ Valid values for 'type' are: · 3308 unmodified lines | ||
| 3309 | 3309 | to ignore the request, or to gather VM memory core dump and/or |
| 3310 | 3310 | reset/shutdown of the VM. |
| 3311 | 3311 | |
| 3312 | + /* KVM_EXIT_IOAPIC_EOI */ | |
| 3313 | + struct { | |
| 3314 | + __u8 vector; | |
| 3315 | + } eoi; | |
| 3316 | + | |
| 3317 | +Indicates that the VCPU's in-kernel local APIC received an EOI for a | |
| 3318 | +level-triggered IOAPIC interrupt. This exit only triggers when the | |
| 3319 | +IOAPIC is implemented in userspace (i.e. KVM_CAP_SPLIT_IRQCHIP is enabled); | |
| 3320 | +the userspace IOAPIC should process the EOI and retrigger the interrupt if | |
| 3321 | +it is still asserted. Vector is the LAPIC interrupt vector for which the | |
| 3322 | +EOI was received. | |
| 3323 | + | |
| 3312 | 3324 | /* Fix the size of the union. */ |
| 3313 | 3325 | char padding[256]; |
| 3314 | 3326 | }; |
| @@ -574,6 +574,8 @@ struct kvm_vcpu_arch { · 573 unmodified lines | ||
| 574 | 574 | struct { |
| 575 | 575 | bool pv_unhalted; |
| 576 | 576 | } pv; |
| 577 | + | |
| 578 | + int pending_ioapic_eoi; | |
| 577 | 579 | }; |
| 578 | 580 | |
| 579 | 581 | struct kvm_lpage_info { |
| @@ -877,15 +877,25 @@ static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector) · 876 unmodified lines | ||
| 877 | 877 | |
| 878 | 878 | static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) |
| 879 | 879 | { |
| 880 | − if (kvm_ioapic_handles_vector(apic, vector)) { | |
| 881 | − int trigger_mode; | |
| 882 | − if (apic_test_vector(vector, apic->regs + APIC_TMR)) | |
| 883 | − trigger_mode = IOAPIC_LEVEL_TRIG; | |
| 884 | − else | |
| 885 | − trigger_mode = IOAPIC_EDGE_TRIG; | |
| 880 | + int trigger_mode; | |
| 881 | + | |
| 882 | + /* Eoi the ioapic only if the ioapic doesn't own the vector. */ | |
| 883 | + if (!kvm_ioapic_handles_vector(apic, vector)) | |
| 884 | + return; | |
| 886 | 885 | |
| 887 | − kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode); | |
| 886 | + /* Request a KVM exit to inform the userspace IOAPIC. */ | |
| 887 | + if (irqchip_split(apic->vcpu->kvm)) { | |
| 888 | + apic->vcpu->arch.pending_ioapic_eoi = vector; | |
| 889 | + kvm_make_request(KVM_REQ_IOAPIC_EOI_EXIT, apic->vcpu); | |
| 890 | + return; | |
| 888 | 891 | } |
| 892 | + | |
| 893 | + if (apic_test_vector(vector, apic->regs + APIC_TMR)) | |
| 894 | + trigger_mode = IOAPIC_LEVEL_TRIG; | |
| 895 | + else | |
| 896 | + trigger_mode = IOAPIC_EDGE_TRIG; | |
| 897 | + | |
| 898 | + kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode); | |
| 889 | 899 | } |
| 890 | 900 | |
| 891 | 901 | static int apic_set_eoi(struct kvm_lapic *apic) |
| @@ -6271,6 +6271,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · 6270 unmodified lines | ||
| 6271 | 6271 | kvm_pmu_handle_event(vcpu); |
| 6272 | 6272 | if (kvm_check_request(KVM_REQ_PMI, vcpu)) |
| 6273 | 6273 | kvm_pmu_deliver_pmi(vcpu); |
| 6274 | + if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) { | |
| 6275 | + BUG_ON(vcpu->arch.pending_ioapic_eoi > 255); | |
| 6276 | + if (test_bit(vcpu->arch.pending_ioapic_eoi, | |
| 6277 | + (void *) vcpu->arch.eoi_exit_bitmap)) { | |
| 6278 | + vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI; | |
| 6279 | + vcpu->run->eoi.vector = | |
| 6280 | + vcpu->arch.pending_ioapic_eoi; | |
| 6281 | + r = 0; | |
| 6282 | + goto out; | |
| 6283 | + } | |
| 6284 | + } | |
| 6274 | 6285 | if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) |
| 6275 | 6286 | vcpu_scan_ioapic(vcpu); |
| 6276 | 6287 | if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu)) |
| @@ -140,6 +140,7 @@ static inline bool is_error_page(struct page *page) · 139 unmodified lines | ||
| 140 | 140 | #define KVM_REQ_APIC_PAGE_RELOAD 25 |
| 141 | 141 | #define KVM_REQ_SMI 26 |
| 142 | 142 | #define KVM_REQ_HV_CRASH 27 |
| 143 | +#define KVM_REQ_IOAPIC_EOI_EXIT 28 | |
| 143 | 144 | |
| 144 | 145 | #define KVM_USERSPACE_IRQ_SOURCE_ID 0 |
| 145 | 146 | #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 |
| @@ -1146,4 +1147,3 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val) · 1000 unmodified lines | ||
| 1146 | 1147 | } |
| 1147 | 1148 | #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ |
| 1148 | 1149 | #endif |
| 1149 | − | |
| @@ -183,6 +183,7 @@ struct kvm_s390_skeys { · 182 unmodified lines | ||
| 183 | 183 | #define KVM_EXIT_EPR 23 |
| 184 | 184 | #define KVM_EXIT_SYSTEM_EVENT 24 |
| 185 | 185 | #define KVM_EXIT_S390_STSI 25 |
| 186 | +#define KVM_EXIT_IOAPIC_EOI 26 | |
| 186 | 187 | |
| 187 | 188 | /* For KVM_EXIT_INTERNAL_ERROR */ |
| 188 | 189 | /* Emulate instruction failed. */ |
| @@ -333,6 +334,10 @@ struct kvm_run { · 144 unmodified lines | ||
| 333 | 334 | __u8 sel1; |
| 334 | 335 | __u16 sel2; |
| 335 | 336 | } s390_stsi; |
| 337 | + /* KVM_EXIT_IOAPIC_EOI */ | |
| 338 | + struct { | |
| 339 | + __u8 vector; | |
| 340 | + } eoi; | |
| 336 | 341 | /* Fix the size of the union. */ |
| 337 | 342 | char padding[256]; |
| 338 | 343 | }; |