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 
29*10f0b222SSean Christopherson static void check_preconditions(struct kvm_vcpu *vcpu)
303f9808caSOliver Upton {
31*10f0b222SSean Christopherson 	if (!__vcpu_has_device_attr(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL,
32*10f0b222SSean Christopherson 				    KVM_VCPU_TSC_OFFSET))
333f9808caSOliver Upton 		return;
343f9808caSOliver Upton 
353f9808caSOliver Upton 	print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test");
363f9808caSOliver Upton 	exit(KSFT_SKIP);
373f9808caSOliver Upton }
383f9808caSOliver Upton 
39*10f0b222SSean Christopherson static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test)
403f9808caSOliver Upton {
41*10f0b222SSean Christopherson 	vcpu_device_attr_set(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL,
4240918184SSean Christopherson 			     KVM_VCPU_TSC_OFFSET, &test->tsc_offset);
433f9808caSOliver Upton }
443f9808caSOliver Upton 
453f9808caSOliver Upton static uint64_t guest_read_system_counter(struct test_case *test)
463f9808caSOliver Upton {
473f9808caSOliver Upton 	return rdtsc();
483f9808caSOliver Upton }
493f9808caSOliver Upton 
503f9808caSOliver Upton static uint64_t host_read_guest_system_counter(struct test_case *test)
513f9808caSOliver Upton {
523f9808caSOliver Upton 	return rdtsc() + test->tsc_offset;
533f9808caSOliver Upton }
543f9808caSOliver Upton 
553f9808caSOliver Upton #else /* __x86_64__ */
563f9808caSOliver Upton 
573f9808caSOliver Upton #error test not implemented for this architecture!
583f9808caSOliver Upton 
593f9808caSOliver Upton #endif
603f9808caSOliver Upton 
613f9808caSOliver Upton #define GUEST_SYNC_CLOCK(__stage, __val)			\
623f9808caSOliver Upton 		GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
633f9808caSOliver Upton 
643f9808caSOliver Upton static void guest_main(void)
653f9808caSOliver Upton {
663f9808caSOliver Upton 	int i;
673f9808caSOliver Upton 
683f9808caSOliver Upton 	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
693f9808caSOliver Upton 		struct test_case *test = &test_cases[i];
703f9808caSOliver Upton 
713f9808caSOliver Upton 		GUEST_SYNC_CLOCK(i, guest_read_system_counter(test));
723f9808caSOliver Upton 	}
733f9808caSOliver Upton }
743f9808caSOliver Upton 
753f9808caSOliver Upton static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end)
763f9808caSOliver Upton {
773f9808caSOliver Upton 	uint64_t obs = uc->args[2];
783f9808caSOliver Upton 
793f9808caSOliver Upton 	TEST_ASSERT(start <= obs && obs <= end,
803f9808caSOliver Upton 		    "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]",
813f9808caSOliver Upton 		    obs, start, end);
823f9808caSOliver Upton 
833f9808caSOliver Upton 	pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n",
843f9808caSOliver Upton 		obs, start, end);
853f9808caSOliver Upton }
863f9808caSOliver Upton 
873f9808caSOliver Upton static void handle_abort(struct ucall *uc)
883f9808caSOliver Upton {
893f9808caSOliver Upton 	TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0],
903f9808caSOliver Upton 		  __FILE__, uc->args[1]);
913f9808caSOliver Upton }
923f9808caSOliver Upton 
93*10f0b222SSean Christopherson static void enter_guest(struct kvm_vcpu *vcpu)
943f9808caSOliver Upton {
953f9808caSOliver Upton 	uint64_t start, end;
963f9808caSOliver Upton 	struct ucall uc;
973f9808caSOliver Upton 	int i;
983f9808caSOliver Upton 
993f9808caSOliver Upton 	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
1003f9808caSOliver Upton 		struct test_case *test = &test_cases[i];
1013f9808caSOliver Upton 
102*10f0b222SSean Christopherson 		setup_system_counter(vcpu, test);
1033f9808caSOliver Upton 		start = host_read_guest_system_counter(test);
104*10f0b222SSean Christopherson 		vcpu_run(vcpu->vm, vcpu->id);
1053f9808caSOliver Upton 		end = host_read_guest_system_counter(test);
1063f9808caSOliver Upton 
107*10f0b222SSean Christopherson 		switch (get_ucall(vcpu->vm, vcpu->id, &uc)) {
1083f9808caSOliver Upton 		case UCALL_SYNC:
1093f9808caSOliver Upton 			handle_sync(&uc, start, end);
1103f9808caSOliver Upton 			break;
1113f9808caSOliver Upton 		case UCALL_ABORT:
1123f9808caSOliver Upton 			handle_abort(&uc);
1133f9808caSOliver Upton 			return;
1143f9808caSOliver Upton 		default:
1153f9808caSOliver Upton 			TEST_ASSERT(0, "unhandled ucall %ld\n",
116*10f0b222SSean Christopherson 				    get_ucall(vcpu->vm, vcpu->id, &uc));
1173f9808caSOliver Upton 		}
1183f9808caSOliver Upton 	}
1193f9808caSOliver Upton }
1203f9808caSOliver Upton 
1213f9808caSOliver Upton int main(void)
1223f9808caSOliver Upton {
123*10f0b222SSean Christopherson 	struct kvm_vcpu *vcpu;
1243f9808caSOliver Upton 	struct kvm_vm *vm;
1253f9808caSOliver Upton 
126*10f0b222SSean Christopherson 	vm = vm_create_with_one_vcpu(&vcpu, guest_main);
127*10f0b222SSean Christopherson 	check_preconditions(vcpu);
1283f9808caSOliver Upton 	ucall_init(vm, NULL);
1293f9808caSOliver Upton 
130*10f0b222SSean Christopherson 	enter_guest(vcpu);
1313f9808caSOliver Upton 	kvm_vm_free(vm);
1323f9808caSOliver Upton }
133