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: Steve Rutherford <srutherford@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
49df6397ed
commit
7543a635aa
|
@ -3309,6 +3309,18 @@ Valid values for 'type' are:
|
|||
to ignore the request, or to gather VM memory core dump and/or
|
||||
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. */
|
||||
char padding[256];
|
||||
};
|
||||
|
|
|
@ -574,6 +574,8 @@ struct kvm_vcpu_arch {
|
|||
struct {
|
||||
bool pv_unhalted;
|
||||
} pv;
|
||||
|
||||
int pending_ioapic_eoi;
|
||||
};
|
||||
|
||||
struct kvm_lpage_info {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
if (kvm_ioapic_handles_vector(apic, vector)) {
|
||||
int trigger_mode;
|
||||
if (apic_test_vector(vector, apic->regs + APIC_TMR))
|
||||
trigger_mode = IOAPIC_LEVEL_TRIG;
|
||||
else
|
||||
trigger_mode = IOAPIC_EDGE_TRIG;
|
||||
int trigger_mode;
|
||||
|
||||
kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode);
|
||||
/* Eoi the ioapic only if the ioapic doesn't own the vector. */
|
||||
if (!kvm_ioapic_handles_vector(apic, vector))
|
||||
return;
|
||||
|
||||
/* 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)
|
||||
|
|
|
@ -6271,6 +6271,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|||
kvm_pmu_handle_event(vcpu);
|
||||
if (kvm_check_request(KVM_REQ_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))
|
||||
vcpu_scan_ioapic(vcpu);
|
||||
if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
|
||||
|
|
|
@ -140,6 +140,7 @@ static inline bool is_error_page(struct page *page)
|
|||
#define KVM_REQ_APIC_PAGE_RELOAD 25
|
||||
#define KVM_REQ_SMI 26
|
||||
#define KVM_REQ_HV_CRASH 27
|
||||
#define KVM_REQ_IOAPIC_EOI_EXIT 28
|
||||
|
||||
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
|
||||
#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)
|
|||
}
|
||||
#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
|
||||
#endif
|
||||
|
||||
|
|
|
@ -183,6 +183,7 @@ struct kvm_s390_skeys {
|
|||
#define KVM_EXIT_EPR 23
|
||||
#define KVM_EXIT_SYSTEM_EVENT 24
|
||||
#define KVM_EXIT_S390_STSI 25
|
||||
#define KVM_EXIT_IOAPIC_EOI 26
|
||||
|
||||
/* For KVM_EXIT_INTERNAL_ERROR */
|
||||
/* Emulate instruction failed. */
|
||||
|
@ -333,6 +334,10 @@ struct kvm_run {
|
|||
__u8 sel1;
|
||||
__u16 sel2;
|
||||
} s390_stsi;
|
||||
/* KVM_EXIT_IOAPIC_EOI */
|
||||
struct {
|
||||
__u8 vector;
|
||||
} eoi;
|
||||
/* Fix the size of the union. */
|
||||
char padding[256];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue