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

sync_regs_test.c (5836B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Test for s390x KVM_CAP_SYNC_REGS
      4 *
      5 * Based on the same test for x86:
      6 * Copyright (C) 2018, Google LLC.
      7 *
      8 * Adaptions for s390x:
      9 * Copyright (C) 2019, Red Hat, Inc.
     10 *
     11 * Test expected behavior of the KVM_CAP_SYNC_REGS functionality.
     12 */
     13
     14#define _GNU_SOURCE /* for program_invocation_short_name */
     15#include <fcntl.h>
     16#include <stdio.h>
     17#include <stdlib.h>
     18#include <string.h>
     19#include <sys/ioctl.h>
     20
     21#include "test_util.h"
     22#include "kvm_util.h"
     23#include "diag318_test_handler.h"
     24
     25#define VCPU_ID 5
     26
     27static void guest_code(void)
     28{
     29	/*
     30	 * We embed diag 501 here instead of doing a ucall to avoid that
     31	 * the compiler has messed with r11 at the time of the ucall.
     32	 */
     33	asm volatile (
     34		"0:	diag 0,0,0x501\n"
     35		"	ahi 11,1\n"
     36		"	j 0b\n"
     37	);
     38}
     39
     40#define REG_COMPARE(reg) \
     41	TEST_ASSERT(left->reg == right->reg, \
     42		    "Register " #reg \
     43		    " values did not match: 0x%llx, 0x%llx\n", \
     44		    left->reg, right->reg)
     45
     46#define REG_COMPARE32(reg) \
     47	TEST_ASSERT(left->reg == right->reg, \
     48		    "Register " #reg \
     49		    " values did not match: 0x%x, 0x%x\n", \
     50		    left->reg, right->reg)
     51
     52
     53static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
     54{
     55	int i;
     56
     57	for (i = 0; i < 16; i++)
     58		REG_COMPARE(gprs[i]);
     59}
     60
     61static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
     62{
     63	int i;
     64
     65	for (i = 0; i < 16; i++)
     66		REG_COMPARE32(acrs[i]);
     67
     68	for (i = 0; i < 16; i++)
     69		REG_COMPARE(crs[i]);
     70}
     71
     72#undef REG_COMPARE
     73
     74#define TEST_SYNC_FIELDS   (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318)
     75#define INVALID_SYNC_FIELD 0x80000000
     76
     77int main(int argc, char *argv[])
     78{
     79	struct kvm_vm *vm;
     80	struct kvm_run *run;
     81	struct kvm_regs regs;
     82	struct kvm_sregs sregs;
     83	int rv, cap;
     84
     85	/* Tell stdout not to buffer its content */
     86	setbuf(stdout, NULL);
     87
     88	cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
     89	if (!cap) {
     90		print_skip("CAP_SYNC_REGS not supported");
     91		exit(KSFT_SKIP);
     92	}
     93
     94	/* Create VM */
     95	vm = vm_create_default(VCPU_ID, 0, guest_code);
     96
     97	run = vcpu_state(vm, VCPU_ID);
     98
     99	/* Request reading invalid register set from VCPU. */
    100	run->kvm_valid_regs = INVALID_SYNC_FIELD;
    101	rv = _vcpu_run(vm, VCPU_ID);
    102	TEST_ASSERT(rv < 0 && errno == EINVAL,
    103		    "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
    104		    rv);
    105	vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
    106
    107	run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
    108	rv = _vcpu_run(vm, VCPU_ID);
    109	TEST_ASSERT(rv < 0 && errno == EINVAL,
    110		    "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
    111		    rv);
    112	vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
    113
    114	/* Request setting invalid register set into VCPU. */
    115	run->kvm_dirty_regs = INVALID_SYNC_FIELD;
    116	rv = _vcpu_run(vm, VCPU_ID);
    117	TEST_ASSERT(rv < 0 && errno == EINVAL,
    118		    "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
    119		    rv);
    120	vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
    121
    122	run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
    123	rv = _vcpu_run(vm, VCPU_ID);
    124	TEST_ASSERT(rv < 0 && errno == EINVAL,
    125		    "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
    126		    rv);
    127	vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
    128
    129	/* Request and verify all valid register sets. */
    130	run->kvm_valid_regs = TEST_SYNC_FIELDS;
    131	rv = _vcpu_run(vm, VCPU_ID);
    132	TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
    133	TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
    134		    "Unexpected exit reason: %u (%s)\n",
    135		    run->exit_reason,
    136		    exit_reason_str(run->exit_reason));
    137	TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
    138		    (run->s390_sieic.ipa >> 8) == 0x83 &&
    139		    (run->s390_sieic.ipb >> 16) == 0x501,
    140		    "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n",
    141		    run->s390_sieic.icptcode, run->s390_sieic.ipa,
    142		    run->s390_sieic.ipb);
    143
    144	vcpu_regs_get(vm, VCPU_ID, &regs);
    145	compare_regs(&regs, &run->s.regs);
    146
    147	vcpu_sregs_get(vm, VCPU_ID, &sregs);
    148	compare_sregs(&sregs, &run->s.regs);
    149
    150	/* Set and verify various register values */
    151	run->s.regs.gprs[11] = 0xBAD1DEA;
    152	run->s.regs.acrs[0] = 1 << 11;
    153
    154	run->kvm_valid_regs = TEST_SYNC_FIELDS;
    155	run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
    156
    157	if (get_diag318_info() > 0) {
    158		run->s.regs.diag318 = get_diag318_info();
    159		run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
    160	}
    161
    162	rv = _vcpu_run(vm, VCPU_ID);
    163	TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
    164	TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
    165		    "Unexpected exit reason: %u (%s)\n",
    166		    run->exit_reason,
    167		    exit_reason_str(run->exit_reason));
    168	TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
    169		    "r11 sync regs value incorrect 0x%llx.",
    170		    run->s.regs.gprs[11]);
    171	TEST_ASSERT(run->s.regs.acrs[0]  == 1 << 11,
    172		    "acr0 sync regs value incorrect 0x%x.",
    173		    run->s.regs.acrs[0]);
    174	TEST_ASSERT(run->s.regs.diag318 == get_diag318_info(),
    175		    "diag318 sync regs value incorrect 0x%llx.",
    176		    run->s.regs.diag318);
    177
    178	vcpu_regs_get(vm, VCPU_ID, &regs);
    179	compare_regs(&regs, &run->s.regs);
    180
    181	vcpu_sregs_get(vm, VCPU_ID, &sregs);
    182	compare_sregs(&sregs, &run->s.regs);
    183
    184	/* Clear kvm_dirty_regs bits, verify new s.regs values are
    185	 * overwritten with existing guest values.
    186	 */
    187	run->kvm_valid_regs = TEST_SYNC_FIELDS;
    188	run->kvm_dirty_regs = 0;
    189	run->s.regs.gprs[11] = 0xDEADBEEF;
    190	run->s.regs.diag318 = 0x4B1D;
    191	rv = _vcpu_run(vm, VCPU_ID);
    192	TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
    193	TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
    194		    "Unexpected exit reason: %u (%s)\n",
    195		    run->exit_reason,
    196		    exit_reason_str(run->exit_reason));
    197	TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
    198		    "r11 sync regs value incorrect 0x%llx.",
    199		    run->s.regs.gprs[11]);
    200	TEST_ASSERT(run->s.regs.diag318 != 0x4B1D,
    201		    "diag318 sync regs value incorrect 0x%llx.",
    202		    run->s.regs.diag318);
    203
    204	kvm_vm_free(vm);
    205
    206	return 0;
    207}