Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * svm_vmcall_test
0004  *
0005  * Copyright © 2021 Amazon.com, Inc. or its affiliates.
0006  *
0007  * Xen shared_info / pvclock testing
0008  */
0009 
0010 #include "test_util.h"
0011 #include "kvm_util.h"
0012 #include "processor.h"
0013 
0014 #include <stdint.h>
0015 #include <time.h>
0016 #include <sched.h>
0017 #include <signal.h>
0018 #include <pthread.h>
0019 
0020 #define NR_TEST_VCPUS 20
0021 
0022 static struct kvm_vm *vm;
0023 pthread_spinlock_t create_lock;
0024 
0025 #define TEST_TSC_KHZ    2345678UL
0026 #define TEST_TSC_OFFSET 200000000
0027 
0028 uint64_t tsc_sync;
0029 static void guest_code(void)
0030 {
0031     uint64_t start_tsc, local_tsc, tmp;
0032 
0033     start_tsc = rdtsc();
0034     do {
0035         tmp = READ_ONCE(tsc_sync);
0036         local_tsc = rdtsc();
0037         WRITE_ONCE(tsc_sync, local_tsc);
0038         if (unlikely(local_tsc < tmp))
0039             GUEST_SYNC_ARGS(0, local_tsc, tmp, 0, 0);
0040 
0041     } while (local_tsc - start_tsc < 5000 * TEST_TSC_KHZ);
0042 
0043     GUEST_DONE();
0044 }
0045 
0046 
0047 static void *run_vcpu(void *_cpu_nr)
0048 {
0049     unsigned long vcpu_id = (unsigned long)_cpu_nr;
0050     unsigned long failures = 0;
0051     static bool first_cpu_done;
0052     struct kvm_vcpu *vcpu;
0053 
0054     /* The kernel is fine, but vm_vcpu_add() needs locking */
0055     pthread_spin_lock(&create_lock);
0056 
0057     vcpu = vm_vcpu_add(vm, vcpu_id, guest_code);
0058 
0059     if (!first_cpu_done) {
0060         first_cpu_done = true;
0061         vcpu_set_msr(vcpu, MSR_IA32_TSC, TEST_TSC_OFFSET);
0062     }
0063 
0064     pthread_spin_unlock(&create_lock);
0065 
0066     for (;;) {
0067         volatile struct kvm_run *run = vcpu->run;
0068                 struct ucall uc;
0069 
0070         vcpu_run(vcpu);
0071                 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0072                             "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
0073                             run->exit_reason,
0074                             exit_reason_str(run->exit_reason));
0075 
0076         switch (get_ucall(vcpu, &uc)) {
0077                 case UCALL_DONE:
0078             goto out;
0079 
0080                 case UCALL_SYNC:
0081             printf("Guest %d sync %lx %lx %ld\n", vcpu->id,
0082                    uc.args[2], uc.args[3], uc.args[2] - uc.args[3]);
0083             failures++;
0084             break;
0085 
0086                 default:
0087                         TEST_FAIL("Unknown ucall %lu", uc.cmd);
0088         }
0089     }
0090  out:
0091     return (void *)failures;
0092 }
0093 
0094 int main(int argc, char *argv[])
0095 {
0096     TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_TSC_CONTROL));
0097 
0098     vm = vm_create(NR_TEST_VCPUS);
0099     vm_ioctl(vm, KVM_SET_TSC_KHZ, (void *) TEST_TSC_KHZ);
0100 
0101     pthread_spin_init(&create_lock, PTHREAD_PROCESS_PRIVATE);
0102     pthread_t cpu_threads[NR_TEST_VCPUS];
0103     unsigned long cpu;
0104     for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++)
0105         pthread_create(&cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);
0106 
0107     unsigned long failures = 0;
0108     for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++) {
0109         void *this_cpu_failures;
0110         pthread_join(cpu_threads[cpu], &this_cpu_failures);
0111         failures += (unsigned long)this_cpu_failures;
0112     }
0113 
0114     TEST_ASSERT(!failures, "TSC sync failed");
0115     pthread_spin_destroy(&create_lock);
0116     kvm_vm_free(vm);
0117     return 0;
0118 }