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
  24#define VCPU_ID 5
  25
  26static void guest_code(void)
  27{
  28        for (;;) {
  29                asm volatile ("diag 0,0,0x501");
  30                asm volatile ("ahi 11,1");
  31        }
  32}
  33
  34#define REG_COMPARE(reg) \
  35        TEST_ASSERT(left->reg == right->reg, \
  36                    "Register " #reg \
  37                    " values did not match: 0x%llx, 0x%llx\n", \
  38                    left->reg, right->reg)
  39
  40static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
  41{
  42        int i;
  43
  44        for (i = 0; i < 16; i++)
  45                REG_COMPARE(gprs[i]);
  46}
  47
  48static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
  49{
  50        int i;
  51
  52        for (i = 0; i < 16; i++)
  53                REG_COMPARE(acrs[i]);
  54
  55        for (i = 0; i < 16; i++)
  56                REG_COMPARE(crs[i]);
  57}
  58
  59#undef REG_COMPARE
  60
  61#define TEST_SYNC_FIELDS   (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS)
  62#define INVALID_SYNC_FIELD 0x80000000
  63
  64int main(int argc, char *argv[])
  65{
  66        struct kvm_vm *vm;
  67        struct kvm_run *run;
  68        struct kvm_regs regs;
  69        struct kvm_sregs sregs;
  70        int rv, cap;
  71
  72        /* Tell stdout not to buffer its content */
  73        setbuf(stdout, NULL);
  74
  75        cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
  76        if (!cap) {
  77                fprintf(stderr, "CAP_SYNC_REGS not supported, skipping test\n");
  78                exit(KSFT_SKIP);
  79        }
  80
  81        /* Create VM */
  82        vm = vm_create_default(VCPU_ID, 0, guest_code);
  83
  84        run = vcpu_state(vm, VCPU_ID);
  85
  86        /* Request and verify all valid register sets. */
  87        run->kvm_valid_regs = TEST_SYNC_FIELDS;
  88        rv = _vcpu_run(vm, VCPU_ID);
  89        TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
  90        TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
  91                    "Unexpected exit reason: %u (%s)\n",
  92                    run->exit_reason,
  93                    exit_reason_str(run->exit_reason));
  94        TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
  95                    (run->s390_sieic.ipa >> 8) == 0x83 &&
  96                    (run->s390_sieic.ipb >> 16) == 0x501,
  97                    "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n",
  98                    run->s390_sieic.icptcode, run->s390_sieic.ipa,
  99                    run->s390_sieic.ipb);
 100
 101        vcpu_regs_get(vm, VCPU_ID, &regs);
 102        compare_regs(&regs, &run->s.regs);
 103
 104        vcpu_sregs_get(vm, VCPU_ID, &sregs);
 105        compare_sregs(&sregs, &run->s.regs);
 106
 107        /* Set and verify various register values */
 108        run->s.regs.gprs[11] = 0xBAD1DEA;
 109        run->s.regs.acrs[0] = 1 << 11;
 110
 111        run->kvm_valid_regs = TEST_SYNC_FIELDS;
 112        run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
 113        rv = _vcpu_run(vm, VCPU_ID);
 114        TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
 115        TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
 116                    "Unexpected exit reason: %u (%s)\n",
 117                    run->exit_reason,
 118                    exit_reason_str(run->exit_reason));
 119        TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
 120                    "r11 sync regs value incorrect 0x%llx.",
 121                    run->s.regs.gprs[11]);
 122        TEST_ASSERT(run->s.regs.acrs[0]  == 1 << 11,
 123                    "acr0 sync regs value incorrect 0x%llx.",
 124                    run->s.regs.acrs[0]);
 125
 126        vcpu_regs_get(vm, VCPU_ID, &regs);
 127        compare_regs(&regs, &run->s.regs);
 128
 129        vcpu_sregs_get(vm, VCPU_ID, &sregs);
 130        compare_sregs(&sregs, &run->s.regs);
 131
 132        /* Clear kvm_dirty_regs bits, verify new s.regs values are
 133         * overwritten with existing guest values.
 134         */
 135        run->kvm_valid_regs = TEST_SYNC_FIELDS;
 136        run->kvm_dirty_regs = 0;
 137        run->s.regs.gprs[11] = 0xDEADBEEF;
 138        rv = _vcpu_run(vm, VCPU_ID);
 139        TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
 140        TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
 141                    "Unexpected exit reason: %u (%s)\n",
 142                    run->exit_reason,
 143                    exit_reason_str(run->exit_reason));
 144        TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
 145                    "r11 sync regs value incorrect 0x%llx.",
 146                    run->s.regs.gprs[11]);
 147
 148        kvm_vm_free(vm);
 149
 150        return 0;
 151}
 152