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 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
25 #ifndef NT_ARM_SVE
26 #define NT_ARM_SVE 0x405
27 #endif
28
29 #ifndef NT_ARM_SSVE
30 #define NT_ARM_SSVE 0x40b
31 #endif
32
33 /*
34 * The architecture defines the maximum VQ as 16 but for extensibility
35 * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
36 * a *lot* more tests than are useful if we use it. Until the
37 * architecture is extended let's limit our coverage to what is
38 * currently allowed, plus one extra to ensure we cover constraining
39 * the VL as expected.
40 */
41 #define TEST_VQ_MAX 17
42
43 struct vec_type {
44 const char *name;
45 unsigned long hwcap_type;
46 unsigned long hwcap;
47 int regset;
48 int prctl_set;
49 };
50
51 static const struct vec_type vec_types[] = {
52 {
53 .name = "SVE",
54 .hwcap_type = AT_HWCAP,
55 .hwcap = HWCAP_SVE,
56 .regset = NT_ARM_SVE,
57 .prctl_set = PR_SVE_SET_VL,
58 },
59 {
60 .name = "Streaming SVE",
61 .hwcap_type = AT_HWCAP2,
62 .hwcap = HWCAP2_SME,
63 .regset = NT_ARM_SSVE,
64 .prctl_set = PR_SME_SET_VL,
65 },
66 };
67
68 #define VL_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
69 #define FLAG_TESTS 2
70 #define FPSIMD_TESTS 2
71
72 #define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
73
fill_buf(char * buf,size_t size)74 static void fill_buf(char *buf, size_t size)
75 {
76 int i;
77
78 for (i = 0; i < size; i++)
79 buf[i] = random();
80 }
81
do_child(void)82 static int do_child(void)
83 {
84 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
85 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
86
87 if (raise(SIGSTOP))
88 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
89
90 return EXIT_SUCCESS;
91 }
92
get_fpsimd(pid_t pid,struct user_fpsimd_state * fpsimd)93 static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
94 {
95 struct iovec iov;
96
97 iov.iov_base = fpsimd;
98 iov.iov_len = sizeof(*fpsimd);
99 return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
100 }
101
set_fpsimd(pid_t pid,struct user_fpsimd_state * fpsimd)102 static int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
103 {
104 struct iovec iov;
105
106 iov.iov_base = fpsimd;
107 iov.iov_len = sizeof(*fpsimd);
108 return ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);
109 }
110
get_sve(pid_t pid,const struct vec_type * type,void ** buf,size_t * size)111 static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
112 void **buf, size_t *size)
113 {
114 struct user_sve_header *sve;
115 void *p;
116 size_t sz = sizeof *sve;
117 struct iovec iov;
118
119 while (1) {
120 if (*size < sz) {
121 p = realloc(*buf, sz);
122 if (!p) {
123 errno = ENOMEM;
124 goto error;
125 }
126
127 *buf = p;
128 *size = sz;
129 }
130
131 iov.iov_base = *buf;
132 iov.iov_len = sz;
133 if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov))
134 goto error;
135
136 sve = *buf;
137 if (sve->size <= sz)
138 break;
139
140 sz = sve->size;
141 }
142
143 return sve;
144
145 error:
146 return NULL;
147 }
148
set_sve(pid_t pid,const struct vec_type * type,const struct user_sve_header * sve)149 static int set_sve(pid_t pid, const struct vec_type *type,
150 const struct user_sve_header *sve)
151 {
152 struct iovec iov;
153
154 iov.iov_base = (void *)sve;
155 iov.iov_len = sve->size;
156 return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
157 }
158
159 /* Validate setting and getting the inherit flag */
ptrace_set_get_inherit(pid_t child,const struct vec_type * type)160 static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)
161 {
162 struct user_sve_header sve;
163 struct user_sve_header *new_sve = NULL;
164 size_t new_sve_size = 0;
165 int ret;
166
167 /* First set the flag */
168 memset(&sve, 0, sizeof(sve));
169 sve.size = sizeof(sve);
170 sve.vl = sve_vl_from_vq(SVE_VQ_MIN);
171 sve.flags = SVE_PT_VL_INHERIT | SVE_PT_REGS_SVE;
172 ret = set_sve(child, type, &sve);
173 if (ret != 0) {
174 ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",
175 type->name);
176 return;
177 }
178
179 /*
180 * Read back the new register state and verify that we have
181 * set the flags we expected.
182 */
183 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
184 ksft_test_result_fail("Failed to read %s SVE flags\n",
185 type->name);
186 return;
187 }
188
189 ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
190 "%s SVE_PT_VL_INHERIT set\n", type->name);
191
192 /* Now clear */
193 sve.flags &= ~SVE_PT_VL_INHERIT;
194 ret = set_sve(child, type, &sve);
195 if (ret != 0) {
196 ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",
197 type->name);
198 return;
199 }
200
201 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
202 ksft_test_result_fail("Failed to read %s SVE flags\n",
203 type->name);
204 return;
205 }
206
207 ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
208 "%s SVE_PT_VL_INHERIT cleared\n", type->name);
209
210 free(new_sve);
211 }
212
213 /* Validate attempting to set the specfied VL via ptrace */
ptrace_set_get_vl(pid_t child,const struct vec_type * type,unsigned int vl,bool * supported)214 static void ptrace_set_get_vl(pid_t child, const struct vec_type *type,
215 unsigned int vl, bool *supported)
216 {
217 struct user_sve_header sve;
218 struct user_sve_header *new_sve = NULL;
219 size_t new_sve_size = 0;
220 int ret, prctl_vl;
221
222 *supported = false;
223
224 /* Check if the VL is supported in this process */
225 prctl_vl = prctl(type->prctl_set, vl);
226 if (prctl_vl == -1)
227 ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",
228 type->name, strerror(errno), errno);
229
230 /* If the VL is not supported then a supported VL will be returned */
231 *supported = (prctl_vl == vl);
232
233 /* Set the VL by doing a set with no register payload */
234 memset(&sve, 0, sizeof(sve));
235 sve.size = sizeof(sve);
236 sve.flags = SVE_PT_REGS_SVE;
237 sve.vl = vl;
238 ret = set_sve(child, type, &sve);
239 if (ret != 0) {
240 ksft_test_result_fail("Failed to set %s VL %u\n",
241 type->name, vl);
242 return;
243 }
244
245 /*
246 * Read back the new register state and verify that we have the
247 * same VL that we got from prctl() on ourselves.
248 */
249 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
250 ksft_test_result_fail("Failed to read %s VL %u\n",
251 type->name, vl);
252 return;
253 }
254
255 ksft_test_result(new_sve->vl == prctl_vl, "Set %s VL %u\n",
256 type->name, vl);
257
258 free(new_sve);
259 }
260
check_u32(unsigned int vl,const char * reg,uint32_t * in,uint32_t * out,int * errors)261 static void check_u32(unsigned int vl, const char *reg,
262 uint32_t *in, uint32_t *out, int *errors)
263 {
264 if (*in != *out) {
265 printf("# VL %d %s wrote %x read %x\n",
266 vl, reg, *in, *out);
267 (*errors)++;
268 }
269 }
270
271 /* Access the FPSIMD registers via the SVE regset */
ptrace_sve_fpsimd(pid_t child,const struct vec_type * type)272 static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
273 {
274 void *svebuf;
275 struct user_sve_header *sve;
276 struct user_fpsimd_state *fpsimd, new_fpsimd;
277 unsigned int i, j;
278 unsigned char *p;
279 int ret;
280
281 svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
282 if (!svebuf) {
283 ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");
284 return;
285 }
286
287 memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
288 sve = svebuf;
289 sve->flags = SVE_PT_REGS_FPSIMD;
290 sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);
291 sve->vl = 16; /* We don't care what the VL is */
292
293 /* Try to set a known FPSIMD state via PT_REGS_SVE */
294 fpsimd = (struct user_fpsimd_state *)((char *)sve +
295 SVE_PT_FPSIMD_OFFSET);
296 for (i = 0; i < 32; ++i) {
297 p = (unsigned char *)&fpsimd->vregs[i];
298
299 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
300 p[j] = j;
301 }
302
303 ret = set_sve(child, type, sve);
304 ksft_test_result(ret == 0, "%s FPSIMD set via SVE: %d\n",
305 type->name, ret);
306 if (ret)
307 goto out;
308
309 /* Verify via the FPSIMD regset */
310 if (get_fpsimd(child, &new_fpsimd)) {
311 ksft_test_result_fail("get_fpsimd(): %s\n",
312 strerror(errno));
313 goto out;
314 }
315 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
316 ksft_test_result_pass("%s get_fpsimd() gave same state\n",
317 type->name);
318 else
319 ksft_test_result_fail("%s get_fpsimd() gave different state\n",
320 type->name);
321
322 out:
323 free(svebuf);
324 }
325
326 /* Validate attempting to set SVE data and read SVE data */
ptrace_set_sve_get_sve_data(pid_t child,const struct vec_type * type,unsigned int vl)327 static void ptrace_set_sve_get_sve_data(pid_t child,
328 const struct vec_type *type,
329 unsigned int vl)
330 {
331 void *write_buf;
332 void *read_buf = NULL;
333 struct user_sve_header *write_sve;
334 struct user_sve_header *read_sve;
335 size_t read_sve_size = 0;
336 unsigned int vq = sve_vq_from_vl(vl);
337 int ret, i;
338 size_t data_size;
339 int errors = 0;
340
341 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
342 write_buf = malloc(data_size);
343 if (!write_buf) {
344 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
345 data_size, type->name, vl);
346 return;
347 }
348 write_sve = write_buf;
349
350 /* Set up some data and write it out */
351 memset(write_sve, 0, data_size);
352 write_sve->size = data_size;
353 write_sve->vl = vl;
354 write_sve->flags = SVE_PT_REGS_SVE;
355
356 for (i = 0; i < __SVE_NUM_ZREGS; i++)
357 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
358 SVE_PT_SVE_ZREG_SIZE(vq));
359
360 for (i = 0; i < __SVE_NUM_PREGS; i++)
361 fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
362 SVE_PT_SVE_PREG_SIZE(vq));
363
364 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
365 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
366
367 /* TODO: Generate a valid FFR pattern */
368
369 ret = set_sve(child, type, write_sve);
370 if (ret != 0) {
371 ksft_test_result_fail("Failed to set %s VL %u data\n",
372 type->name, vl);
373 goto out;
374 }
375
376 /* Read the data back */
377 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
378 ksft_test_result_fail("Failed to read %s VL %u data\n",
379 type->name, vl);
380 goto out;
381 }
382 read_sve = read_buf;
383
384 /* We might read more data if there's extensions we don't know */
385 if (read_sve->size < write_sve->size) {
386 ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
387 type->name, write_sve->size,
388 read_sve->size);
389 goto out_read;
390 }
391
392 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
393 if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
394 read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
395 SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
396 printf("# Mismatch in %u Z%d\n", vl, i);
397 errors++;
398 }
399 }
400
401 for (i = 0; i < __SVE_NUM_PREGS; i++) {
402 if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
403 read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
404 SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
405 printf("# Mismatch in %u P%d\n", vl, i);
406 errors++;
407 }
408 }
409
410 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
411 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
412 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
413 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
414
415 ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
416 type->name, vl);
417
418 out_read:
419 free(read_buf);
420 out:
421 free(write_buf);
422 }
423
424 /* Validate attempting to set SVE data and read it via the FPSIMD regset */
ptrace_set_sve_get_fpsimd_data(pid_t child,const struct vec_type * type,unsigned int vl)425 static void ptrace_set_sve_get_fpsimd_data(pid_t child,
426 const struct vec_type *type,
427 unsigned int vl)
428 {
429 void *write_buf;
430 struct user_sve_header *write_sve;
431 unsigned int vq = sve_vq_from_vl(vl);
432 struct user_fpsimd_state fpsimd_state;
433 int ret, i;
434 size_t data_size;
435 int errors = 0;
436
437 if (__BYTE_ORDER == __BIG_ENDIAN) {
438 ksft_test_result_skip("Big endian not supported\n");
439 return;
440 }
441
442 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
443 write_buf = malloc(data_size);
444 if (!write_buf) {
445 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
446 data_size, type->name, vl);
447 return;
448 }
449 write_sve = write_buf;
450
451 /* Set up some data and write it out */
452 memset(write_sve, 0, data_size);
453 write_sve->size = data_size;
454 write_sve->vl = vl;
455 write_sve->flags = SVE_PT_REGS_SVE;
456
457 for (i = 0; i < __SVE_NUM_ZREGS; i++)
458 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
459 SVE_PT_SVE_ZREG_SIZE(vq));
460
461 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
462 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
463
464 ret = set_sve(child, type, write_sve);
465 if (ret != 0) {
466 ksft_test_result_fail("Failed to set %s VL %u data\n",
467 type->name, vl);
468 goto out;
469 }
470
471 /* Read the data back */
472 if (get_fpsimd(child, &fpsimd_state)) {
473 ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
474 type->name, vl);
475 goto out;
476 }
477
478 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
479 __uint128_t tmp = 0;
480
481 /*
482 * Z regs are stored endianness invariant, this won't
483 * work for big endian
484 */
485 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
486 sizeof(tmp));
487
488 if (tmp != fpsimd_state.vregs[i]) {
489 printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
490 type->name, vl, i);
491 errors++;
492 }
493 }
494
495 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
496 &fpsimd_state.fpsr, &errors);
497 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
498 &fpsimd_state.fpcr, &errors);
499
500 ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
501 type->name, vl);
502
503 out:
504 free(write_buf);
505 }
506
507 /* Validate attempting to set FPSIMD data and read it via the SVE regset */
ptrace_set_fpsimd_get_sve_data(pid_t child,const struct vec_type * type,unsigned int vl)508 static void ptrace_set_fpsimd_get_sve_data(pid_t child,
509 const struct vec_type *type,
510 unsigned int vl)
511 {
512 void *read_buf = NULL;
513 unsigned char *p;
514 struct user_sve_header *read_sve;
515 unsigned int vq = sve_vq_from_vl(vl);
516 struct user_fpsimd_state write_fpsimd;
517 int ret, i, j;
518 size_t read_sve_size = 0;
519 size_t expected_size;
520 int errors = 0;
521
522 if (__BYTE_ORDER == __BIG_ENDIAN) {
523 ksft_test_result_skip("Big endian not supported\n");
524 return;
525 }
526
527 for (i = 0; i < 32; ++i) {
528 p = (unsigned char *)&write_fpsimd.vregs[i];
529
530 for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)
531 p[j] = j;
532 }
533
534 ret = set_fpsimd(child, &write_fpsimd);
535 if (ret != 0) {
536 ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",
537 ret);
538 return;
539 }
540
541 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
542 ksft_test_result_fail("Failed to read %s VL %u data\n",
543 type->name, vl);
544 return;
545 }
546 read_sve = read_buf;
547
548 if (read_sve->vl != vl) {
549 ksft_test_result_fail("Child VL != expected VL %d\n",
550 read_sve->vl, vl);
551 goto out;
552 }
553
554 /* The kernel may return either SVE or FPSIMD format */
555 switch (read_sve->flags & SVE_PT_REGS_MASK) {
556 case SVE_PT_REGS_FPSIMD:
557 expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);
558 if (read_sve_size < expected_size) {
559 ksft_test_result_fail("Read %d bytes, expected %d\n",
560 read_sve_size, expected_size);
561 goto out;
562 }
563
564 ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,
565 sizeof(write_fpsimd));
566 if (ret != 0) {
567 ksft_print_msg("Read FPSIMD data mismatch\n");
568 errors++;
569 }
570 break;
571
572 case SVE_PT_REGS_SVE:
573 expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
574 if (read_sve_size < expected_size) {
575 ksft_test_result_fail("Read %d bytes, expected %d\n",
576 read_sve_size, expected_size);
577 goto out;
578 }
579
580 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
581 __uint128_t tmp = 0;
582
583 /*
584 * Z regs are stored endianness invariant, this won't
585 * work for big endian
586 */
587 memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
588 sizeof(tmp));
589
590 if (tmp != write_fpsimd.vregs[i]) {
591 ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",
592 type->name, vl, i, i);
593 errors++;
594 }
595 }
596
597 check_u32(vl, "FPSR", &write_fpsimd.fpsr,
598 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
599 check_u32(vl, "FPCR", &write_fpsimd.fpcr,
600 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
601 break;
602 default:
603 ksft_print_msg("Unexpected regs type %d\n",
604 read_sve->flags & SVE_PT_REGS_MASK);
605 errors++;
606 break;
607 }
608
609 ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",
610 type->name, vl);
611
612 out:
613 free(read_buf);
614 }
615
do_parent(pid_t child)616 static int do_parent(pid_t child)
617 {
618 int ret = EXIT_FAILURE;
619 pid_t pid;
620 int status, i;
621 siginfo_t si;
622 unsigned int vq, vl;
623 bool vl_supported;
624
625 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
626
627 /* Attach to the child */
628 while (1) {
629 int sig;
630
631 pid = wait(&status);
632 if (pid == -1) {
633 perror("wait");
634 goto error;
635 }
636
637 /*
638 * This should never happen but it's hard to flag in
639 * the framework.
640 */
641 if (pid != child)
642 continue;
643
644 if (WIFEXITED(status) || WIFSIGNALED(status))
645 ksft_exit_fail_msg("Child died unexpectedly\n");
646
647 if (!WIFSTOPPED(status))
648 goto error;
649
650 sig = WSTOPSIG(status);
651
652 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
653 if (errno == ESRCH)
654 goto disappeared;
655
656 if (errno == EINVAL) {
657 sig = 0; /* bust group-stop */
658 goto cont;
659 }
660
661 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
662 strerror(errno));
663 goto error;
664 }
665
666 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
667 si.si_pid == pid)
668 break;
669
670 cont:
671 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
672 if (errno == ESRCH)
673 goto disappeared;
674
675 ksft_test_result_fail("PTRACE_CONT: %s\n",
676 strerror(errno));
677 goto error;
678 }
679 }
680
681 for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
682 /* FPSIMD via SVE regset */
683 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
684 ptrace_sve_fpsimd(child, &vec_types[i]);
685 } else {
686 ksft_test_result_skip("%s FPSIMD set via SVE\n",
687 vec_types[i].name);
688 ksft_test_result_skip("%s FPSIMD read\n",
689 vec_types[i].name);
690 }
691
692 /* prctl() flags */
693 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
694 ptrace_set_get_inherit(child, &vec_types[i]);
695 } else {
696 ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
697 vec_types[i].name);
698 ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
699 vec_types[i].name);
700 }
701
702 /* Step through every possible VQ */
703 for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
704 vl = sve_vl_from_vq(vq);
705
706 /* First, try to set this vector length */
707 if (getauxval(vec_types[i].hwcap_type) &
708 vec_types[i].hwcap) {
709 ptrace_set_get_vl(child, &vec_types[i], vl,
710 &vl_supported);
711 } else {
712 ksft_test_result_skip("%s get/set VL %d\n",
713 vec_types[i].name, vl);
714 vl_supported = false;
715 }
716
717 /* If the VL is supported validate data set/get */
718 if (vl_supported) {
719 ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
720 ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
721 ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);
722 } else {
723 ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
724 vec_types[i].name, vl);
725 ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
726 vec_types[i].name, vl);
727 ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",
728 vec_types[i].name, vl);
729 }
730 }
731 }
732
733 ret = EXIT_SUCCESS;
734
735 error:
736 kill(child, SIGKILL);
737
738 disappeared:
739 return ret;
740 }
741
main(void)742 int main(void)
743 {
744 int ret = EXIT_SUCCESS;
745 pid_t child;
746
747 srandom(getpid());
748
749 ksft_print_header();
750 ksft_set_plan(EXPECTED_TESTS);
751
752 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
753 ksft_exit_skip("SVE not available\n");
754
755 child = fork();
756 if (!child)
757 return do_child();
758
759 if (do_parent(child))
760 ret = EXIT_FAILURE;
761
762 ksft_print_cnts();
763
764 return ret;
765 }
766