KVM: SVM: Fix clearing IRQ window inhibit with nested guests
Clearing IRQ window inhibit today relies on interrupt window
interception, but that is not always reachable when nested guests are
involved.
If L1 is intercepting IRQs, then interrupt_window_interception() will
never be reached while L2 is active, because the only reason KVM
would set the V_IRQ intercept in vmcb02 would be on behalf of L1, i.e.
because of vmcb12. svm_clear_vintr() always operates on (at least)
vmcb01, and VMRUN unconditionally sets GIF=1, which means that
enter_svm_guest_mode() will always do svm_clear_vintr() via
svm_set_gif(svm, true). I.e. KVM will keep the VM-wide inhibit set until
control transfers back to L1 *and* an interrupt window is triggered.
If L1 is not intercepting IRQs, KVM may immediately inject L1's ExtINT
into L2 if IRQs are enabled in L2 without taking an interrupt window
interception.
Address this by clearing the IRQ window inhibit when KVM actually
injects an interrupt and there are no further injectable interrupts.
That way, if L1 isn't intercepting IRQs, KVM will drop the inhibit as
soon as an interrupt is injected into L2. And if L1 is intercepting
IRQs, KVM will keep the inhibit until the IRQ is injected into L2. So,
AVIC won't be left inhibited.
Note, somewhat blindly invoking kvm_clear_apicv_inhibit() is both wrong
and suboptimal. If the IRQWIN inhibit isn't set, then the vCPU will
unnecessarily take apicv_update_lock for write. And if a _different_ vCPU
has an injectable IRQ, clearing IRQWIN may block that vCPU's ability to
inject its IRQ. Defer fixing both issues to a future commit, as fixing
one problem without also fixing the other would also leave KVM in a
temporarily bad state, as would fixing both issues without fixing _this_
bug. I.e. it's not feasible to fix each bug independently without there
being some remaining flaw in KVM.
Co-developed-by: Naveen N Rao (AMD) <naveen@kernel.org>
Signed-off-by: Naveen N Rao (AMD) <naveen@kernel.org>
Tested-by: Naveen N Rao (AMD) <naveen@kernel.org>
Link: https://patch.msgid.link/20260123224514.2509129-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>