mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
KVM: x86: Move "ack" phase of local APIC IRQ delivery to separate API
Split the "ack" phase, i.e. the movement of an interrupt from IRR=>ISR, out of kvm_get_apic_interrupt() and into a separate API so that nested VMX can acknowledge a specific interrupt _after_ emulating a VM-Exit from L2 to L1. To correctly emulate nested posted interrupts while APICv is active, KVM must: 1. find the highest pending interrupt. 2. check if that IRQ is L2's notification vector 3. emulate VM-Exit if the IRQ is NOT the notification vector 4. ACK the IRQ in L1 _after_ VM-Exit When APICv is active, the process of moving the IRQ from the IRR to the ISR also requires a VMWRITE to update vmcs01.GUEST_INTERRUPT_STATUS.SVI, and so acknowledging the interrupt before switching to vmcs01 would result in marking the IRQ as in-service in the wrong VMCS. KVM currently fudges around this issue by doing kvm_get_apic_interrupt() smack dab in the middle of emulating VM-Exit, but that hack doesn't play nice with nested posted interrupts, as notification vector IRQs don't trigger a VM-Exit in the first place. Cc: Nathan Chancellor <nathan@kernel.org> Link: https://lore.kernel.org/r/20240906043413.1049633-2-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
7efb4d8a39
commit
a194a3a13c
|
|
@ -2922,14 +2922,13 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
}
|
||||
|
||||
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
|
||||
void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector)
|
||||
{
|
||||
int vector = kvm_apic_has_interrupt(vcpu);
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
u32 ppr;
|
||||
|
||||
if (vector == -1)
|
||||
return -1;
|
||||
if (WARN_ON_ONCE(vector < 0 || !apic))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We get here even with APIC virtualization enabled, if doing
|
||||
|
|
@ -2957,6 +2956,16 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
|
|||
__apic_update_ppr(apic, &ppr);
|
||||
}
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_apic_ack_interrupt);
|
||||
|
||||
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int vector = kvm_apic_has_interrupt(vcpu);
|
||||
|
||||
if (vector != -1)
|
||||
kvm_apic_ack_interrupt(vcpu, vector);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);
|
|||
void kvm_free_lapic(struct kvm_vcpu *vcpu);
|
||||
|
||||
int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
|
||||
void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector);
|
||||
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
|
||||
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
|
||||
int kvm_apic_accept_events(struct kvm_vcpu *vcpu);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user