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