1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021, Google LLC. 4 * 5 * Tests for adjusting the KVM clock from userspace 6 */ 7 #include <asm/kvm_para.h> 8 #include <asm/pvclock.h> 9 #include <asm/pvclock-abi.h> 10 #include <stdint.h> 11 #include <string.h> 12 #include <sys/stat.h> 13 #include <time.h> 14 15 #include "test_util.h" 16 #include "kvm_util.h" 17 #include "processor.h" 18 19 struct test_case { 20 uint64_t kvmclock_base; 21 int64_t realtime_offset; 22 }; 23 24 static struct test_case test_cases[] = { 25 { .kvmclock_base = 0 }, 26 { .kvmclock_base = 180 * NSEC_PER_SEC }, 27 { .kvmclock_base = 0, .realtime_offset = -180 * NSEC_PER_SEC }, 28 { .kvmclock_base = 0, .realtime_offset = 180 * NSEC_PER_SEC }, 29 }; 30 31 #define GUEST_SYNC_CLOCK(__stage, __val) \ 32 GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0) 33 34 static void guest_main(vm_paddr_t pvti_pa, struct pvclock_vcpu_time_info *pvti) 35 { 36 int i; 37 38 wrmsr(MSR_KVM_SYSTEM_TIME_NEW, pvti_pa | KVM_MSR_ENABLED); 39 for (i = 0; i < ARRAY_SIZE(test_cases); i++) 40 GUEST_SYNC_CLOCK(i, __pvclock_read_cycles(pvti, rdtsc())); 41 } 42 43 #define EXPECTED_FLAGS (KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC) 44 45 static inline void assert_flags(struct kvm_clock_data *data) 46 { 47 TEST_ASSERT((data->flags & EXPECTED_FLAGS) == EXPECTED_FLAGS, 48 "unexpected clock data flags: %x (want set: %x)", 49 data->flags, EXPECTED_FLAGS); 50 } 51 52 static void handle_sync(struct ucall *uc, struct kvm_clock_data *start, 53 struct kvm_clock_data *end) 54 { 55 uint64_t obs, exp_lo, exp_hi; 56 57 obs = uc->args[2]; 58 exp_lo = start->clock; 59 exp_hi = end->clock; 60 61 assert_flags(start); 62 assert_flags(end); 63 64 TEST_ASSERT(exp_lo <= obs && obs <= exp_hi, 65 "unexpected kvm-clock value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]", 66 obs, exp_lo, exp_hi); 67 68 pr_info("kvm-clock value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n", 69 obs, exp_lo, exp_hi); 70 } 71 72 static void handle_abort(struct ucall *uc) 73 { 74 REPORT_GUEST_ASSERT(*uc); 75 } 76 77 static void setup_clock(struct kvm_vm *vm, struct test_case *test_case) 78 { 79 struct kvm_clock_data data; 80 81 memset(&data, 0, sizeof(data)); 82 83 data.clock = test_case->kvmclock_base; 84 if (test_case->realtime_offset) { 85 struct timespec ts; 86 int r; 87 88 data.flags |= KVM_CLOCK_REALTIME; 89 do { 90 r = clock_gettime(CLOCK_REALTIME, &ts); 91 if (!r) 92 break; 93 } while (errno == EINTR); 94 95 TEST_ASSERT(!r, "clock_gettime() failed: %d\n", r); 96 97 data.realtime = ts.tv_sec * NSEC_PER_SEC; 98 data.realtime += ts.tv_nsec; 99 data.realtime += test_case->realtime_offset; 100 } 101 102 vm_ioctl(vm, KVM_SET_CLOCK, &data); 103 } 104 105 static void enter_guest(struct kvm_vcpu *vcpu) 106 { 107 struct kvm_clock_data start, end; 108 struct kvm_vm *vm = vcpu->vm; 109 struct ucall uc; 110 int i; 111 112 for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 113 setup_clock(vm, &test_cases[i]); 114 115 vm_ioctl(vm, KVM_GET_CLOCK, &start); 116 117 vcpu_run(vcpu); 118 vm_ioctl(vm, KVM_GET_CLOCK, &end); 119 120 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); 121 122 switch (get_ucall(vcpu, &uc)) { 123 case UCALL_SYNC: 124 handle_sync(&uc, &start, &end); 125 break; 126 case UCALL_ABORT: 127 handle_abort(&uc); 128 return; 129 default: 130 TEST_ASSERT(0, "unhandled ucall: %ld\n", uc.cmd); 131 } 132 } 133 } 134 135 #define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource" 136 137 static void check_clocksource(void) 138 { 139 char *clk_name; 140 struct stat st; 141 FILE *fp; 142 143 fp = fopen(CLOCKSOURCE_PATH, "r"); 144 if (!fp) { 145 pr_info("failed to open clocksource file: %d; assuming TSC.\n", 146 errno); 147 return; 148 } 149 150 if (fstat(fileno(fp), &st)) { 151 pr_info("failed to stat clocksource file: %d; assuming TSC.\n", 152 errno); 153 goto out; 154 } 155 156 clk_name = malloc(st.st_size); 157 TEST_ASSERT(clk_name, "failed to allocate buffer to read file\n"); 158 159 if (!fgets(clk_name, st.st_size, fp)) { 160 pr_info("failed to read clocksource file: %d; assuming TSC.\n", 161 ferror(fp)); 162 goto out; 163 } 164 165 TEST_ASSERT(!strncmp(clk_name, "tsc\n", st.st_size), 166 "clocksource not supported: %s", clk_name); 167 out: 168 fclose(fp); 169 } 170 171 int main(void) 172 { 173 struct kvm_vcpu *vcpu; 174 vm_vaddr_t pvti_gva; 175 vm_paddr_t pvti_gpa; 176 struct kvm_vm *vm; 177 int flags; 178 179 flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK); 180 TEST_REQUIRE(flags & KVM_CLOCK_REALTIME); 181 182 check_clocksource(); 183 184 vm = vm_create_with_one_vcpu(&vcpu, guest_main); 185 186 pvti_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000); 187 pvti_gpa = addr_gva2gpa(vm, pvti_gva); 188 vcpu_args_set(vcpu, 2, pvti_gpa, pvti_gva); 189 190 enter_guest(vcpu); 191 kvm_vm_free(vm); 192 } 193