From: Partha Sarathi Satapathy <partha.satapathy@oracle.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>,
Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H . Peter Anvin" <hpa@zytor.com>,
Shuah Khan <shuah@kernel.org>,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
Subject: [PATCH 2/2] KVM: selftests: Cover aliased xAPIC physical IDs
Date: Tue, 27 Oct 2026 05:18:08 +0000 [thread overview]
Message-ID: <20261027051808.243000-2-partha.satapathy@oracle.com> (raw)
In-Reply-To: <20261027051808.243000-1-partha.satapathy@oracle.com>
From: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
The optimized physical APIC map must select the lowest vCPU ID
when multiple xAPIC-mode vCPUs share an effective physical APIC ID.
Extend recalc_apic_map_test with a regression test that enables
KVM_X2APIC_API_USE_32BIT_IDS and creates vCPU 285 before vCPU 29.
Keep both LAPICs in xAPIC mode, where their physical APIC IDs alias
to 0x1d.
Inject an MSI to destination 0x1d and verify that its vector is
pending only in vCPU 29's IRR. This checks lowest-ID selection when
the higher-ID alias is created first.
Signed-off-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
Tested-by: Partha Sarathi Satapathy <partha.satapathy@oracle.com>
Signed-off-by: Partha Sarathi Satapathy <partha.satapathy@oracle.com>
---
.../selftests/kvm/x86/recalc_apic_map_test.c | 98 +++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c b/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c
index cbc92a862ea9..88959adde14d 100644
--- a/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c
+++ b/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c
@@ -18,6 +18,100 @@
#define LAPIC_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)
#define MAX_XAPIC_ID 0xff
+#define ALIAS_LOW_VCPU_ID 29
+#define ALIAS_HIGH_VCPU_ID (ALIAS_LOW_VCPU_ID | 0x100)
+#define ALIAS_VECTOR 0xe1
+#define X86_MSI_BASE_ADDRESS 0xfee00000
+
+static void assert_lapic_xapic_mode(struct kvm_vcpu *vcpu)
+{
+ u64 apicbase = vcpu_get_msr(vcpu, MSR_IA32_APICBASE);
+
+ TEST_ASSERT(apicbase & MSR_IA32_APICBASE_ENABLE,
+ "vCPU %u local APIC is not enabled, APICBASE=%#lx",
+ vcpu->id, (unsigned long)apicbase);
+ TEST_ASSERT(!(apicbase & X2APIC_ENABLE),
+ "vCPU %u unexpectedly entered x2APIC mode, APICBASE=%#lx",
+ vcpu->id, (unsigned long)apicbase);
+}
+
+static void lapic_sw_enable(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic_state lapic;
+
+ vcpu_ioctl(vcpu, KVM_GET_LAPIC, &lapic);
+ *((u32 *)&lapic.regs[APIC_SPIV]) |= APIC_SPIV_APIC_ENABLED;
+ vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic);
+}
+
+static bool lapic_irr_has_vector(struct kvm_vcpu *vcpu, u32 vector)
+{
+ struct kvm_lapic_state lapic;
+ u32 irr;
+
+ vcpu_ioctl(vcpu, KVM_GET_LAPIC, &lapic);
+ irr = *((u32 *)&lapic.regs[APIC_IRR + APIC_VECTOR_TO_REG_OFFSET(vector)]);
+
+ return irr & (1u << APIC_VECTOR_TO_BIT_NUMBER(vector));
+}
+
+static void signal_msi(struct kvm_vm *vm, u32 dest_id, u8 vector)
+{
+ struct kvm_msi msi = {
+ .address_lo = X86_MSI_BASE_ADDRESS | (dest_id << 12),
+ .address_hi = 0,
+ .data = vector,
+ };
+ int r;
+
+ r = __vm_ioctl(vm, KVM_SIGNAL_MSI, &msi);
+ TEST_ASSERT(r == 1, "KVM_SIGNAL_MSI should deliver 1 IRQ, got %d", r);
+}
+
+static void test_xapic_alias_lowest_vcpu_id(void)
+{
+ struct kvm_vcpu *high, *low;
+ struct kvm_vm *vm;
+ bool high_has_irq;
+ bool low_has_irq;
+
+ TEST_REQUIRE(kvm_check_cap(KVM_CAP_X2APIC_API) &
+ KVM_X2APIC_API_USE_32BIT_IDS);
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_SIGNAL_MSI));
+ TEST_REQUIRE(kvm_check_cap(KVM_CAP_MAX_VCPU_ID) > ALIAS_HIGH_VCPU_ID);
+
+ vm = vm_create(2);
+ vm_enable_cap(vm, KVM_CAP_X2APIC_API, KVM_X2APIC_API_USE_32BIT_IDS);
+
+ /*
+ * Reproduce hotplug ordering where the vCPU with x2APIC ID 0x11d is
+ * created before the vCPU with x2APIC ID 0x1d. In xAPIC mode they
+ * alias to physical APIC ID 0x1d. With KVM_X2APIC_API_USE_32BIT_IDS,
+ * KVM's ABI says aliased physical APIC events are delivered only to
+ * the lowest vCPU ID.
+ */
+ high = vm_vcpu_add(vm, ALIAS_HIGH_VCPU_ID, NULL);
+ low = vm_vcpu_add(vm, ALIAS_LOW_VCPU_ID, NULL);
+
+ assert_lapic_xapic_mode(high);
+ assert_lapic_xapic_mode(low);
+
+ lapic_sw_enable(high);
+ lapic_sw_enable(low);
+
+ signal_msi(vm, ALIAS_LOW_VCPU_ID, ALIAS_VECTOR);
+
+ high_has_irq = lapic_irr_has_vector(high, ALIAS_VECTOR);
+ low_has_irq = lapic_irr_has_vector(low, ALIAS_VECTOR);
+
+ TEST_ASSERT(!high_has_irq && low_has_irq,
+ "Aliased xAPIC IRQ delivered to wrong vCPU: high vCPU %u IRR=%u, low vCPU %u IRR=%u",
+ ALIAS_HIGH_VCPU_ID, high_has_irq,
+ ALIAS_LOW_VCPU_ID, low_has_irq);
+
+ kvm_vm_free(vm);
+}
+
static void *race(void *arg)
{
struct kvm_lapic_state lapic = {};
@@ -42,6 +136,10 @@ int main(void)
int i;
kvm_static_assert(KVM_MAX_VCPUS > MAX_XAPIC_ID);
+ kvm_static_assert(ALIAS_HIGH_VCPU_ID > MAX_XAPIC_ID);
+ kvm_static_assert((ALIAS_HIGH_VCPU_ID & MAX_XAPIC_ID) == ALIAS_LOW_VCPU_ID);
+
+ test_xapic_alias_lowest_vcpu_id();
/*
* Create the max number of vCPUs supported by selftests so that KVM
--
2.43.7
next prev parent reply other threads:[~2026-10-27 5:18 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 5:18 [PATCH 1/2] KVM: x86: Select lowest vCPU ID for aliased xAPIC IDs Partha Sarathi Satapathy
2026-10-27 5:18 ` Partha Sarathi Satapathy [this message]
2026-10-27 15:40 ` Sean Christopherson
2026-10-27 19:42 ` Alejandro Jimenez
2026-10-27 20:25 ` 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=20261027051808.243000-2-partha.satapathy@oracle.com \
--to=partha.satapathy@oracle.com \
--cc=alejandro.j.jimenez@oracle.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=shuah@kernel.org \
--cc=tglx@kernel.org \
--cc=x86@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®