linux/tools/testing/selftests/kvm/s390x/sync_regs_test.c
<<
>>
Prefs
   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}
 208