Skip to content

Commit a194a3a

Browse files
committed
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 7efb4d8 commit a194a3a

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

arch/x86/kvm/lapic.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,14 +2922,13 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
29222922
}
29232923
}
29242924

2925-
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
2925+
void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector)
29262926
{
2927-
int vector = kvm_apic_has_interrupt(vcpu);
29282927
struct kvm_lapic *apic = vcpu->arch.apic;
29292928
u32 ppr;
29302929

2931-
if (vector == -1)
2932-
return -1;
2930+
if (WARN_ON_ONCE(vector < 0 || !apic))
2931+
return;
29332932

29342933
/*
29352934
* We get here even with APIC virtualization enabled, if doing
@@ -2957,6 +2956,16 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
29572956
__apic_update_ppr(apic, &ppr);
29582957
}
29592958

2959+
}
2960+
EXPORT_SYMBOL_GPL(kvm_apic_ack_interrupt);
2961+
2962+
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
2963+
{
2964+
int vector = kvm_apic_has_interrupt(vcpu);
2965+
2966+
if (vector != -1)
2967+
kvm_apic_ack_interrupt(vcpu, vector);
2968+
29602969
return vector;
29612970
}
29622971

arch/x86/kvm/lapic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);
8888
void kvm_free_lapic(struct kvm_vcpu *vcpu);
8989

9090
int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
91+
void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector);
9192
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
9293
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
9394
int kvm_apic_accept_events(struct kvm_vcpu *vcpu);

0 commit comments

Comments
 (0)