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;
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.vl = vl;
237 ret = set_sve(child, type, &sve);
238 if (ret != 0) {
239 ksft_test_result_fail("Failed to set %s VL %u\n",
240 type->name, vl);
241 return;
242 }
243
244 /*
245 * Read back the new register state and verify that we have the
246 * same VL that we got from prctl() on ourselves.
247 */
248 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
249 ksft_test_result_fail("Failed to read %s VL %u\n",
250 type->name, vl);
251 return;
252 }
253
254 ksft_test_result(new_sve->vl = prctl_vl, "Set %s VL %u\n",
255 type->name, vl);
256
257 free(new_sve);
258 }
259
check_u32(unsigned int vl,const char * reg,uint32_t * in,uint32_t * out,int * errors)260 static void check_u32(unsigned int vl, const char *reg,
261 uint32_t *in, uint32_t *out, int *errors)
262 {
263 if (*in != *out) {
264 printf("# VL %d %s wrote %x read %x\n",
265 vl, reg, *in, *out);
266 (*errors)++;
267 }
268 }
269
270 /* Access the FPSIMD registers via the SVE regset */
ptrace_sve_fpsimd(pid_t child,const struct vec_type * type)271 static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
272 {
273 void *svebuf;
274 struct user_sve_header *sve;
275 struct user_fpsimd_state *fpsimd, new_fpsimd;
276 unsigned int i, j;
277 unsigned char *p;
278 int ret;
279
280 svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
281 if (!svebuf) {
282 ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");
283 return;
284 }
285
286 memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
287 sve = svebuf;
288 sve->flags = SVE_PT_REGS_FPSIMD;
289 sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);
290 sve->vl = 16; /* We don't care what the VL is */
291
292 /* Try to set a known FPSIMD state via PT_REGS_SVE */
293 fpsimd = (struct user_fpsimd_state *)((char *)sve +
294 SVE_PT_FPSIMD_OFFSET);
295 for (i = 0; i < 32; ++i) {
296 p = (unsigned char *)&fpsimd->vregs[i];
297
298 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
299 p[j] = j;
300 }
301
302 ret = set_sve(child, type, sve);
303 ksft_test_result(ret == 0, "%s FPSIMD set via SVE: %d\n",
304 type->name, ret);
305 if (ret)
306 goto out;
307
308 /* Verify via the FPSIMD regset */
309 if (get_fpsimd(child, &new_fpsimd)) {
310 ksft_test_result_fail("get_fpsimd(): %s\n",
311 strerror(errno));
312 goto out;
313 }
314 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
315 ksft_test_result_pass("%s get_fpsimd() gave same state\n",
316 type->name);
317 else
318 ksft_test_result_fail("%s get_fpsimd() gave different state\n",
319 type->name);
320
321 out:
322 free(svebuf);
323 }
324
325 /* 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)326 static void ptrace_set_sve_get_sve_data(pid_t child,
327 const struct vec_type *type,
328 unsigned int vl)
329 {
330 void *write_buf;
331 void *read_buf = NULL;
332 struct user_sve_header *write_sve;
333 struct user_sve_header *read_sve;
334 size_t read_sve_size = 0;
335 unsigned int vq = sve_vq_from_vl(vl);
336 int ret, i;
337 size_t data_size;
338 int errors = 0;
339
340 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
341 write_buf = malloc(data_size);
342 if (!write_buf) {
343 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
344 data_size, type->name, vl);
345 return;
346 }
347 write_sve = write_buf;
348
349 /* Set up some data and write it out */
350 memset(write_sve, 0, data_size);
351 write_sve->size = data_size;
352 write_sve->vl = vl;
353 write_sve->flags = SVE_PT_REGS_SVE;
354
355 for (i = 0; i < __SVE_NUM_ZREGS; i++)
356 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
357 SVE_PT_SVE_ZREG_SIZE(vq));
358
359 for (i = 0; i < __SVE_NUM_PREGS; i++)
360 fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
361 SVE_PT_SVE_PREG_SIZE(vq));
362
363 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
364 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
365
366 /* TODO: Generate a valid FFR pattern */
367
368 ret = set_sve(child, type, write_sve);
369 if (ret != 0) {
370 ksft_test_result_fail("Failed to set %s VL %u data\n",
371 type->name, vl);
372 goto out;
373 }
374
375 /* Read the data back */
376 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
377 ksft_test_result_fail("Failed to read %s VL %u data\n",
378 type->name, vl);
379 goto out;
380 }
381 read_sve = read_buf;
382
383 /* We might read more data if there's extensions we don't know */
384 if (read_sve->size < write_sve->size) {
385 ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
386 type->name, write_sve->size,
387 read_sve->size);
388 goto out_read;
389 }
390
391 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
392 if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
393 read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
394 SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
395 printf("# Mismatch in %u Z%d\n", vl, i);
396 errors++;
397 }
398 }
399
400 for (i = 0; i < __SVE_NUM_PREGS; i++) {
401 if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
402 read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
403 SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
404 printf("# Mismatch in %u P%d\n", vl, i);
405 errors++;
406 }
407 }
408
409 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
410 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
411 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
412 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
413
414 ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
415 type->name, vl);
416
417 out_read:
418 free(read_buf);
419 out:
420 free(write_buf);
421 }
422
423 /* 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)424 static void ptrace_set_sve_get_fpsimd_data(pid_t child,
425 const struct vec_type *type,
426 unsigned int vl)
427 {
428 void *write_buf;
429 struct user_sve_header *write_sve;
430 unsigned int vq = sve_vq_from_vl(vl);
431 struct user_fpsimd_state fpsimd_state;
432 int ret, i;
433 size_t data_size;
434 int errors = 0;
435
436 if (__BYTE_ORDER == __BIG_ENDIAN) {
437 ksft_test_result_skip("Big endian not supported\n");
438 return;
439 }
440
441 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
442 write_buf = malloc(data_size);
443 if (!write_buf) {
444 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
445 data_size, type->name, vl);
446 return;
447 }
448 write_sve = write_buf;
449
450 /* Set up some data and write it out */
451 memset(write_sve, 0, data_size);
452 write_sve->size = data_size;
453 write_sve->vl = vl;
454 write_sve->flags = SVE_PT_REGS_SVE;
455
456 for (i = 0; i < __SVE_NUM_ZREGS; i++)
457 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
458 SVE_PT_SVE_ZREG_SIZE(vq));
459
460 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
461 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
462
463 ret = set_sve(child, type, write_sve);
464 if (ret != 0) {
465 ksft_test_result_fail("Failed to set %s VL %u data\n",
466 type->name, vl);
467 goto out;
468 }
469
470 /* Read the data back */
471 if (get_fpsimd(child, &fpsimd_state)) {
472 ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
473 type->name, vl);
474 goto out;
475 }
476
477 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
478 __uint128_t tmp = 0;
479
480 /*
481 * Z regs are stored endianness invariant, this won't
482 * work for big endian
483 */
484 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
485 sizeof(tmp));
486
487 if (tmp != fpsimd_state.vregs[i]) {
488 printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
489 type->name, vl, i);
490 errors++;
491 }
492 }
493
494 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
495 &fpsimd_state.fpsr, &errors);
496 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
497 &fpsimd_state.fpcr, &errors);
498
499 ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
500 type->name, vl);
501
502 out:
503 free(write_buf);
504 }
505
506 /* 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)507 static void ptrace_set_fpsimd_get_sve_data(pid_t child,
508 const struct vec_type *type,
509 unsigned int vl)
510 {
511 void *read_buf = NULL;
512 unsigned char *p;
513 struct user_sve_header *read_sve;
514 unsigned int vq = sve_vq_from_vl(vl);
515 struct user_fpsimd_state write_fpsimd;
516 int ret, i, j;
517 size_t read_sve_size = 0;
518 size_t expected_size;
519 int errors = 0;
520
521 if (__BYTE_ORDER == __BIG_ENDIAN) {
522 ksft_test_result_skip("Big endian not supported\n");
523 return;
524 }
525
526 for (i = 0; i < 32; ++i) {
527 p = (unsigned char *)&write_fpsimd.vregs[i];
528
529 for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)
530 p[j] = j;
531 }
532
533 ret = set_fpsimd(child, &write_fpsimd);
534 if (ret != 0) {
535 ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",
536 ret);
537 return;
538 }
539
540 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
541 ksft_test_result_fail("Failed to read %s VL %u data\n",
542 type->name, vl);
543 return;
544 }
545 read_sve = read_buf;
546
547 if (read_sve->vl != vl) {
548 ksft_test_result_fail("Child VL != expected VL %d\n",
549 read_sve->vl, vl);
550 goto out;
551 }
552
553 /* The kernel may return either SVE or FPSIMD format */
554 switch (read_sve->flags & SVE_PT_REGS_MASK) {
555 case SVE_PT_REGS_FPSIMD:
556 expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);
557 if (read_sve_size < expected_size) {
558 ksft_test_result_fail("Read %d bytes, expected %d\n",
559 read_sve_size, expected_size);
560 goto out;
561 }
562
563 ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,
564 sizeof(write_fpsimd));
565 if (ret != 0) {
566 ksft_print_msg("Read FPSIMD data mismatch\n");
567 errors++;
568 }
569 break;
570
571 case SVE_PT_REGS_SVE:
572 expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
573 if (read_sve_size < expected_size) {
574 ksft_test_result_fail("Read %d bytes, expected %d\n",
575 read_sve_size, expected_size);
576 goto out;
577 }
578
579 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
580 __uint128_t tmp = 0;
581
582 /*
583 * Z regs are stored endianness invariant, this won't
584 * work for big endian
585 */
586 memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
587 sizeof(tmp));
588
589 if (tmp != write_fpsimd.vregs[i]) {
590 ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",
591 type->name, vl, i, i);
592 errors++;
593 }
594 }
595
596 check_u32(vl, "FPSR", &write_fpsimd.fpsr,
597 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
598 check_u32(vl, "FPCR", &write_fpsimd.fpcr,
599 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
600 break;
601 default:
602 ksft_print_msg("Unexpected regs type %d\n",
603 read_sve->flags & SVE_PT_REGS_MASK);
604 errors++;
605 break;
606 }
607
608 ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",
609 type->name, vl);
610
611 out:
612 free(read_buf);
613 }
614
do_parent(pid_t child)615 static int do_parent(pid_t child)
616 {
617 int ret = EXIT_FAILURE;
618 pid_t pid;
619 int status, i;
620 siginfo_t si;
621 unsigned int vq, vl;
622 bool vl_supported;
623
624 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
625
626 /* Attach to the child */
627 while (1) {
628 int sig;
629
630 pid = wait(&status);
631 if (pid == -1) {
632 perror("wait");
633 goto error;
634 }
635
636 /*
637 * This should never happen but it's hard to flag in
638 * the framework.
639 */
640 if (pid != child)
641 continue;
642
643 if (WIFEXITED(status) || WIFSIGNALED(status))
644 ksft_exit_fail_msg("Child died unexpectedly\n");
645
646 if (!WIFSTOPPED(status))
647 goto error;
648
649 sig = WSTOPSIG(status);
650
651 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
652 if (errno == ESRCH)
653 goto disappeared;
654
655 if (errno == EINVAL) {
656 sig = 0; /* bust group-stop */
657 goto cont;
658 }
659
660 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
661 strerror(errno));
662 goto error;
663 }
664
665 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
666 si.si_pid == pid)
667 break;
668
669 cont:
670 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
671 if (errno == ESRCH)
672 goto disappeared;
673
674 ksft_test_result_fail("PTRACE_CONT: %s\n",
675 strerror(errno));
676 goto error;
677 }
678 }
679
680 for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
681 /* FPSIMD via SVE regset */
682 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
683 ptrace_sve_fpsimd(child, &vec_types[i]);
684 } else {
685 ksft_test_result_skip("%s FPSIMD set via SVE\n",
686 vec_types[i].name);
687 ksft_test_result_skip("%s FPSIMD read\n",
688 vec_types[i].name);
689 }
690
691 /* prctl() flags */
692 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
693 ptrace_set_get_inherit(child, &vec_types[i]);
694 } else {
695 ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
696 vec_types[i].name);
697 ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
698 vec_types[i].name);
699 }
700
701 /* Step through every possible VQ */
702 for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
703 vl = sve_vl_from_vq(vq);
704
705 /* First, try to set this vector length */
706 if (getauxval(vec_types[i].hwcap_type) &
707 vec_types[i].hwcap) {
708 ptrace_set_get_vl(child, &vec_types[i], vl,
709 &vl_supported);
710 } else {
711 ksft_test_result_skip("%s get/set VL %d\n",
712 vec_types[i].name, vl);
713 vl_supported = false;
714 }
715
716 /* If the VL is supported validate data set/get */
717 if (vl_supported) {
718 ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
719 ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
720 ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);
721 } else {
722 ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
723 vec_types[i].name, vl);
724 ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
725 vec_types[i].name, vl);
726 ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",
727 vec_types[i].name, vl);
728 }
729 }
730 }
731
732 ret = EXIT_SUCCESS;
733
734 error:
735 kill(child, SIGKILL);
736
737 disappeared:
738 return ret;
739 }
740
main(void)741 int main(void)
742 {
743 int ret = EXIT_SUCCESS;
744 pid_t child;
745
746 srandom(getpid());
747
748 ksft_print_header();
749 ksft_set_plan(EXPECTED_TESTS);
750
751 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
752 ksft_exit_skip("SVE not available\n");
753
754 child = fork();
755 if (!child)
756 return do_child();
757
758 if (do_parent(child))
759 ret = EXIT_FAILURE;
760
761 ksft_print_cnts();
762
763 return ret;
764 }
765