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

set_boot_cpu_id.c (3530B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Test that KVM_SET_BOOT_CPU_ID works as intended
      4 *
      5 * Copyright (C) 2020, Red Hat, Inc.
      6 */
      7#define _GNU_SOURCE /* for program_invocation_name */
      8#include <fcntl.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11#include <string.h>
     12#include <sys/ioctl.h>
     13
     14#include "test_util.h"
     15#include "kvm_util.h"
     16#include "processor.h"
     17#include "apic.h"
     18
     19#define N_VCPU 2
     20#define VCPU_ID0 0
     21#define VCPU_ID1 1
     22
     23static void guest_bsp_vcpu(void *arg)
     24{
     25	GUEST_SYNC(1);
     26
     27	GUEST_ASSERT(get_bsp_flag() != 0);
     28
     29	GUEST_DONE();
     30}
     31
     32static void guest_not_bsp_vcpu(void *arg)
     33{
     34	GUEST_SYNC(1);
     35
     36	GUEST_ASSERT(get_bsp_flag() == 0);
     37
     38	GUEST_DONE();
     39}
     40
     41static void test_set_boot_busy(struct kvm_vm *vm)
     42{
     43	int res;
     44
     45	res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID0);
     46	TEST_ASSERT(res == -1 && errno == EBUSY,
     47			"KVM_SET_BOOT_CPU_ID set while running vm");
     48}
     49
     50static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid)
     51{
     52	struct ucall uc;
     53	int stage;
     54
     55	for (stage = 0; stage < 2; stage++) {
     56
     57		vcpu_run(vm, vcpuid);
     58
     59		switch (get_ucall(vm, vcpuid, &uc)) {
     60		case UCALL_SYNC:
     61			TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
     62					uc.args[1] == stage + 1,
     63					"Stage %d: Unexpected register values vmexit, got %lx",
     64					stage + 1, (ulong)uc.args[1]);
     65			test_set_boot_busy(vm);
     66			break;
     67		case UCALL_DONE:
     68			TEST_ASSERT(stage == 1,
     69					"Expected GUEST_DONE in stage 2, got stage %d",
     70					stage);
     71			break;
     72		case UCALL_ABORT:
     73			TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx",
     74						(const char *)uc.args[0], __FILE__,
     75						uc.args[1], uc.args[2], uc.args[3]);
     76		default:
     77			TEST_ASSERT(false, "Unexpected exit: %s",
     78					exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason));
     79		}
     80	}
     81}
     82
     83static struct kvm_vm *create_vm(void)
     84{
     85	struct kvm_vm *vm;
     86	uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * 2;
     87	uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * N_VCPU;
     88	uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages;
     89
     90	pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, pages);
     91	vm = vm_create(VM_MODE_DEFAULT, pages, O_RDWR);
     92
     93	kvm_vm_elf_load(vm, program_invocation_name);
     94	vm_create_irqchip(vm);
     95
     96	return vm;
     97}
     98
     99static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code)
    100{
    101	if (bsp_code)
    102		vm_vcpu_add_default(vm, vcpuid, guest_bsp_vcpu);
    103	else
    104		vm_vcpu_add_default(vm, vcpuid, guest_not_bsp_vcpu);
    105}
    106
    107static void run_vm_bsp(uint32_t bsp_vcpu)
    108{
    109	struct kvm_vm *vm;
    110	bool is_bsp_vcpu1 = bsp_vcpu == VCPU_ID1;
    111
    112	vm = create_vm();
    113
    114	if (is_bsp_vcpu1)
    115		vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1);
    116
    117	add_x86_vcpu(vm, VCPU_ID0, !is_bsp_vcpu1);
    118	add_x86_vcpu(vm, VCPU_ID1, is_bsp_vcpu1);
    119
    120	run_vcpu(vm, VCPU_ID0);
    121	run_vcpu(vm, VCPU_ID1);
    122
    123	kvm_vm_free(vm);
    124}
    125
    126static void check_set_bsp_busy(void)
    127{
    128	struct kvm_vm *vm;
    129	int res;
    130
    131	vm = create_vm();
    132
    133	add_x86_vcpu(vm, VCPU_ID0, true);
    134	add_x86_vcpu(vm, VCPU_ID1, false);
    135
    136	res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1);
    137	TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set after adding vcpu");
    138
    139	run_vcpu(vm, VCPU_ID0);
    140	run_vcpu(vm, VCPU_ID1);
    141
    142	res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1);
    143	TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set to a terminated vcpu");
    144
    145	kvm_vm_free(vm);
    146}
    147
    148int main(int argc, char *argv[])
    149{
    150	if (!kvm_check_cap(KVM_CAP_SET_BOOT_CPU_ID)) {
    151		print_skip("set_boot_cpu_id not available");
    152		return 0;
    153	}
    154
    155	run_vm_bsp(VCPU_ID0);
    156	run_vm_bsp(VCPU_ID1);
    157	run_vm_bsp(VCPU_ID0);
    158
    159	check_set_bsp_busy();
    160}