13f9808caSOliver Upton // SPDX-License-Identifier: GPL-2.0-only
23f9808caSOliver Upton /*
33f9808caSOliver Upton * Copyright (C) 2021, Google LLC.
43f9808caSOliver Upton *
53f9808caSOliver Upton * Tests for adjusting the system counter from userspace
63f9808caSOliver Upton */
73f9808caSOliver Upton #include <asm/kvm_para.h>
83f9808caSOliver Upton #include <stdint.h>
93f9808caSOliver Upton #include <string.h>
103f9808caSOliver Upton #include <sys/stat.h>
113f9808caSOliver Upton #include <time.h>
123f9808caSOliver Upton
133f9808caSOliver Upton #include "test_util.h"
143f9808caSOliver Upton #include "kvm_util.h"
153f9808caSOliver Upton #include "processor.h"
163f9808caSOliver Upton
173f9808caSOliver Upton #ifdef __x86_64__
183f9808caSOliver Upton
193f9808caSOliver Upton struct test_case {
203f9808caSOliver Upton uint64_t tsc_offset;
213f9808caSOliver Upton };
223f9808caSOliver Upton
233f9808caSOliver Upton static struct test_case test_cases[] = {
243f9808caSOliver Upton { 0 },
253f9808caSOliver Upton { 180 * NSEC_PER_SEC },
263f9808caSOliver Upton { -180 * NSEC_PER_SEC },
273f9808caSOliver Upton };
283f9808caSOliver Upton
check_preconditions(struct kvm_vcpu * vcpu)2910f0b222SSean Christopherson static void check_preconditions(struct kvm_vcpu *vcpu)
303f9808caSOliver Upton {
317ed397d1SSean Christopherson __TEST_REQUIRE(!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,
327ed397d1SSean Christopherson KVM_VCPU_TSC_OFFSET),
337ed397d1SSean Christopherson "KVM_VCPU_TSC_OFFSET not supported; skipping test");
343f9808caSOliver Upton }
353f9808caSOliver Upton
setup_system_counter(struct kvm_vcpu * vcpu,struct test_case * test)3610f0b222SSean Christopherson static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test)
373f9808caSOliver Upton {
38768e9a61SSean Christopherson vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,
39768e9a61SSean Christopherson &test->tsc_offset);
403f9808caSOliver Upton }
413f9808caSOliver Upton
guest_read_system_counter(struct test_case * test)423f9808caSOliver Upton static uint64_t guest_read_system_counter(struct test_case *test)
433f9808caSOliver Upton {
443f9808caSOliver Upton return rdtsc();
453f9808caSOliver Upton }
463f9808caSOliver Upton
host_read_guest_system_counter(struct test_case * test)473f9808caSOliver Upton static uint64_t host_read_guest_system_counter(struct test_case *test)
483f9808caSOliver Upton {
493f9808caSOliver Upton return rdtsc() + test->tsc_offset;
503f9808caSOliver Upton }
513f9808caSOliver Upton
523f9808caSOliver Upton #else /* __x86_64__ */
533f9808caSOliver Upton
543f9808caSOliver Upton #error test not implemented for this architecture!
553f9808caSOliver Upton
563f9808caSOliver Upton #endif
573f9808caSOliver Upton
583f9808caSOliver Upton #define GUEST_SYNC_CLOCK(__stage, __val) \
593f9808caSOliver Upton GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
603f9808caSOliver Upton
guest_main(void)613f9808caSOliver Upton static void guest_main(void)
623f9808caSOliver Upton {
633f9808caSOliver Upton int i;
643f9808caSOliver Upton
653f9808caSOliver Upton for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
663f9808caSOliver Upton struct test_case *test = &test_cases[i];
673f9808caSOliver Upton
683f9808caSOliver Upton GUEST_SYNC_CLOCK(i, guest_read_system_counter(test));
693f9808caSOliver Upton }
703f9808caSOliver Upton }
713f9808caSOliver Upton
handle_sync(struct ucall * uc,uint64_t start,uint64_t end)723f9808caSOliver Upton static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end)
733f9808caSOliver Upton {
743f9808caSOliver Upton uint64_t obs = uc->args[2];
753f9808caSOliver Upton
763f9808caSOliver Upton TEST_ASSERT(start <= obs && obs <= end,
773f9808caSOliver Upton "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]",
783f9808caSOliver Upton obs, start, end);
793f9808caSOliver Upton
803f9808caSOliver Upton pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n",
813f9808caSOliver Upton obs, start, end);
823f9808caSOliver Upton }
833f9808caSOliver Upton
handle_abort(struct ucall * uc)843f9808caSOliver Upton static void handle_abort(struct ucall *uc)
853f9808caSOliver Upton {
86594a1c27SColton Lewis REPORT_GUEST_ASSERT(*uc);
873f9808caSOliver Upton }
883f9808caSOliver Upton
enter_guest(struct kvm_vcpu * vcpu)8910f0b222SSean Christopherson static void enter_guest(struct kvm_vcpu *vcpu)
903f9808caSOliver Upton {
913f9808caSOliver Upton uint64_t start, end;
923f9808caSOliver Upton struct ucall uc;
933f9808caSOliver Upton int i;
943f9808caSOliver Upton
953f9808caSOliver Upton for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
963f9808caSOliver Upton struct test_case *test = &test_cases[i];
973f9808caSOliver Upton
9810f0b222SSean Christopherson setup_system_counter(vcpu, test);
993f9808caSOliver Upton start = host_read_guest_system_counter(test);
100768e9a61SSean Christopherson vcpu_run(vcpu);
1013f9808caSOliver Upton end = host_read_guest_system_counter(test);
1023f9808caSOliver Upton
103768e9a61SSean Christopherson switch (get_ucall(vcpu, &uc)) {
1043f9808caSOliver Upton case UCALL_SYNC:
1053f9808caSOliver Upton handle_sync(&uc, start, end);
1063f9808caSOliver Upton break;
1073f9808caSOliver Upton case UCALL_ABORT:
1083f9808caSOliver Upton handle_abort(&uc);
1093f9808caSOliver Upton return;
1103f9808caSOliver Upton default:
111*250e138dSAndrew Jones TEST_ASSERT(0, "unhandled ucall %ld",
112768e9a61SSean Christopherson get_ucall(vcpu, &uc));
1133f9808caSOliver Upton }
1143f9808caSOliver Upton }
1153f9808caSOliver Upton }
1163f9808caSOliver Upton
main(void)1173f9808caSOliver Upton int main(void)
1183f9808caSOliver Upton {
11910f0b222SSean Christopherson struct kvm_vcpu *vcpu;
1203f9808caSOliver Upton struct kvm_vm *vm;
1213f9808caSOliver Upton
12210f0b222SSean Christopherson vm = vm_create_with_one_vcpu(&vcpu, guest_main);
12310f0b222SSean Christopherson check_preconditions(vcpu);
1243f9808caSOliver Upton
12510f0b222SSean Christopherson enter_guest(vcpu);
1263f9808caSOliver Upton kvm_vm_free(vm);
1273f9808caSOliver Upton }
128