128 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2021, Google LLC.4 *5 * Tests for adjusting the system counter from userspace6 */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#endif57 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