1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2021 ARM Limited.
4 */
5 #include <errno.h>
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/auxv.h>
13 #include <sys/prctl.h>
14 #include <sys/ptrace.h>
15 #include <sys/types.h>
16 #include <sys/uio.h>
17 #include <sys/wait.h>
18 #include <asm/sigcontext.h>
19 #include <asm/ptrace.h>
20
21 #include "../../kselftest.h"
22
23 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
24 #ifndef NT_ARM_ZA
25 #define NT_ARM_ZA 0x40c
26 #endif
27
28 /*
29 * The architecture defines the maximum VQ as 16 but for extensibility
30 * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
31 * a *lot* more tests than are useful if we use it. Until the
32 * architecture is extended let's limit our coverage to what is
33 * currently allowed, plus one extra to ensure we cover constraining
34 * the VL as expected.
35 */
36 #define TEST_VQ_MAX 17
37
38 #define EXPECTED_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
39
fill_buf(char * buf,size_t size)40 static void fill_buf(char *buf, size_t size)
41 {
42 int i;
43
44 for (i = 0; i < size; i++)
45 buf[i] = random();
46 }
47
do_child(void)48 static int do_child(void)
49 {
50 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
51 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
52
53 if (raise(SIGSTOP))
54 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
55
56 return EXIT_SUCCESS;
57 }
58
get_za(pid_t pid,void ** buf,size_t * size)59 static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
60 {
61 struct user_za_header *za;
62 void *p;
63 size_t sz = sizeof(*za);
64 struct iovec iov;
65
66 while (1) {
67 if (*size < sz) {
68 p = realloc(*buf, sz);
69 if (!p) {
70 errno = ENOMEM;
71 goto error;
72 }
73
74 *buf = p;
75 *size = sz;
76 }
77
78 iov.iov_base = *buf;
79 iov.iov_len = sz;
80 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
81 goto error;
82
83 za = *buf;
84 if (za->size <= sz)
85 break;
86
87 sz = za->size;
88 }
89
90 return za;
91
92 error:
93 return NULL;
94 }
95
set_za(pid_t pid,const struct user_za_header * za)96 static int set_za(pid_t pid, const struct user_za_header *za)
97 {
98 struct iovec iov;
99
100 iov.iov_base = (void *)za;
101 iov.iov_len = za->size;
102 return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);
103 }
104
105 /* Validate attempting to set the specfied VL via ptrace */
ptrace_set_get_vl(pid_t child,unsigned int vl,bool * supported)106 static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported)
107 {
108 struct user_za_header za;
109 struct user_za_header *new_za = NULL;
110 size_t new_za_size = 0;
111 int ret, prctl_vl;
112
113 *supported = false;
114
115 /* Check if the VL is supported in this process */
116 prctl_vl = prctl(PR_SME_SET_VL, vl);
117 if (prctl_vl == -1)
118 ksft_exit_fail_msg("prctl(PR_SME_SET_VL) failed: %s (%d)\n",
119 strerror(errno), errno);
120
121 /* If the VL is not supported then a supported VL will be returned */
122 *supported = (prctl_vl == vl);
123
124 /* Set the VL by doing a set with no register payload */
125 memset(&za, 0, sizeof(za));
126 za.size = sizeof(za);
127 za.vl = vl;
128 ret = set_za(child, &za);
129 if (ret != 0) {
130 ksft_test_result_fail("Failed to set VL %u\n", vl);
131 return;
132 }
133
134 /*
135 * Read back the new register state and verify that we have the
136 * same VL that we got from prctl() on ourselves.
137 */
138 if (!get_za(child, (void **)&new_za, &new_za_size)) {
139 ksft_test_result_fail("Failed to read VL %u\n", vl);
140 return;
141 }
142
143 ksft_test_result(new_za->vl = prctl_vl, "Set VL %u\n", vl);
144
145 free(new_za);
146 }
147
148 /* Validate attempting to set no ZA data and read it back */
ptrace_set_no_data(pid_t child,unsigned int vl)149 static void ptrace_set_no_data(pid_t child, unsigned int vl)
150 {
151 void *read_buf = NULL;
152 struct user_za_header write_za;
153 struct user_za_header *read_za;
154 size_t read_za_size = 0;
155 int ret;
156
157 /* Set up some data and write it out */
158 memset(&write_za, 0, sizeof(write_za));
159 write_za.size = ZA_PT_ZA_OFFSET;
160 write_za.vl = vl;
161
162 ret = set_za(child, &write_za);
163 if (ret != 0) {
164 ksft_test_result_fail("Failed to set VL %u no data\n", vl);
165 return;
166 }
167
168 /* Read the data back */
169 if (!get_za(child, (void **)&read_buf, &read_za_size)) {
170 ksft_test_result_fail("Failed to read VL %u no data\n", vl);
171 return;
172 }
173 read_za = read_buf;
174
175 /* We might read more data if there's extensions we don't know */
176 if (read_za->size < write_za.size) {
177 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
178 vl, write_za.size, read_za->size);
179 goto out_read;
180 }
181
182 ksft_test_result(read_za->size == write_za.size,
183 "Disabled ZA for VL %u\n", vl);
184
185 out_read:
186 free(read_buf);
187 }
188
189 /* Validate attempting to set data and read it back */
ptrace_set_get_data(pid_t child,unsigned int vl)190 static void ptrace_set_get_data(pid_t child, unsigned int vl)
191 {
192 void *write_buf;
193 void *read_buf = NULL;
194 struct user_za_header *write_za;
195 struct user_za_header *read_za;
196 size_t read_za_size = 0;
197 unsigned int vq = sve_vq_from_vl(vl);
198 int ret;
199 size_t data_size;
200
201 data_size = ZA_PT_SIZE(vq);
202 write_buf = malloc(data_size);
203 if (!write_buf) {
204 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n",
205 data_size, vl);
206 return;
207 }
208 write_za = write_buf;
209
210 /* Set up some data and write it out */
211 memset(write_za, 0, data_size);
212 write_za->size = data_size;
213 write_za->vl = vl;
214
215 fill_buf(write_buf + ZA_PT_ZA_OFFSET, ZA_PT_ZA_SIZE(vq));
216
217 ret = set_za(child, write_za);
218 if (ret != 0) {
219 ksft_test_result_fail("Failed to set VL %u data\n", vl);
220 goto out;
221 }
222
223 /* Read the data back */
224 if (!get_za(child, (void **)&read_buf, &read_za_size)) {
225 ksft_test_result_fail("Failed to read VL %u data\n", vl);
226 goto out;
227 }
228 read_za = read_buf;
229
230 /* We might read more data if there's extensions we don't know */
231 if (read_za->size < write_za->size) {
232 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
233 vl, write_za->size, read_za->size);
234 goto out_read;
235 }
236
237 ksft_test_result(memcmp(write_buf + ZA_PT_ZA_OFFSET,
238 read_buf + ZA_PT_ZA_OFFSET,
239 ZA_PT_ZA_SIZE(vq)) == 0,
240 "Data match for VL %u\n", vl);
241
242 out_read:
243 free(read_buf);
244 out:
245 free(write_buf);
246 }
247
do_parent(pid_t child)248 static int do_parent(pid_t child)
249 {
250 int ret = EXIT_FAILURE;
251 pid_t pid;
252 int status;
253 siginfo_t si;
254 unsigned int vq, vl;
255 bool vl_supported;
256
257 /* Attach to the child */
258 while (1) {
259 int sig;
260
261 pid = wait(&status);
262 if (pid == -1) {
263 perror("wait");
264 goto error;
265 }
266
267 /*
268 * This should never happen but it's hard to flag in
269 * the framework.
270 */
271 if (pid != child)
272 continue;
273
274 if (WIFEXITED(status) || WIFSIGNALED(status))
275 ksft_exit_fail_msg("Child died unexpectedly\n");
276
277 if (!WIFSTOPPED(status))
278 goto error;
279
280 sig = WSTOPSIG(status);
281
282 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
283 if (errno == ESRCH)
284 goto disappeared;
285
286 if (errno == EINVAL) {
287 sig = 0; /* bust group-stop */
288 goto cont;
289 }
290
291 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
292 strerror(errno));
293 goto error;
294 }
295
296 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
297 si.si_pid == pid)
298 break;
299
300 cont:
301 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
302 if (errno == ESRCH)
303 goto disappeared;
304
305 ksft_test_result_fail("PTRACE_CONT: %s\n",
306 strerror(errno));
307 goto error;
308 }
309 }
310
311 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
312
313 /* Step through every possible VQ */
314 for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
315 vl = sve_vl_from_vq(vq);
316
317 /* First, try to set this vector length */
318 ptrace_set_get_vl(child, vl, &vl_supported);
319
320 /* If the VL is supported validate data set/get */
321 if (vl_supported) {
322 ptrace_set_no_data(child, vl);
323 ptrace_set_get_data(child, vl);
324 } else {
325 ksft_test_result_skip("Disabled ZA for VL %u\n", vl);
326 ksft_test_result_skip("Get and set data for VL %u\n",
327 vl);
328 }
329 }
330
331 ret = EXIT_SUCCESS;
332
333 error:
334 kill(child, SIGKILL);
335
336 disappeared:
337 return ret;
338 }
339
main(void)340 int main(void)
341 {
342 int ret = EXIT_SUCCESS;
343 pid_t child;
344
345 srandom(getpid());
346
347 ksft_print_header();
348
349 if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
350 ksft_set_plan(1);
351 ksft_exit_skip("SME not available\n");
352 }
353
354 ksft_set_plan(EXPECTED_TESTS);
355
356 child = fork();
357 if (!child)
358 return do_child();
359
360 if (do_parent(child))
361 ret = EXIT_FAILURE;
362
363 ksft_print_cnts();
364
365 return ret;
366 }
367