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