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_run *run = vcpu->run; 109 struct kvm_vm *vm = vcpu->vm; 110 struct ucall uc; 111 int i; 112 113 for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 114 setup_clock(vm, &test_cases[i]); 115 116 vm_ioctl(vm, KVM_GET_CLOCK, &start); 117 118 vcpu_run(vcpu); 119 vm_ioctl(vm, KVM_GET_CLOCK, &end); 120 121 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, 122 "unexpected exit reason: %u (%s)", 123 run->exit_reason, exit_reason_str(run->exit_reason)); 124 125 switch (get_ucall(vcpu, &uc)) { 126 case UCALL_SYNC: 127 handle_sync(&uc, &start, &end); 128 break; 129 case UCALL_ABORT: 130 handle_abort(&uc); 131 return; 132 default: 133 TEST_ASSERT(0, "unhandled ucall: %ld\n", uc.cmd); 134 } 135 } 136 } 137 138 #define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource" 139 140 static void check_clocksource(void) 141 { 142 char *clk_name; 143 struct stat st; 144 FILE *fp; 145 146 fp = fopen(CLOCKSOURCE_PATH, "r"); 147 if (!fp) { 148 pr_info("failed to open clocksource file: %d; assuming TSC.\n", 149 errno); 150 return; 151 } 152 153 if (fstat(fileno(fp), &st)) { 154 pr_info("failed to stat clocksource file: %d; assuming TSC.\n", 155 errno); 156 goto out; 157 } 158 159 clk_name = malloc(st.st_size); 160 TEST_ASSERT(clk_name, "failed to allocate buffer to read file\n"); 161 162 if (!fgets(clk_name, st.st_size, fp)) { 163 pr_info("failed to read clocksource file: %d; assuming TSC.\n", 164 ferror(fp)); 165 goto out; 166 } 167 168 TEST_ASSERT(!strncmp(clk_name, "tsc\n", st.st_size), 169 "clocksource not supported: %s", clk_name); 170 out: 171 fclose(fp); 172 } 173 174 int main(void) 175 { 176 struct kvm_vcpu *vcpu; 177 vm_vaddr_t pvti_gva; 178 vm_paddr_t pvti_gpa; 179 struct kvm_vm *vm; 180 int flags; 181 182 flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK); 183 TEST_REQUIRE(flags & KVM_CLOCK_REALTIME); 184 185 check_clocksource(); 186 187 vm = vm_create_with_one_vcpu(&vcpu, guest_main); 188 189 pvti_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000); 190 pvti_gpa = addr_gva2gpa(vm, pvti_gva); 191 vcpu_args_set(vcpu, 2, pvti_gpa, pvti_gva); 192 193 enter_guest(vcpu); 194 kvm_vm_free(vm); 195 } 196