Commit 7543a635 authored by Steve Rutherford's avatar Steve Rutherford Committed by Paolo Bonzini

KVM: x86: Add KVM exit for IOAPIC EOIs

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.
Signed-off-by: default avatarSteve Rutherford <srutherford@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 49df6397
...@@ -3309,6 +3309,18 @@ Valid values for 'type' are: ...@@ -3309,6 +3309,18 @@ Valid values for 'type' are:
to ignore the request, or to gather VM memory core dump and/or to ignore the request, or to gather VM memory core dump and/or
reset/shutdown of the VM. reset/shutdown of the VM.
/* KVM_EXIT_IOAPIC_EOI */
struct {
__u8 vector;
} eoi;
Indicates that the VCPU's in-kernel local APIC received an EOI for a
level-triggered IOAPIC interrupt. This exit only triggers when the
IOAPIC is implemented in userspace (i.e. KVM_CAP_SPLIT_IRQCHIP is enabled);
the userspace IOAPIC should process the EOI and retrigger the interrupt if
it is still asserted. Vector is the LAPIC interrupt vector for which the
EOI was received.
/* Fix the size of the union. */ /* Fix the size of the union. */
char padding[256]; char padding[256];
}; };
......
...@@ -574,6 +574,8 @@ struct kvm_vcpu_arch { ...@@ -574,6 +574,8 @@ struct kvm_vcpu_arch {
struct { struct {
bool pv_unhalted; bool pv_unhalted;
} pv; } pv;
int pending_ioapic_eoi;
}; };
struct kvm_lpage_info { struct kvm_lpage_info {
......
...@@ -877,15 +877,25 @@ static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector) ...@@ -877,15 +877,25 @@ static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector)
static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
{ {
if (kvm_ioapic_handles_vector(apic, vector)) { int trigger_mode;
int trigger_mode;
if (apic_test_vector(vector, apic->regs + APIC_TMR)) /* Eoi the ioapic only if the ioapic doesn't own the vector. */
trigger_mode = IOAPIC_LEVEL_TRIG; if (!kvm_ioapic_handles_vector(apic, vector))
else return;
trigger_mode = IOAPIC_EDGE_TRIG;
kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode); /* Request a KVM exit to inform the userspace IOAPIC. */
if (irqchip_split(apic->vcpu->kvm)) {
apic->vcpu->arch.pending_ioapic_eoi = vector;
kvm_make_request(KVM_REQ_IOAPIC_EOI_EXIT, apic->vcpu);
return;
} }
if (apic_test_vector(vector, apic->regs + APIC_TMR))
trigger_mode = IOAPIC_LEVEL_TRIG;
else
trigger_mode = IOAPIC_EDGE_TRIG;
kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode);
} }
static int apic_set_eoi(struct kvm_lapic *apic) static int apic_set_eoi(struct kvm_lapic *apic)
......
...@@ -6271,6 +6271,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) ...@@ -6271,6 +6271,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_pmu_handle_event(vcpu); kvm_pmu_handle_event(vcpu);
if (kvm_check_request(KVM_REQ_PMI, vcpu)) if (kvm_check_request(KVM_REQ_PMI, vcpu))
kvm_pmu_deliver_pmi(vcpu); kvm_pmu_deliver_pmi(vcpu);
if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
if (test_bit(vcpu->arch.pending_ioapic_eoi,
(void *) vcpu->arch.eoi_exit_bitmap)) {
vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
vcpu->run->eoi.vector =
vcpu->arch.pending_ioapic_eoi;
r = 0;
goto out;
}
}
if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
vcpu_scan_ioapic(vcpu); vcpu_scan_ioapic(vcpu);
if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu)) if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
......
...@@ -140,6 +140,7 @@ static inline bool is_error_page(struct page *page) ...@@ -140,6 +140,7 @@ static inline bool is_error_page(struct page *page)
#define KVM_REQ_APIC_PAGE_RELOAD 25 #define KVM_REQ_APIC_PAGE_RELOAD 25
#define KVM_REQ_SMI 26 #define KVM_REQ_SMI 26
#define KVM_REQ_HV_CRASH 27 #define KVM_REQ_HV_CRASH 27
#define KVM_REQ_IOAPIC_EOI_EXIT 28
#define KVM_USERSPACE_IRQ_SOURCE_ID 0 #define KVM_USERSPACE_IRQ_SOURCE_ID 0
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 #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) ...@@ -1146,4 +1147,3 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
} }
#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
#endif #endif
...@@ -183,6 +183,7 @@ struct kvm_s390_skeys { ...@@ -183,6 +183,7 @@ struct kvm_s390_skeys {
#define KVM_EXIT_EPR 23 #define KVM_EXIT_EPR 23
#define KVM_EXIT_SYSTEM_EVENT 24 #define KVM_EXIT_SYSTEM_EVENT 24
#define KVM_EXIT_S390_STSI 25 #define KVM_EXIT_S390_STSI 25
#define KVM_EXIT_IOAPIC_EOI 26
/* For KVM_EXIT_INTERNAL_ERROR */ /* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */ /* Emulate instruction failed. */
...@@ -333,6 +334,10 @@ struct kvm_run { ...@@ -333,6 +334,10 @@ struct kvm_run {
__u8 sel1; __u8 sel1;
__u16 sel2; __u16 sel2;
} s390_stsi; } s390_stsi;
/* KVM_EXIT_IOAPIC_EOI */
struct {
__u8 vector;
} eoi;
/* Fix the size of the union. */ /* Fix the size of the union. */
char padding[256]; char padding[256];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment