Skip to content

Commit eb98192

Browse files
esposemsean-jc
authored andcommitted
KVM: selftests: Verify APIC_ID is set when forcing x2APIC=>xAPIC transition
Add a sub-test to verify that KVM stuffs the APIC_ID when userspace forces a transition from x2APIC to xAPIC without first disabling the APIC. Such a transition is architecturally disallowed (WRMSR will #GP), but needs to be handled by KVM to allow userspace to emulate RESET (ignoring that userspace should also stuff local APIC state on RESET). Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> Link: https://lore.kernel.org/r/20230109130605.2013555-3-eesposit@redhat.com Co-developed-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 052c3b9 commit eb98192

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

tools/testing/selftests/kvm/x86_64/xapic_state_test.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,59 @@ static void test_icr(struct xapic_vcpu *x)
132132
__test_icr(x, -1ull & ~APIC_DM_FIXED_MASK);
133133
}
134134

135+
static void __test_apic_id(struct kvm_vcpu *vcpu, uint64_t apic_base)
136+
{
137+
uint32_t apic_id, expected;
138+
struct kvm_lapic_state xapic;
139+
140+
vcpu_set_msr(vcpu, MSR_IA32_APICBASE, apic_base);
141+
142+
vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic);
143+
144+
expected = apic_base & X2APIC_ENABLE ? vcpu->id : vcpu->id << 24;
145+
apic_id = *((u32 *)&xapic.regs[APIC_ID]);
146+
147+
TEST_ASSERT(apic_id == expected,
148+
"APIC_ID not set back to %s format; wanted = %x, got = %x",
149+
(apic_base & X2APIC_ENABLE) ? "x2APIC" : "xAPIC",
150+
expected, apic_id);
151+
}
152+
153+
/*
154+
* Verify that KVM switches the APIC_ID between xAPIC and x2APIC when userspace
155+
* stuffs MSR_IA32_APICBASE. Setting the APIC_ID when x2APIC is enabled and
156+
* when the APIC transitions for DISABLED to ENABLED is architectural behavior
157+
* (on Intel), whereas the x2APIC => xAPIC transition behavior is KVM ABI since
158+
* attempted to transition from x2APIC to xAPIC without disabling the APIC is
159+
* architecturally disallowed.
160+
*/
161+
static void test_apic_id(void)
162+
{
163+
const uint32_t NR_VCPUS = 3;
164+
struct kvm_vcpu *vcpus[NR_VCPUS];
165+
uint64_t apic_base;
166+
struct kvm_vm *vm;
167+
int i;
168+
169+
vm = vm_create_with_vcpus(NR_VCPUS, NULL, vcpus);
170+
vm_enable_cap(vm, KVM_CAP_X2APIC_API, KVM_X2APIC_API_USE_32BIT_IDS);
171+
172+
for (i = 0; i < NR_VCPUS; i++) {
173+
apic_base = vcpu_get_msr(vcpus[i], MSR_IA32_APICBASE);
174+
175+
TEST_ASSERT(apic_base & MSR_IA32_APICBASE_ENABLE,
176+
"APIC not in ENABLED state at vCPU RESET");
177+
TEST_ASSERT(!(apic_base & X2APIC_ENABLE),
178+
"APIC not in xAPIC mode at vCPU RESET");
179+
180+
__test_apic_id(vcpus[i], apic_base);
181+
__test_apic_id(vcpus[i], apic_base | X2APIC_ENABLE);
182+
__test_apic_id(vcpus[i], apic_base);
183+
}
184+
185+
kvm_vm_free(vm);
186+
}
187+
135188
int main(int argc, char *argv[])
136189
{
137190
struct xapic_vcpu x = {
@@ -157,4 +210,6 @@ int main(int argc, char *argv[])
157210
virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
158211
test_icr(&x);
159212
kvm_vm_free(vm);
213+
214+
test_apic_id();
160215
}

0 commit comments

Comments
 (0)