root/tools/testing/selftests/kvm/s390x/sync_regs_test.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. guest_code
  2. compare_regs
  3. compare_sregs
  4. main

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

/* [<][>][^][v][top][bottom][index][help] */