cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

system_counter_offset_test.c (2765B)


      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#define VCPU_ID 0
     18
     19#ifdef __x86_64__
     20
     21struct test_case {
     22	uint64_t tsc_offset;
     23};
     24
     25static struct test_case test_cases[] = {
     26	{ 0 },
     27	{ 180 * NSEC_PER_SEC },
     28	{ -180 * NSEC_PER_SEC },
     29};
     30
     31static void check_preconditions(struct kvm_vm *vm)
     32{
     33	if (!_vcpu_has_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET))
     34		return;
     35
     36	print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test");
     37	exit(KSFT_SKIP);
     38}
     39
     40static void setup_system_counter(struct kvm_vm *vm, struct test_case *test)
     41{
     42	vcpu_access_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL,
     43				KVM_VCPU_TSC_OFFSET, &test->tsc_offset, true);
     44}
     45
     46static uint64_t guest_read_system_counter(struct test_case *test)
     47{
     48	return rdtsc();
     49}
     50
     51static uint64_t host_read_guest_system_counter(struct test_case *test)
     52{
     53	return rdtsc() + test->tsc_offset;
     54}
     55
     56#else /* __x86_64__ */
     57
     58#error test not implemented for this architecture!
     59
     60#endif
     61
     62#define GUEST_SYNC_CLOCK(__stage, __val)			\
     63		GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
     64
     65static void guest_main(void)
     66{
     67	int i;
     68
     69	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
     70		struct test_case *test = &test_cases[i];
     71
     72		GUEST_SYNC_CLOCK(i, guest_read_system_counter(test));
     73	}
     74}
     75
     76static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end)
     77{
     78	uint64_t obs = uc->args[2];
     79
     80	TEST_ASSERT(start <= obs && obs <= end,
     81		    "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]",
     82		    obs, start, end);
     83
     84	pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n",
     85		obs, start, end);
     86}
     87
     88static void handle_abort(struct ucall *uc)
     89{
     90	TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0],
     91		  __FILE__, uc->args[1]);
     92}
     93
     94static void enter_guest(struct kvm_vm *vm)
     95{
     96	uint64_t start, end;
     97	struct ucall uc;
     98	int i;
     99
    100	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
    101		struct test_case *test = &test_cases[i];
    102
    103		setup_system_counter(vm, test);
    104		start = host_read_guest_system_counter(test);
    105		vcpu_run(vm, VCPU_ID);
    106		end = host_read_guest_system_counter(test);
    107
    108		switch (get_ucall(vm, VCPU_ID, &uc)) {
    109		case UCALL_SYNC:
    110			handle_sync(&uc, start, end);
    111			break;
    112		case UCALL_ABORT:
    113			handle_abort(&uc);
    114			return;
    115		default:
    116			TEST_ASSERT(0, "unhandled ucall %ld\n",
    117				    get_ucall(vm, VCPU_ID, &uc));
    118		}
    119	}
    120}
    121
    122int main(void)
    123{
    124	struct kvm_vm *vm;
    125
    126	vm = vm_create_default(VCPU_ID, 0, guest_main);
    127	check_preconditions(vm);
    128	ucall_init(vm, NULL);
    129
    130	enter_guest(vm);
    131	kvm_vm_free(vm);
    132}