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 18 static uint8_t mem1[65536]; 19 static uint8_t mem2[65536]; 20 21 static 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 32 int 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