111 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright © 2021 Amazon.com, Inc. or its affiliates.4 */5 6#include "test_util.h"7#include "kvm_util.h"8#include "processor.h"9 10#include <stdint.h>11#include <time.h>12#include <sched.h>13#include <signal.h>14#include <pthread.h>15 16#define NR_TEST_VCPUS 2017 18static struct kvm_vm *vm;19pthread_spinlock_t create_lock;20 21#define TEST_TSC_KHZ 2345678UL22#define TEST_TSC_OFFSET 20000000023 24uint64_t tsc_sync;25static void guest_code(void)26{27 uint64_t start_tsc, local_tsc, tmp;28 29 start_tsc = rdtsc();30 do {31 tmp = READ_ONCE(tsc_sync);32 local_tsc = rdtsc();33 WRITE_ONCE(tsc_sync, local_tsc);34 if (unlikely(local_tsc < tmp))35 GUEST_SYNC_ARGS(0, local_tsc, tmp, 0, 0);36 37 } while (local_tsc - start_tsc < 5000 * TEST_TSC_KHZ);38 39 GUEST_DONE();40}41 42 43static void *run_vcpu(void *_cpu_nr)44{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;49 50 /* The kernel is fine, but vm_vcpu_add() needs locking */51 pthread_spin_lock(&create_lock);52 53 vcpu = vm_vcpu_add(vm, vcpu_id, guest_code);54 55 if (!first_cpu_done) {56 first_cpu_done = true;57 vcpu_set_msr(vcpu, MSR_IA32_TSC, TEST_TSC_OFFSET);58 }59 60 pthread_spin_unlock(&create_lock);61 62 for (;;) {63 struct ucall uc;64 65 vcpu_run(vcpu);66 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);67 68 switch (get_ucall(vcpu, &uc)) {69 case UCALL_DONE:70 goto out;71 72 case UCALL_SYNC:73 printf("Guest %d sync %lx %lx %ld\n", vcpu->id,74 uc.args[2], uc.args[3], uc.args[2] - uc.args[3]);75 failures++;76 break;77 78 default:79 TEST_FAIL("Unknown ucall %lu", uc.cmd);80 }81 }82 out:83 return (void *)failures;84}85 86int main(int argc, char *argv[])87{88 TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_TSC_CONTROL));89 90 vm = vm_create(NR_TEST_VCPUS);91 vm_ioctl(vm, KVM_SET_TSC_KHZ, (void *) TEST_TSC_KHZ);92 93 pthread_spin_init(&create_lock, PTHREAD_PROCESS_PRIVATE);94 pthread_t cpu_threads[NR_TEST_VCPUS];95 unsigned long cpu;96 for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++)97 pthread_create(&cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);98 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;104 }105 106 TEST_ASSERT(!failures, "TSC sync failed");107 pthread_spin_destroy(&create_lock);108 kvm_vm_free(vm);109 return 0;110}111