1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021, Google LLC. 4 * 5 * Tests for adjusting the system counter from userspace 6 */ 7 #include <asm/kvm_para.h> 8 #include <stdint.h> 9 #include <string.h> 10 #include <sys/stat.h> 11 #include <time.h> 12 13 #include "test_util.h" 14 #include "kvm_util.h" 15 #include "processor.h" 16 17 #ifdef __x86_64__ 18 19 struct test_case { 20 uint64_t tsc_offset; 21 }; 22 23 static struct test_case test_cases[] = { 24 { 0 }, 25 { 180 * NSEC_PER_SEC }, 26 { -180 * NSEC_PER_SEC }, 27 }; 28 29 static void check_preconditions(struct kvm_vcpu *vcpu) 30 { 31 __TEST_REQUIRE(!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL, 32 KVM_VCPU_TSC_OFFSET), 33 "KVM_VCPU_TSC_OFFSET not supported; skipping test"); 34 } 35 36 static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test) 37 { 38 vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET, 39 &test->tsc_offset); 40 } 41 42 static uint64_t guest_read_system_counter(struct test_case *test) 43 { 44 return rdtsc(); 45 } 46 47 static uint64_t host_read_guest_system_counter(struct test_case *test) 48 { 49 return rdtsc() + test->tsc_offset; 50 } 51 52 #else /* __x86_64__ */ 53 54 #error test not implemented for this architecture! 55 56 #endif 57 58 #define GUEST_SYNC_CLOCK(__stage, __val) \ 59 GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0) 60 61 static void guest_main(void) 62 { 63 int i; 64 65 for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 66 struct test_case *test = &test_cases[i]; 67 68 GUEST_SYNC_CLOCK(i, guest_read_system_counter(test)); 69 } 70 } 71 72 static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end) 73 { 74 uint64_t obs = uc->args[2]; 75 76 TEST_ASSERT(start <= obs && obs <= end, 77 "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]", 78 obs, start, end); 79 80 pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n", 81 obs, start, end); 82 } 83 84 static void handle_abort(struct ucall *uc) 85 { 86 REPORT_GUEST_ASSERT(*uc); 87 } 88 89 static void enter_guest(struct kvm_vcpu *vcpu) 90 { 91 uint64_t start, end; 92 struct ucall uc; 93 int i; 94 95 for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 96 struct test_case *test = &test_cases[i]; 97 98 setup_system_counter(vcpu, test); 99 start = host_read_guest_system_counter(test); 100 vcpu_run(vcpu); 101 end = host_read_guest_system_counter(test); 102 103 switch (get_ucall(vcpu, &uc)) { 104 case UCALL_SYNC: 105 handle_sync(&uc, start, end); 106 break; 107 case UCALL_ABORT: 108 handle_abort(&uc); 109 return; 110 default: 111 TEST_ASSERT(0, "unhandled ucall %ld\n", 112 get_ucall(vcpu, &uc)); 113 } 114 } 115 } 116 117 int main(void) 118 { 119 struct kvm_vcpu *vcpu; 120 struct kvm_vm *vm; 121 122 vm = vm_create_with_one_vcpu(&vcpu, guest_main); 123 check_preconditions(vcpu); 124 ucall_init(vm, NULL); 125 126 enter_guest(vcpu); 127 kvm_vm_free(vm); 128 } 129