mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: stable@vger.kernel.org,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	 Sasha Levin <sashal@kernel.org>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Paolo Bonzini <pbonzini@redhat.com>
Subject: [PATCH 6.6.y 04/20] KVM: nVMX: Defer SVI update to vmcs01 on EOI when L2 is active w/o VID
Date: Thu, 14 Aug 2025 17:25:24 -0700	[thread overview]
Message-ID: <20250815002540.2375664-5-seanjc@google.com> (raw)
In-Reply-To: <20250815002540.2375664-1-seanjc@google.com>

From: Chao Gao <chao.gao@intel.com>

[ Upstream commit 04bc93cf49d16d01753b95ddb5d4f230b809a991 ]

If KVM emulates an EOI for L1's virtual APIC while L2 is active, defer
updating GUEST_INTERUPT_STATUS.SVI, i.e. the VMCS's cache of the highest
in-service IRQ, until L1 is active, as vmcs01, not vmcs02, needs to track
vISR.  The missed SVI update for vmcs01 can result in L1 interrupts being
incorrectly blocked, e.g. if there is a pending interrupt with lower
priority than the interrupt that was EOI'd.

This bug only affects use cases where L1's vAPIC is effectively passed
through to L2, e.g. in a pKVM scenario where L2 is L1's depriveleged host,
as KVM will only emulate an EOI for L1's vAPIC if Virtual Interrupt
Delivery (VID) is disabled in vmc12, and L1 isn't intercepting L2 accesses
to its (virtual) APIC page (or if x2APIC is enabled, the EOI MSR).

WARN() if KVM updates L1's ISR while L2 is active with VID enabled, as an
EOI from L2 is supposed to affect L2's vAPIC, but still defer the update,
to try to keep L1 alive.  Specifically, KVM forwards all APICv-related
VM-Exits to L1 via nested_vmx_l1_wants_exit():

	case EXIT_REASON_APIC_ACCESS:
	case EXIT_REASON_APIC_WRITE:
	case EXIT_REASON_EOI_INDUCED:
		/*
		 * The controls for "virtualize APIC accesses," "APIC-
		 * register virtualization," and "virtual-interrupt
		 * delivery" only come from vmcs12.
		 */
		return true;

Fixes: c7c9c56ca26f ("x86, apicv: add virtual interrupt delivery support")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/kvm/20230312180048.1778187-1-jason.cj.chen@intel.com
Reported-by: Markku Ahvenjärvi <mankku@gmail.com>
Closes: https://lore.kernel.org/all/20240920080012.74405-1-mankku@gmail.com
Cc: Janne Karhunen <janne.karhunen@gmail.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
[sean: drop request, handle in VMX, write changelog]
Tested-by: Chao Gao <chao.gao@intel.com>
Link: https://lore.kernel.org/r/20241128000010.4051275-3-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
[sean: resolve minor syntactic conflict in lapic.h, account for lack of
       kvm_x86_call(), drop sanity check due to lack of wants_to_run]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/lapic.c      | 11 +++++++++++
 arch/x86/kvm/lapic.h      |  1 +
 arch/x86/kvm/vmx/nested.c |  5 +++++
 arch/x86/kvm/vmx/vmx.c    | 16 ++++++++++++++++
 arch/x86/kvm/vmx/vmx.h    |  1 +
 5 files changed, 34 insertions(+)

diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index cbf85a1ffb74..ba1c2a7f74f7 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -803,6 +803,17 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
 	}
 }
 
