Skip to content

Commit 7e1901f

Browse files
committed
KVM: VMX: prepare sync_pir_to_irr for running with APICv disabled
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: [email protected] Reviewed-by: Maxim Levitsky <[email protected]> Reviewed-by: David Matlack <[email protected]> Reviewed-by: Sean Christopherson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 81835ee commit 7e1901f

File tree

1 file changed

+25
-14
lines changed

1 file changed

+25
-14
lines changed

arch/x86/kvm/vmx/vmx.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6267,9 +6267,9 @@ static int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
62676267
{
62686268
struct vcpu_vmx *vmx = to_vmx(vcpu);
62696269
int max_irr;
6270-
bool max_irr_updated;
6270+
bool got_posted_interrupt;
62716271

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

62756275
if (pi_test_on(&vmx->pi_desc)) {
@@ -6279,22 +6279,33 @@ static int vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
62796279
* But on x86 this is just a compiler barrier anyway.
62806280
*/
62816281
smp_mb__after_atomic();
6282-
max_irr_updated =
6282+
got_posted_interrupt =
62836283
kvm_apic_update_irr(vcpu, vmx->pi_desc.pir, &max_irr);
6284-
6285-
/*
6286-
* If we are running L2 and L1 has a new pending interrupt
6287-
* which can be injected, this may cause a vmexit or it may
6288-
* be injected into L2. Either way, this interrupt will be
6289-
* processed via KVM_REQ_EVENT, not RVI, because we do not use
6290-
* virtual interrupt delivery to inject L1 interrupts into L2.
6291-
*/
6292-
if (is_guest_mode(vcpu) && max_irr_updated)
6293-
kvm_make_request(KVM_REQ_EVENT, vcpu);
62946284
} else {
62956285
max_irr = kvm_lapic_find_highest_irr(vcpu);
6286+
got_posted_interrupt = false;
62966287
}
6297-
vmx_hwapic_irr_update(vcpu, max_irr);
6288+
6289+
/*
6290+
* Newly recognized interrupts are injected via either virtual interrupt
6291+
* delivery (RVI) or KVM_REQ_EVENT. Virtual interrupt delivery is
6292+
* disabled in two cases:
6293+
*
6294+
* 1) If L2 is running and the vCPU has a new pending interrupt. If L1
6295+
* wants to exit on interrupts, KVM_REQ_EVENT is needed to synthesize a
6296+
* VM-Exit to L1. If L1 doesn't want to exit, the interrupt is injected
6297+
* into L2, but KVM doesn't use virtual interrupt delivery to inject
6298+
* interrupts into L2, and so KVM_REQ_EVENT is again needed.
6299+
*
6300+
* 2) If APICv is disabled for this vCPU, assigned devices may still
6301+
* attempt to post interrupts. The posted interrupt vector will cause
6302+
* a VM-Exit and the subsequent entry will call sync_pir_to_irr.
6303+
*/
6304+
if (!is_guest_mode(vcpu) && kvm_vcpu_apicv_active(vcpu))
6305+
vmx_set_rvi(max_irr);
6306+
else if (got_posted_interrupt)
6307+
kvm_make_request(KVM_REQ_EVENT, vcpu);
6308+
62986309
return max_irr;
62996310
}
63006311

0 commit comments

Comments
 (0)