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

tsc_scaling_sync.c (2920B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * svm_vmcall_test
      4 *
      5 * Copyright © 2021 Amazon.com, Inc. or its affiliates.
      6 *
      7 * Xen shared_info / pvclock testing
      8 */
      9
     10#include "test_util.h"
     11#include "kvm_util.h"
     12#include "processor.h"
     13
     14#include <stdint.h>
     15#include <time.h>
     16#include <sched.h>
     17#include <signal.h>
     18#include <pthread.h>
     19
     20#define NR_TEST_VCPUS 20
     21
     22static struct kvm_vm *vm;
     23pthread_spinlock_t create_lock;
     24
     25#define TEST_TSC_KHZ    2345678UL
     26#define TEST_TSC_OFFSET 200000000
     27
     28uint64_t tsc_sync;
     29static void guest_code(void)
     30{
     31	uint64_t start_tsc, local_tsc, tmp;
     32
     33	start_tsc = rdtsc();
     34	do {
     35		tmp = READ_ONCE(tsc_sync);
     36		local_tsc = rdtsc();
     37		WRITE_ONCE(tsc_sync, local_tsc);
     38		if (unlikely(local_tsc < tmp))
     39			GUEST_SYNC_ARGS(0, local_tsc, tmp, 0, 0);
     40
     41	} while (local_tsc - start_tsc < 5000 * TEST_TSC_KHZ);
     42
     43	GUEST_DONE();
     44}
     45
     46
     47static void *run_vcpu(void *_cpu_nr)
     48{
     49	unsigned long cpu = (unsigned long)_cpu_nr;
     50	unsigned long failures = 0;
     51	static bool first_cpu_done;
     52
     53	/* The kernel is fine, but vm_vcpu_add_default() needs locking */
     54	pthread_spin_lock(&create_lock);
     55
     56	vm_vcpu_add_default(vm, cpu, guest_code);
     57
     58	if (!first_cpu_done) {
     59		first_cpu_done = true;
     60		vcpu_set_msr(vm, cpu, MSR_IA32_TSC, TEST_TSC_OFFSET);
     61	}
     62
     63	pthread_spin_unlock(&create_lock);
     64
     65	for (;;) {
     66		volatile struct kvm_run *run = vcpu_state(vm, cpu);
     67                struct ucall uc;
     68
     69                vcpu_run(vm, cpu);
     70                TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
     71                            "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
     72                            run->exit_reason,
     73                            exit_reason_str(run->exit_reason));
     74
     75                switch (get_ucall(vm, cpu, &uc)) {
     76                case UCALL_DONE:
     77			goto out;
     78
     79                case UCALL_SYNC:
     80			printf("Guest %ld sync %lx %lx %ld\n", cpu, uc.args[2], uc.args[3], uc.args[2] - uc.args[3]);
     81			failures++;
     82			break;
     83
     84                default:
     85                        TEST_FAIL("Unknown ucall %lu", uc.cmd);
     86		}
     87	}
     88 out:
     89	return (void *)failures;
     90}
     91
     92int main(int argc, char *argv[])
     93{
     94        if (!kvm_check_cap(KVM_CAP_VM_TSC_CONTROL)) {
     95		print_skip("KVM_CAP_VM_TSC_CONTROL not available");
     96		exit(KSFT_SKIP);
     97	}
     98
     99	vm = vm_create_default_with_vcpus(0, DEFAULT_STACK_PGS * NR_TEST_VCPUS, 0, guest_code, NULL);
    100	vm_ioctl(vm, KVM_SET_TSC_KHZ, (void *) TEST_TSC_KHZ);
    101
    102	pthread_spin_init(&create_lock, PTHREAD_PROCESS_PRIVATE);
    103	pthread_t cpu_threads[NR_TEST_VCPUS];
    104	unsigned long cpu;
    105	for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++)
    106		pthread_create(&cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);
    107
    108	unsigned long failures = 0;
    109	for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++) {
    110		void *this_cpu_failures;
    111		pthread_join(cpu_threads[cpu], &this_cpu_failures);
    112		failures += (unsigned long)this_cpu_failures;
    113	}
    114
    115	TEST_ASSERT(!failures, "TSC sync failed");
    116	pthread_spin_destroy(&create_lock);
    117	kvm_vm_free(vm);
    118	return 0;
    119}