+void kvm_apic_update_hwapic_isr(struct kvm_vcpu *vcpu)
+{
+	struct kvm_lapic *apic = vcpu->arch.apic;
+
+	if (WARN_ON_ONCE(!lapic_in_kernel(vcpu)) || !apic->apicv_active)
+		return;
+
+	static_call(kvm_x86_hwapic_isr_update)(vcpu, apic_find_highest_isr(apic));
+}
+EXPORT_SYMBOL_GPL(kvm_apic_update_hwapic_isr);
+
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 {
 	/* This may race with setting of irr in __apic_accept_irq() and
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 0a0ea4b5dd8c..0dd069b8d6d1 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -124,6 +124,7 @@ int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
 int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
 int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
 enum lapic_mode kvm_get_apic_mode(struct kvm_vcpu *vcpu);
+void kvm_apic_update_hwapic_isr(struct kvm_vcpu *vcpu);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
 u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index d3e346a574f1..fdf7503491f9 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4900,6 +4900,11 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
 		kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
 	}
 
+	if (vmx->nested.update_vmcs01_hwapic_isr) {
+		vmx->nested.update_vmcs01_hwapic_isr = false;
+		kvm_apic_update_hwapic_isr(vcpu);
+	}
+
 	if ((vm_exit_reason != -1) &&
 	    (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
 		vmx->nested.need_vmcs12_to_shadow_sync = true;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index cde01eb1f5e3..4563e7a9a851 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6839,6 +6839,22 @@ static void vmx_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)
 	u16 status;
 	u8 old;
 
+	/*
+	 * If L2 is active, defer the SVI update until vmcs01 is loaded, as SVI
+	 * is only relevant for if and only if Virtual Interrupt Delivery is
+	 * enabled in vmcs12, and if VID is enabled then L2 EOIs affect L2's
+	 * vAPIC, not L1's vAPIC.  KVM must update vmcs01 on the next nested
+	 * VM-Exit, otherwise L1 with run with a stale SVI.
+	 */
+	if (is_guest_mode(vcpu)) {
+		/*
+		 * KVM is supposed to forward intercepted L2 EOIs to L1 if VID
+		 * is enabled in vmcs12; as above, the EOIs affect L2's vAPIC.
+		 */
+		to_vmx(vcpu)->nested.update_vmcs01_hwapic_isr = true;
+		return;
+	}
+
 	if (max_isr == -1)
 		max_isr = 0;
 
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index 6be1627d888e..88c5b7ebf9d3 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -177,6 +177,7 @@ struct nested_vmx {
 	bool reload_vmcs01_apic_access_page;
 	bool update_vmcs01_cpu_dirty_logging;
 	bool update_vmcs01_apicv_status;
+	bool update_vmcs01_hwapic_isr;
 
 	/*
 	 * Enlightened VMCS has been enabled. It does not mean that L1 has to
-- 
2.51.0.rc1.163.g2494970778-goog


  parent reply	other threads:[~2025-08-15  0:25 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-15  0:25 [PATCH 6.6.y 00/20] KVM: x86: Backports for 6.6.y Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 01/20] KVM: x86/hyper-v: Skip non-canonical addresses during PV TLB flush Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 02/20] KVM: SVM: Set RFLAGS.IF=1 in C code, to get VMRUN out of the STI shadow Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 03/20] KVM: x86: Plumb in the vCPU to kvm_x86_ops.hwapic_isr_update() Sean Christopherson
2025-08-15  0:25 ` Sean Christopherson [this message]
2025-08-15  0:25 ` [PATCH 6.6.y 05/20] KVM: x86: Take irqfds.lock when adding/deleting IRQ bypass producer Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 06/20] KVM: x86: Snapshot the host's DEBUGCTL in common x86 Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 07/20] KVM: x86: Snapshot the host's DEBUGCTL after disabling IRQs Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 08/20] KVM: x86: Plumb "force_immediate_exit" into kvm_entry() tracepoint Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 09/20] KVM: VMX: Re-enter guest in fastpath for "spurious" preemption timer exits Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 10/20] KVM: VMX: Handle forced exit due to preemption timer in fastpath Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 11/20] KVM: x86: Move handling of is_guest_mode() into fastpath exit handlers Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 12/20] KVM: VMX: Handle KVM-induced preemption timer exits in fastpath for L2 Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 13/20] KVM: x86: Fully defer to vendor code to decide how to force immediate exit Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 14/20] KVM: x86: Convert vcpu_run()'s immediate exit param into a generic bitmap Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 15/20] KVM: x86: Drop kvm_x86_ops.set_dr6() in favor of a new KVM_RUN flag Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 16/20] KVM: VMX: Allow guest to set DEBUGCTL.RTM_DEBUG if RTM is supported Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 17/20] KVM: VMX: Extract checking of guest's DEBUGCTL into helper Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 18/20] KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 19/20] KVM: VMX: Wrap all accesses to IA32_DEBUGCTL with getter/setter APIs Sean Christopherson
2025-08-15  0:25 ` [PATCH 6.6.y 20/20] KVM: VMX: Preserve host's DEBUGCTLMSR_FREEZE_IN_SMM while running the guest Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250815002540.2375664-5-seanjc@google.com \
    --to=seanjc@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=sashal@kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®