1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Test for s390x KVM_S390_MEM_OP
5 * Copyright (C) 2019, Red Hat, Inc.
11 #include <sys/ioctl.h>
13 #include "test_util.h"
18 static uint8_t mem1[65536];
19 static uint8_t mem2[65536];
22 struct kvm_vm *kvm_vm;
27 static struct test_default test_default_init(void *guest_code)
29 struct test_default t;
31 t.size = min((size_t)kvm_check_cap(KVM_CAP_S390_MEM_OP), sizeof(mem1));
32 t.kvm_vm = vm_create_default(VCPU_ID, 0, guest_code);
33 t.run = vcpu_state(t.kvm_vm, VCPU_ID);
37 static void guest_copy(void)
39 memcpy(&mem2, &mem1, sizeof(mem2));
43 static void test_copy(void)
45 struct test_default t = test_default_init(guest_copy);
46 struct kvm_s390_mem_op ksmo;
49 for (i = 0; i < sizeof(mem1); i++)
52 /* Set the first array */
53 ksmo.gaddr = addr_gva2gpa(t.kvm_vm, (uintptr_t)mem1);
56 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
57 ksmo.buf = (uintptr_t)mem1;
59 vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
61 /* Let the guest code copy the first array to the second */
62 vcpu_run(t.kvm_vm, VCPU_ID);
63 TEST_ASSERT(t.run->exit_reason == KVM_EXIT_S390_SIEIC,
64 "Unexpected exit reason: %u (%s)\n",
66 exit_reason_str(t.run->exit_reason));
68 memset(mem2, 0xaa, sizeof(mem2));
70 /* Get the second array */
71 ksmo.gaddr = (uintptr_t)mem2;
74 ksmo.op = KVM_S390_MEMOP_LOGICAL_READ;
75 ksmo.buf = (uintptr_t)mem2;
77 vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
79 TEST_ASSERT(!memcmp(mem1, mem2, t.size),
80 "Memory contents do not match!");
82 kvm_vm_free(t.kvm_vm);
85 static void guest_idle(void)
91 static void test_errors(void)
93 struct test_default t = test_default_init(guest_idle);
94 struct kvm_s390_mem_op ksmo;
97 /* Check error conditions - first bad size: */
98 ksmo.gaddr = (uintptr_t)mem1;
101 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
102 ksmo.buf = (uintptr_t)mem1;
104 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
105 TEST_ASSERT(rv == -1 && errno == E2BIG, "ioctl allows insane sizes");
108 ksmo.gaddr = (uintptr_t)mem1;
111 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
112 ksmo.buf = (uintptr_t)mem1;
114 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
115 TEST_ASSERT(rv == -1 && (errno == EINVAL || errno == ENOMEM),
116 "ioctl allows 0 as size");
119 ksmo.gaddr = (uintptr_t)mem1;
122 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
123 ksmo.buf = (uintptr_t)mem1;
125 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
126 TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows all flags");
129 ksmo.gaddr = (uintptr_t)mem1;
133 ksmo.buf = (uintptr_t)mem1;
135 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
136 TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows bad operations");
138 /* Bad guest address: */
139 ksmo.gaddr = ~0xfffUL;
140 ksmo.flags = KVM_S390_MEMOP_F_CHECK_ONLY;
142 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
143 ksmo.buf = (uintptr_t)mem1;
145 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
146 TEST_ASSERT(rv > 0, "ioctl does not report bad guest memory access");
148 /* Bad host address: */
149 ksmo.gaddr = (uintptr_t)mem1;
152 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
155 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
156 TEST_ASSERT(rv == -1 && errno == EFAULT,
157 "ioctl does not report bad host memory address");
159 /* Bad access register: */
160 t.run->psw_mask &= ~(3UL << (63 - 17));
161 t.run->psw_mask |= 1UL << (63 - 17); /* Enable AR mode */
162 vcpu_run(t.kvm_vm, VCPU_ID); /* To sync new state to SIE block */
163 ksmo.gaddr = (uintptr_t)mem1;
166 ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE;
167 ksmo.buf = (uintptr_t)mem1;
169 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
170 TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows ARs > 15");
171 t.run->psw_mask &= ~(3UL << (63 - 17)); /* Disable AR mode */
172 vcpu_run(t.kvm_vm, VCPU_ID); /* Run to sync new state */
174 /* Check that the SIDA calls are rejected for non-protected guests */
178 ksmo.op = KVM_S390_MEMOP_SIDA_READ;
179 ksmo.buf = (uintptr_t)mem1;
180 ksmo.sida_offset = 0x1c0;
181 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
182 TEST_ASSERT(rv == -1 && errno == EINVAL,
183 "ioctl does not reject SIDA_READ in non-protected mode");
184 ksmo.op = KVM_S390_MEMOP_SIDA_WRITE;
185 rv = _vcpu_ioctl(t.kvm_vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo);
186 TEST_ASSERT(rv == -1 && errno == EINVAL,
187 "ioctl does not reject SIDA_WRITE in non-protected mode");
189 kvm_vm_free(t.kvm_vm);
192 int main(int argc, char *argv[])
196 setbuf(stdout, NULL); /* Tell stdout not to buffer its content */
198 memop_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP);
200 print_skip("CAP_S390_MEM_OP not supported");