1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Test edge cases and race conditions in kvm_recalculate_apic_map(). 4 */ 5 6 #include <sys/ioctl.h> 7 #include <pthread.h> 8 #include <time.h> 9 10 #include "processor.h" 11 #include "test_util.h" 12 #include "kvm_util.h" 13 #include "apic.h" 14 15 #define TIMEOUT 5 /* seconds */ 16 17 #define LAPIC_DISABLED 0 18 #define LAPIC_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) 19 #define MAX_XAPIC_ID 0xff 20 21 static void *race(void *arg) 22 { 23 struct kvm_lapic_state lapic = {}; 24 struct kvm_vcpu *vcpu = arg; 25 26 while (1) { 27 /* Trigger kvm_recalculate_apic_map(). */ 28 vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic); 29 pthread_testcancel(); 30 } 31 32 return NULL; 33 } 34 35 int main(void) 36 { 37 struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; 38 struct kvm_vcpu *vcpuN; 39 struct kvm_vm *vm; 40 pthread_t thread; 41 time_t t; 42 int i; 43 44 kvm_static_assert(KVM_MAX_VCPUS > MAX_XAPIC_ID); 45 46 /* 47 * Create the max number of vCPUs supported by selftests so that KVM 48 * has decent amount of work to do when recalculating the map, i.e. to 49 * make the problematic window large enough to hit. 50 */ 51 vm = vm_create_with_vcpus(KVM_MAX_VCPUS, NULL, vcpus); 52 53 /* 54 * Enable x2APIC on all vCPUs so that KVM doesn't bail from the recalc 55 * due to vCPUs having aliased xAPIC IDs (truncated to 8 bits). 56 */ 57 for (i = 0; i < KVM_MAX_VCPUS; i++) 58 vcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC); 59 60 TEST_ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0); 61 62 vcpuN = vcpus[KVM_MAX_VCPUS - 1]; 63 for (t = time(NULL) + TIMEOUT; time(NULL) < t;) { 64 vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_X2APIC); 65 vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED); 66 } 67 68 TEST_ASSERT_EQ(pthread_cancel(thread), 0); 69 TEST_ASSERT_EQ(pthread_join(thread, NULL), 0); 70 71 kvm_vm_free(vm); 72 73 return 0; 74 } 75