brintos

brintos / linux-shallow public Read only

0
0
Text · 2.6 KiB · 513d421 Raw
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