All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] KVM: x86: lapic: update apic_base and APIC ID together
@ 2026-08-18 23:42 Dongli Zhang
  2026-08-18 23:49 ` Dongli Zhang
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Dongli Zhang @ 2026-08-18 23:42 UTC (permalink / raw)
  To: kvm; +Cc: seanjc, pbonzini, joe.jin

The commit b2849bec936b ("KVM: VMX: Update SVI during runtime APICv
activation") resolved the loss of EOI issue when apicv is activated after
being inhibited at runtime. However, it does not resolve the cause of the
runtime apicv inhibition.

The inhibition occurs because apic_base and the APIC ID are not updated
together.

Although commit 052c3b99cbc8 ("KVM: x86: Reinitialize xAPIC ID when
userspace forces x2APIC => xAPIC") reinitializes the xAPIC ID to the
vCPU ID when userspace forces the APIC to transition directly from x2APIC
to xAPIC mode, the updates are not performed in a single transaction.

If another thread calls kvm_recalculate_apic_map() during the window
between updating apic_base and the APIC ID, kvm_recalculate_phys_map() may
set xapic_id_mismatch and temporarily inhibit APICv.

       Thread A                        Thread B

__kvm_apic_set_base()

-> vcpu->arch.apic_base = value;
   (disable x2apic)
                              kvm_recalculate_apic_map()
                              -> kvm_recalculate_phys_map()
                                 *xapic_id_mismatch = true;

-> kvm_apic_set_xapic_id(apic, vcpu->vcpu_id);


It is easier to reproduce without the commit 052c3b99cbc8 ("KVM: x86:
Reinitialize xAPIC ID when userspace forces x2APIC => xAPIC").

In the QEMU scenario, when a vCPU is removed, QEMU parks the KVM vCPU fd
and reuses it later. When the same vCPU fd is reused for another hot-add
operation, its x2APIC is still enabled. Once QEMU tries to disable x2APIC,
we may encounter the race windows described above.

Add conditional lock protection within __kvm_apic_set_base() so that
vcpu->arch.apic_base and the APIC ID are updated atomically. The same lock
is also used in kvm_recalculate_apic_map().

Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
---
 arch/x86/kvm/lapic.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 48b019114c19..1d858c259ab8 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2793,17 +2793,29 @@ static void __kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value)
 {
 	u64 old_value = vcpu->arch.apic_base;
 	struct kvm_lapic *apic = vcpu->arch.apic;
+	u64 changed = old_value ^ value;
+	bool apicbase_enable_changed = changed & MSR_IA32_APICBASE_ENABLE;
+	bool x2apic_enable_changed = changed & X2APIC_ENABLE;
+	bool apic_mode_changed = apicbase_enable_changed || x2apic_enable_changed;
+	bool need_lock = apic && apic_mode_changed;
+
+	/*
+	 * Serialize apic_base and APIC ID updates with APIC map
+	 * recalculation.
+	 */
+	if (need_lock)
+		mutex_lock(&vcpu->kvm->arch.apic_map_lock);
 
 	vcpu->arch.apic_base = value;
 
-	if ((old_value ^ value) & MSR_IA32_APICBASE_ENABLE)
+	if (apicbase_enable_changed)
 		vcpu->arch.cpuid_dynamic_bits_dirty = true;
 
 	if (!apic)
 		return;
 
 	/* update jump label if enable bit changes */
-	if ((old_value ^ value) & MSR_IA32_APICBASE_ENABLE) {
+	if (apicbase_enable_changed) {
 		if (value & MSR_IA32_APICBASE_ENABLE) {
 			kvm_apic_set_xapic_id(apic, vcpu->vcpu_id);
 			static_branch_slow_dec_deferred(&apic_hw_disabled);
@@ -2815,14 +2827,17 @@ static void __kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value)
 		}
 	}
 
-	if ((old_value ^ value) & X2APIC_ENABLE) {
+	if (x2apic_enable_changed) {
 		if (value & X2APIC_ENABLE)
 			kvm_apic_set_x2apic_id(apic, vcpu->vcpu_id);
 		else if (value & MSR_IA32_APICBASE_ENABLE)
 			kvm_apic_set_xapic_id(apic, vcpu->vcpu_id);
 	}
 
-	if ((old_value ^ value) & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) {
+	if (need_lock)
+		mutex_unlock(&vcpu->kvm->arch.apic_map_lock);
+
+	if (apic_mode_changed) {
 		kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
 		kvm_x86_call(set_virtual_apic_mode)(vcpu);
 	}
-- 
2.43.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-19  5:48 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-18 23:42 [PATCH 1/1] KVM: x86: lapic: update apic_base and APIC ID together Dongli Zhang
2026-08-18 23:49 ` Dongli Zhang
2026-08-19  0:03 ` sashiko-bot
2026-08-19  5:48 ` Chao Gao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.