1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright © 2021 Amazon.com, Inc. or its affiliates.
16 #define NR_TEST_VCPUS 20
18 static struct kvm_vm
*vm
;
19 pthread_spinlock_t create_lock
;
21 #define TEST_TSC_KHZ 2345678UL
22 #define TEST_TSC_OFFSET 200000000
25 static void guest_code(void)
27 uint64_t start_tsc
, local_tsc
, tmp
;
31 tmp
= READ_ONCE(tsc_sync
);
33 WRITE_ONCE(tsc_sync
, local_tsc
);
34 if (unlikely(local_tsc
< tmp
))
35 GUEST_SYNC_ARGS(0, local_tsc
, tmp
, 0, 0);
37 } while (local_tsc
- start_tsc
< 5000 * TEST_TSC_KHZ
);
43 static void *run_vcpu(void *_cpu_nr
)
45 unsigned long vcpu_id
= (unsigned long)_cpu_nr
;
46 unsigned long failures
= 0;
47 static bool first_cpu_done
;
48 struct kvm_vcpu
*vcpu
;
50 /* The kernel is fine, but vm_vcpu_add() needs locking */
51 pthread_spin_lock(&create_lock
);
53 vcpu
= vm_vcpu_add(vm
, vcpu_id
, guest_code
);
55 if (!first_cpu_done
) {
56 first_cpu_done
= true;
57 vcpu_set_msr(vcpu
, MSR_IA32_TSC
, TEST_TSC_OFFSET
);
60 pthread_spin_unlock(&create_lock
);
66 TEST_ASSERT_KVM_EXIT_REASON(vcpu
, KVM_EXIT_IO
);
68 switch (get_ucall(vcpu
, &uc
)) {
73 printf("Guest %d sync %lx %lx %ld\n", vcpu
->id
,
74 uc
.args
[2], uc
.args
[3], uc
.args
[2] - uc
.args
[3]);
79 TEST_FAIL("Unknown ucall %lu", uc
.cmd
);
83 return (void *)failures
;
86 int main(int argc
, char *argv
[])
88 TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_TSC_CONTROL
));
90 vm
= vm_create(NR_TEST_VCPUS
);
91 vm_ioctl(vm
, KVM_SET_TSC_KHZ
, (void *) TEST_TSC_KHZ
);
93 pthread_spin_init(&create_lock
, PTHREAD_PROCESS_PRIVATE
);
94 pthread_t cpu_threads
[NR_TEST_VCPUS
];
96 for (cpu
= 0; cpu
< NR_TEST_VCPUS
; cpu
++)
97 pthread_create(&cpu_threads
[cpu
], NULL
, run_vcpu
, (void *)cpu
);
99 unsigned long failures
= 0;
100 for (cpu
= 0; cpu
< NR_TEST_VCPUS
; cpu
++) {
101 void *this_cpu_failures
;
102 pthread_join(cpu_threads
[cpu
], &this_cpu_failures
);
103 failures
+= (unsigned long)this_cpu_failures
;
106 TEST_ASSERT(!failures
, "TSC sync failed");
107 pthread_spin_destroy(&create_lock
);