[PATCH 2/4] KVM: VMX: prepare sync_pir_to_irr for running with APICv disabled

Paolo Bonzini
2021-11-23T00:43:30Z

If APICv is disabled for this vCPU, assigned devices may
still attempt to post interrupts. In that case, we need
to cancel the vmentry and deliver the interrupt with
KVM_REQ_EVENT. Extend the existing code that handles
injection of L1 interrupts into L2 to cover this case
as well.

vmx_hwapic_irr_update is only called when APICv is active
so it would be confusing to add a check for
vcpu->arch.apicv_active in there. Instead, just use
vmx_set_rvi directly in vmx_sync_pir_to_irr.

Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
arch/x86/kvm/vmx/vmx.c | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index ba66c171d951..cccf1eab58ac 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6264,7 +6264,7 @@ static int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
int max_irr;
bool max_irr_updated;

- if (KVM_BUG_ON(!vcpu->arch.apicv_active, vcpu->kvm))
+ if (KVM_BUG_ON(!enable_apicv, vcpu->kvm))
return -EIO;

if (pi_test_on(&vmx->pi_desc)) {
@@ -6276,20 +6276,31 @@ static int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
smp_mb__after_atomic();
max_irr_updated =
kvm_apic_update_irr(vcpu, vmx->pi_desc.pir, &max_irr);
-
- /*
- * If we are running L2 and L1 has a new pending interrupt
- * which can be injected, this may cause a vmexit or it may
- * be injected into L2. Either way, this interrupt will be
- * processed via KVM_REQ_EVENT, not RVI, because we do not use
- * virtual interrupt delivery to inject L1 interrupts into L2.
- */
- if (is_guest_mode(vcpu) && max_irr_updated)
- kvm_make_request(KVM_REQ_EVENT, vcpu);
} else {
max_irr = kvm_lapic_find_highest_irr(vcpu);
+ max_irr_updated = false;
}
- vmx_hwapic_irr_update(vcpu, max_irr);
+
+ /*
+ * If virtual interrupt delivery is not in use, the interrupt
+ * will be processed via KVM_REQ_EVENT, not RVI. This can happen
+ * in two cases:
+ *
+ * 1) If we are running L2 and L1 has a new pending interrupt
+ * which can be injected, this may cause a vmexit or it may
+ * be injected into L2. We do not use virtual interrupt
+ * delivery to inject L1 interrupts into L2.
+ *
+ * 2) If APICv is disabled for this vCPU, assigned devices may
+ * still attempt to post interrupts. The posted interrupt
+ * vector will cause a vmexit and the subsequent entry will
+ * call sync_pir_to_irr.
+ */
+ if (!is_guest_mode(vcpu) && vcpu->arch.apicv_active)
+ vmx_set_rvi(max_irr);
+ else if (max_irr_updated)
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+
return max_irr;
}

--
2.27.0