1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2015-2021 ARM Limited.
4 * Original author: Dave Martin <Dave.Martin@arm.com>
5 */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/auxv.h>
14 #include <sys/prctl.h>
15 #include <sys/ptrace.h>
16 #include <sys/types.h>
17 #include <sys/uio.h>
18 #include <sys/wait.h>
19 #include <asm/sigcontext.h>
20 #include <asm/ptrace.h>
21
22 #include "../../kselftest.h"
23
24 #define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
25 #define FPSIMD_TESTS 5
26
27 #define EXPECTED_TESTS (VL_TESTS + FPSIMD_TESTS)
28
29 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
30 #ifndef NT_ARM_SVE
31 #define NT_ARM_SVE 0x405
32 #endif
33
fill_buf(char * buf,size_t size)34 static void fill_buf(char *buf, size_t size)
35 {
36 int i;
37
38 for (i = 0; i < size; i++)
39 buf[i] = random();
40 }
41
do_child(void)42 static int do_child(void)
43 {
44 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
45 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
46
47 if (raise(SIGSTOP))
48 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
49
50 return EXIT_SUCCESS;
51 }
52
get_fpsimd(pid_t pid,struct user_fpsimd_state * fpsimd)53 static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
54 {
55 struct iovec iov;
56
57 iov.iov_base = fpsimd;
58 iov.iov_len = sizeof(*fpsimd);
59 return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
60 }
61
get_sve(pid_t pid,void ** buf,size_t * size)62 static struct user_sve_header *get_sve(pid_t pid, void **buf, size_t *size)
63 {
64 struct user_sve_header *sve;
65 void *p;
66 size_t sz = sizeof *sve;
67 struct iovec iov;
68
69 while (1) {
70 if (*size < sz) {
71 p = realloc(*buf, sz);
72 if (!p) {
73 errno = ENOMEM;
74 goto error;
75 }
76
77 *buf = p;
78 *size = sz;
79 }
80
81 iov.iov_base = *buf;
82 iov.iov_len = sz;
83 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_SVE, &iov))
84 goto error;
85
86 sve = *buf;
87 if (sve->size <= sz)
88 break;
89
90 sz = sve->size;
91 }
92
93 return sve;
94
95 error:
96 return NULL;
97 }
98
set_sve(pid_t pid,const struct user_sve_header * sve)99 static int set_sve(pid_t pid, const struct user_sve_header *sve)
100 {
101 struct iovec iov;
102
103 iov.iov_base = (void *)sve;
104 iov.iov_len = sve->size;
105 return ptrace(PTRACE_SETREGSET, pid, NT_ARM_SVE, &iov);
106 }
107
108 /* Validate setting and getting the inherit flag */
ptrace_set_get_inherit(pid_t child)109 static void ptrace_set_get_inherit(pid_t child)
110 {
111 struct user_sve_header sve;
112 struct user_sve_header *new_sve = NULL;
113 size_t new_sve_size = 0;
114 int ret;
115
116 /* First set the flag */
117 memset(&sve, 0, sizeof(sve));
118 sve.size = sizeof(sve);
119 sve.vl = sve_vl_from_vq(SVE_VQ_MIN);
120 sve.flags = SVE_PT_VL_INHERIT;
121 ret = set_sve(child, &sve);
122 if (ret != 0) {
123 ksft_test_result_fail("Failed to set SVE_PT_VL_INHERIT\n");
124 return;
125 }
126
127 /*
128 * Read back the new register state and verify that we have
129 * set the flags we expected.
130 */
131 if (!get_sve(child, (void **)&new_sve, &new_sve_size)) {
132 ksft_test_result_fail("Failed to read SVE flags\n");
133 return;
134 }
135
136 ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
137 "SVE_PT_VL_INHERIT set\n");
138
139 /* Now clear */
140 sve.flags &= ~SVE_PT_VL_INHERIT;
141 ret = set_sve(child, &sve);
142 if (ret != 0) {
143 ksft_test_result_fail("Failed to clear SVE_PT_VL_INHERIT\n");
144 return;
145 }
146
147 if (!get_sve(child, (void **)&new_sve, &new_sve_size)) {
148 ksft_test_result_fail("Failed to read SVE flags\n");
149 return;
150 }
151
152 ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
153 "SVE_PT_VL_INHERIT cleared\n");
154
155 free(new_sve);
156 }
157
158 /* Validate attempting to set the specfied VL via ptrace */
ptrace_set_get_vl(pid_t child,unsigned int vl,bool * supported)159 static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported)
160 {
161 struct user_sve_header sve;
162 struct user_sve_header *new_sve = NULL;
163 size_t new_sve_size = 0;
164 int ret, prctl_vl;
165
166 *supported = false;
167
168 /* Check if the VL is supported in this process */
169 prctl_vl = prctl(PR_SVE_SET_VL, vl);
170 if (prctl_vl == -1)
171 ksft_exit_fail_msg("prctl(PR_SVE_SET_VL) failed: %s (%d)\n",
172 strerror(errno), errno);
173
174 /* If the VL is not supported then a supported VL will be returned */
175 *supported = (prctl_vl == vl);
176
177 /* Set the VL by doing a set with no register payload */
178 memset(&sve, 0, sizeof(sve));
179 sve.size = sizeof(sve);
180 sve.vl = vl;
181 ret = set_sve(child, &sve);
182 if (ret != 0) {
183 ksft_test_result_fail("Failed to set VL %u\n", vl);
184 return;
185 }
186
187 /*
188 * Read back the new register state and verify that we have the
189 * same VL that we got from prctl() on ourselves.
190 */
191 if (!get_sve(child, (void **)&new_sve, &new_sve_size)) {
192 ksft_test_result_fail("Failed to read VL %u\n", vl);
193 return;
194 }
195
196 ksft_test_result(new_sve->vl = prctl_vl, "Set VL %u\n", vl);
197
198 free(new_sve);
199 }
200
check_u32(unsigned int vl,const char * reg,uint32_t * in,uint32_t * out,int * errors)201 static void check_u32(unsigned int vl, const char *reg,
202 uint32_t *in, uint32_t *out, int *errors)
203 {
204 if (*in != *out) {
205 printf("# VL %d %s wrote %x read %x\n",
206 vl, reg, *in, *out);
207 (*errors)++;
208 }
209 }
210
211 /* Access the FPSIMD registers via the SVE regset */
ptrace_sve_fpsimd(pid_t child)212 static void ptrace_sve_fpsimd(pid_t child)
213 {
214 void *svebuf = NULL;
215 size_t svebufsz = 0;
216 struct user_sve_header *sve;
217 struct user_fpsimd_state *fpsimd, new_fpsimd;
218 unsigned int i, j;
219 unsigned char *p;
220
221 /* New process should start with FPSIMD registers only */
222 sve = get_sve(child, &svebuf, &svebufsz);
223 if (!sve) {
224 ksft_test_result_fail("get_sve: %s\n", strerror(errno));
225
226 return;
227 } else {
228 ksft_test_result_pass("get_sve(FPSIMD)\n");
229 }
230
231 ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
232 "Set FPSIMD registers\n");
233 if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
234 goto out;
235
236 /* Try to set a known FPSIMD state via PT_REGS_SVE */
237 fpsimd = (struct user_fpsimd_state *)((char *)sve +
238 SVE_PT_FPSIMD_OFFSET);
239 for (i = 0; i < 32; ++i) {
240 p = (unsigned char *)&fpsimd->vregs[i];
241
242 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
243 p[j] = j;
244 }
245
246 if (set_sve(child, sve)) {
247 ksft_test_result_fail("set_sve(FPSIMD): %s\n",
248 strerror(errno));
249
250 goto out;
251 }
252
253 /* Verify via the FPSIMD regset */
254 if (get_fpsimd(child, &new_fpsimd)) {
255 ksft_test_result_fail("get_fpsimd(): %s\n",
256 strerror(errno));
257 goto out;
258 }
259 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
260 ksft_test_result_pass("get_fpsimd() gave same state\n");
261 else
262 ksft_test_result_fail("get_fpsimd() gave different state\n");
263
264 out:
265 free(svebuf);
266 }
267
268 /* Validate attempting to set SVE data and read SVE data */
ptrace_set_sve_get_sve_data(pid_t child,unsigned int vl)269 static void ptrace_set_sve_get_sve_data(pid_t child, unsigned int vl)
270 {
271 void *write_buf;
272 void *read_buf = NULL;
273 struct user_sve_header *write_sve;
274 struct user_sve_header *read_sve;
275 size_t read_sve_size = 0;
276 unsigned int vq = sve_vq_from_vl(vl);
277 int ret, i;
278 size_t data_size;
279 int errors = 0;
280
281 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
282 write_buf = malloc(data_size);
283 if (!write_buf) {
284 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n",
285 data_size, vl);
286 return;
287 }
288 write_sve = write_buf;
289
290 /* Set up some data and write it out */
291 memset(write_sve, 0, data_size);
292 write_sve->size = data_size;
293 write_sve->vl = vl;
294 write_sve->flags = SVE_PT_REGS_SVE;
295
296 for (i = 0; i < __SVE_NUM_ZREGS; i++)
297 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
298 SVE_PT_SVE_ZREG_SIZE(vq));
299
300 for (i = 0; i < __SVE_NUM_PREGS; i++)
301 fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
302 SVE_PT_SVE_PREG_SIZE(vq));
303
304 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
305 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
306
307 /* TODO: Generate a valid FFR pattern */
308
309 ret = set_sve(child, write_sve);
310 if (ret != 0) {
311 ksft_test_result_fail("Failed to set VL %u data\n", vl);
312 goto out;
313 }
314
315 /* Read the data back */
316 if (!get_sve(child, (void **)&read_buf, &read_sve_size)) {
317 ksft_test_result_fail("Failed to read VL %u data\n", vl);
318 goto out;
319 }
320 read_sve = read_buf;
321
322 /* We might read more data if there's extensions we don't know */
323 if (read_sve->size < write_sve->size) {
324 ksft_test_result_fail("Wrote %d bytes, only read %d\n",
325 write_sve->size, read_sve->size);
326 goto out_read;
327 }
328
329 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
330 if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
331 read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
332 SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
333 printf("# Mismatch in %u Z%d\n", vl, i);
334 errors++;
335 }
336 }
337
338 for (i = 0; i < __SVE_NUM_PREGS; i++) {
339 if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
340 read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
341 SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
342 printf("# Mismatch in %u P%d\n", vl, i);
343 errors++;
344 }
345 }
346
347 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
348 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
349 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
350 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
351
352 ksft_test_result(errors == 0, "Set and get SVE data for VL %u\n", vl);
353
354 out_read:
355 free(read_buf);
356 out:
357 free(write_buf);
358 }
359
360 /* Validate attempting to set SVE data and read SVE data */
ptrace_set_sve_get_fpsimd_data(pid_t child,unsigned int vl)361 static void ptrace_set_sve_get_fpsimd_data(pid_t child, unsigned int vl)
362 {
363 void *write_buf;
364 struct user_sve_header *write_sve;
365 unsigned int vq = sve_vq_from_vl(vl);
366 struct user_fpsimd_state fpsimd_state;
367 int ret, i;
368 size_t data_size;
369 int errors = 0;
370
371 if (__BYTE_ORDER == __BIG_ENDIAN) {
372 ksft_test_result_skip("Big endian not supported\n");
373 return;
374 }
375
376 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
377 write_buf = malloc(data_size);
378 if (!write_buf) {
379 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n",
380 data_size, vl);
381 return;
382 }
383 write_sve = write_buf;
384
385 /* Set up some data and write it out */
386 memset(write_sve, 0, data_size);
387 write_sve->size = data_size;
388 write_sve->vl = vl;
389 write_sve->flags = SVE_PT_REGS_SVE;
390
391 for (i = 0; i < __SVE_NUM_ZREGS; i++)
392 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
393 SVE_PT_SVE_ZREG_SIZE(vq));
394
395 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
396 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
397
398 ret = set_sve(child, write_sve);
399 if (ret != 0) {
400 ksft_test_result_fail("Failed to set VL %u data\n", vl);
401 goto out;
402 }
403
404 /* Read the data back */
405 if (get_fpsimd(child, &fpsimd_state)) {
406 ksft_test_result_fail("Failed to read VL %u FPSIMD data\n",
407 vl);
408 goto out;
409 }
410
411 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
412 __uint128_t tmp = 0;
413
414 /*
415 * Z regs are stored endianness invariant, this won't
416 * work for big endian
417 */
418 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
419 sizeof(tmp));
420
421 if (tmp != fpsimd_state.vregs[i]) {
422 printf("# Mismatch in FPSIMD for VL %u Z%d\n", vl, i);
423 errors++;
424 }
425 }
426
427 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
428 &fpsimd_state.fpsr, &errors);
429 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
430 &fpsimd_state.fpcr, &errors);
431
432 ksft_test_result(errors == 0, "Set and get FPSIMD data for VL %u\n",
433 vl);
434
435 out:
436 free(write_buf);
437 }
438
do_parent(pid_t child)439 static int do_parent(pid_t child)
440 {
441 int ret = EXIT_FAILURE;
442 pid_t pid;
443 int status;
444 siginfo_t si;
445 unsigned int vq, vl;
446 bool vl_supported;
447
448 /* Attach to the child */
449 while (1) {
450 int sig;
451
452 pid = wait(&status);
453 if (pid == -1) {
454 perror("wait");
455 goto error;
456 }
457
458 /*
459 * This should never happen but it's hard to flag in
460 * the framework.
461 */
462 if (pid != child)
463 continue;
464
465 if (WIFEXITED(status) || WIFSIGNALED(status))
466 ksft_exit_fail_msg("Child died unexpectedly\n");
467
468 if (!WIFSTOPPED(status))
469 goto error;
470
471 sig = WSTOPSIG(status);
472
473 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
474 if (errno == ESRCH)
475 goto disappeared;
476
477 if (errno == EINVAL) {
478 sig = 0; /* bust group-stop */
479 goto cont;
480 }
481
482 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
483 strerror(errno));
484 goto error;
485 }
486
487 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
488 si.si_pid == pid)
489 break;
490
491 cont:
492 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
493 if (errno == ESRCH)
494 goto disappeared;
495
496 ksft_test_result_fail("PTRACE_CONT: %s\n",
497 strerror(errno));
498 goto error;
499 }
500 }
501
502 /* FPSIMD via SVE regset */
503 ptrace_sve_fpsimd(child);
504
505 /* prctl() flags */
506 ptrace_set_get_inherit(child);
507
508 /* Step through every possible VQ */
509 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
510 vl = sve_vl_from_vq(vq);
511
512 /* First, try to set this vector length */
513 ptrace_set_get_vl(child, vl, &vl_supported);
514
515 /* If the VL is supported validate data set/get */
516 if (vl_supported) {
517 ptrace_set_sve_get_sve_data(child, vl);
518 ptrace_set_sve_get_fpsimd_data(child, vl);
519 } else {
520 ksft_test_result_skip("set SVE get SVE for VL %d\n", vl);
521 ksft_test_result_skip("set SVE get FPSIMD for VL %d\n", vl);
522 }
523 }
524
525 ret = EXIT_SUCCESS;
526
527 error:
528 kill(child, SIGKILL);
529
530 disappeared:
531 return ret;
532 }
533
main(void)534 int main(void)
535 {
536 int ret = EXIT_SUCCESS;
537 pid_t child;
538
539 srandom(getpid());
540
541 ksft_print_header();
542 ksft_set_plan(EXPECTED_TESTS);
543
544 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
545 ksft_exit_skip("SVE not available\n");
546
547 child = fork();
548 if (!child)
549 return do_child();
550
551 if (do_parent(child))
552 ret = EXIT_FAILURE;
553
554 ksft_print_cnts();
555
556 return ret;
557 }
558