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 19struct test_case { 20 uint64_t tsc_offset; 21}; 22 23static struct test_case test_cases[] = { 24 { 0 }, 25 { 180 * NSEC_PER_SEC }, 26 { -180 * NSEC_PER_SEC }, 27}; 28 29static 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 36static 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 42static uint64_t guest_read_system_counter(struct test_case *test) 43{ 44 return rdtsc(); 45} 46 47static 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 61static 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 72static 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 84static void handle_abort(struct ucall *uc) 85{ 86 REPORT_GUEST_ASSERT(*uc); 87} 88 89static 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", 112 get_ucall(vcpu, &uc)); 113 } 114 } 115} 116 117int 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 125 enter_guest(vcpu); 126 kvm_vm_free(vm); 127} 128