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