linux/tools/testing/selftests/kvm/s390x/memop.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Test for s390x KVM_S390_MEM_OP
   4 *
   5 * Copyright (C) 2019, Red Hat, Inc.
   6 */
   7
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <sys/ioctl.h>
  12
  13#include "test_util.h"
  14#include "kvm_util.h"
  15
  16#define VCPU_ID 1
  17
  18static uint8_t mem1[65536];
  19static uint8_t mem2[65536];
  20
  21static void guest_code(void)
  22{
  23        int i;
  24
  25        for (;;) {
  26                for (i = 0; i < sizeof(mem2); i++)
  27                        mem2[i] = mem1[i];
  28                GUEST_SYNC(0);
  29        }
  30}
  31
  32int main(int argc, char *argv[])
  33{
  34        struct kvm_vm *vm;
  35        struct kvm_run *run;
  36        struct kvm_s390_mem_op ksmo;
  37        int rv, i, maxsize;
  38
  39        setbuf(stdout, NULL);   /* Tell stdout not to buffer its content */
  40
  41        maxsize = kvm_check_cap(KVM_CAP_S390_MEM_OP);
  42        if (!maxsize) {
  43                print_skip("CAP_S390_MEM_OP not supported");
  44                exit(KSFT_SKIP);
  45        }
  46        if (maxsize > sizeof(mem1))
  47                maxsize = sizeof(mem1);
  48
  49        /* Create VM */
  50        vm = vm_create_default(VCPU_ID, 0, guest_code);
  51        run = vcpu_state(vm, VCPU_ID);
  52
  53        for (i = 0; i < sizeof(mem1); i++)
  54                mem1[i] = i * i + i;
  55
  56        /* Set the first array */
  57        ksmo.gaddr = addr_gva2gpa(vm, (uintptr_t)mem1);
  58        ksmo.flags = 0;
  59        ksmo.size = maxsize;
  60        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
  61        ksmo.buf = (uintptr_t)mem1;
  62        ksmo.ar = 0;
  63        vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
  64
  65        /* Let the guest code copy the first array to the second */
  66        vcpu_run(vm, VCPU_ID);
  67        TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
  68                    "Unexpected exit reason: %u (%s)\n",
  69                    run->exit_reason,
  70                    exit_reason_str(run->exit_reason));
  71
  72        memset(mem2, 0xaa, sizeof(mem2));
  73
  74        /* Get the second array */
  75        ksmo.gaddr = (uintptr_t)mem2;
  76        ksmo.flags = 0;
  77        ksmo.size = maxsize;
  78        ksmo.op = KVM_S390_MEMOP_LOGICAL_READ;
  79        ksmo.buf = (uintptr_t)mem2;
  80        ksmo.ar = 0;
  81        vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
  82
  83        TEST_ASSERT(!memcmp(mem1, mem2, maxsize),
  84                    "Memory contents do not match!");
  85
  86        /* Check error conditions - first bad size: */
  87        ksmo.gaddr = (uintptr_t)mem1;
  88        ksmo.flags = 0;
  89        ksmo.size = -1;
  90        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
  91        ksmo.buf = (uintptr_t)mem1;
  92        ksmo.ar = 0;
  93        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
  94        TEST_ASSERT(rv == -1 && errno == E2BIG, "ioctl allows insane sizes");
  95
  96        /* Zero size: */
  97        ksmo.gaddr = (uintptr_t)mem1;
  98        ksmo.flags = 0;
  99        ksmo.size = 0;
 100        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
 101        ksmo.buf = (uintptr_t)mem1;
 102        ksmo.ar = 0;
 103        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
 104        TEST_ASSERT(rv == -1 && (errno == EINVAL || errno == ENOMEM),
 105                    "ioctl allows 0 as size");
 106
 107        /* Bad flags: */
 108        ksmo.gaddr = (uintptr_t)mem1;
 109        ksmo.flags = -1;
 110        ksmo.size = maxsize;
 111        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
 112        ksmo.buf = (uintptr_t)mem1;
 113        ksmo.ar = 0;
 114        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
 115        TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows all flags");
 116
 117        /* Bad operation: */
 118        ksmo.gaddr = (uintptr_t)mem1;
 119        ksmo.flags = 0;
 120        ksmo.size = maxsize;
 121        ksmo.op = -1;
 122        ksmo.buf = (uintptr_t)mem1;
 123        ksmo.ar = 0;
 124        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
 125        TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows bad operations");
 126
 127        /* Bad guest address: */
 128        ksmo.gaddr = ~0xfffUL;
 129        ksmo.flags = KVM_S390_MEMOP_F_CHECK_ONLY;
 130        ksmo.size = maxsize;
 131        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
 132        ksmo.buf = (uintptr_t)mem1;
 133        ksmo.ar = 0;
 134        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
 135        TEST_ASSERT(rv > 0, "ioctl does not report bad guest memory access");
 136
 137        /* Bad host address: */
 138        ksmo.gaddr = (uintptr_t)mem1;
 139        ksmo.flags = 0;
 140        ksmo.size = maxsize;
 141        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
 142        ksmo.buf = 0;
 143        ksmo.ar = 0;
 144        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
 145        TEST_ASSERT(rv == -1 && errno == EFAULT,
 146                    "ioctl does not report bad host memory address");
 147
 148        /* Bad access register: */
 149        run->psw_mask &= ~(3UL << (63 - 17));
 150        run->psw_mask |= 1UL << (63 - 17);  /* Enable AR mode */
 151        vcpu_run(vm, VCPU_ID);              /* To sync new state to SIE block */
 152        ksmo.gaddr = (uintptr_t)mem1;
 153        ksmo.flags = 0;
 154        ksmo.size = maxsize;
 155        ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
 156        ksmo.buf = (uintptr_t)mem1;
 157        ksmo.ar = 17;
 158        rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
 159        TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows ARs > 15");
 160        run->psw_mask &= ~(3UL << (63 - 17));   /* Disable AR mode */
 161        vcpu_run(vm, VCPU_ID);                  /* Run to sync new state */
 162
 163        kvm_vm_free(vm);
 164
 165        return 0;
 166}
 167