1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015-2021 ARM Limited.
4 * Original author: Dave Martin <Dave.Martin@arm.com>
14 #include <sys/prctl.h>
15 #include <sys/ptrace.h>
16 #include <sys/types.h>
19 #include <asm/sigcontext.h>
20 #include <asm/ptrace.h>
22 #include "../../kselftest.h"
24 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
26 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
28 #define NT_ARM_SVE 0x405
33 unsigned long hwcap_type;
39 static const struct vec_type vec_types[] = {
42 .hwcap_type = AT_HWCAP,
45 .prctl_set = PR_SVE_SET_VL,
49 #define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
51 #define FPSIMD_TESTS 3
53 #define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
55 static void fill_buf(char *buf, size_t size)
59 for (i = 0; i < size; i++)
63 static int do_child(void)
65 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
66 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
69 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
74 static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
78 iov.iov_base = fpsimd;
79 iov.iov_len = sizeof(*fpsimd);
80 return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
83 static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
84 void **buf, size_t *size)
86 struct user_sve_header *sve;
88 size_t sz = sizeof *sve;
93 p = realloc(*buf, sz);
105 if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov))
121 static int set_sve(pid_t pid, const struct vec_type *type,
122 const struct user_sve_header *sve)
126 iov.iov_base = (void *)sve;
127 iov.iov_len = sve->size;
128 return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
131 /* Validate setting and getting the inherit flag */
132 static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)
134 struct user_sve_header sve;
135 struct user_sve_header *new_sve = NULL;
136 size_t new_sve_size = 0;
139 /* First set the flag */
140 memset(&sve, 0, sizeof(sve));
141 sve.size = sizeof(sve);
142 sve.vl = sve_vl_from_vq(SVE_VQ_MIN);
143 sve.flags = SVE_PT_VL_INHERIT;
144 ret = set_sve(child, type, &sve);
146 ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",
152 * Read back the new register state and verify that we have
153 * set the flags we expected.
155 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
156 ksft_test_result_fail("Failed to read %s SVE flags\n",
161 ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
162 "%s SVE_PT_VL_INHERIT set\n", type->name);
165 sve.flags &= ~SVE_PT_VL_INHERIT;
166 ret = set_sve(child, type, &sve);
168 ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",
173 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
174 ksft_test_result_fail("Failed to read %s SVE flags\n",
179 ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
180 "%s SVE_PT_VL_INHERIT cleared\n", type->name);
185 /* Validate attempting to set the specfied VL via ptrace */
186 static void ptrace_set_get_vl(pid_t child, const struct vec_type *type,
187 unsigned int vl, bool *supported)
189 struct user_sve_header sve;
190 struct user_sve_header *new_sve = NULL;
191 size_t new_sve_size = 0;
196 /* Check if the VL is supported in this process */
197 prctl_vl = prctl(type->prctl_set, vl);
199 ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",
200 type->name, strerror(errno), errno);
202 /* If the VL is not supported then a supported VL will be returned */
203 *supported = (prctl_vl == vl);
205 /* Set the VL by doing a set with no register payload */
206 memset(&sve, 0, sizeof(sve));
207 sve.size = sizeof(sve);
209 ret = set_sve(child, type, &sve);
211 ksft_test_result_fail("Failed to set %s VL %u\n",
217 * Read back the new register state and verify that we have the
218 * same VL that we got from prctl() on ourselves.
220 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
221 ksft_test_result_fail("Failed to read %s VL %u\n",
226 ksft_test_result(new_sve->vl = prctl_vl, "Set %s VL %u\n",
232 static void check_u32(unsigned int vl, const char *reg,
233 uint32_t *in, uint32_t *out, int *errors)
236 printf("# VL %d %s wrote %x read %x\n",
242 /* Access the FPSIMD registers via the SVE regset */
243 static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
247 struct user_sve_header *sve;
248 struct user_fpsimd_state *fpsimd, new_fpsimd;
252 /* New process should start with FPSIMD registers only */
253 sve = get_sve(child, type, &svebuf, &svebufsz);
255 ksft_test_result_fail("get_sve(%s): %s\n",
256 type->name, strerror(errno));
260 ksft_test_result_pass("get_sve(%s FPSIMD)\n", type->name);
263 ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
264 "Set FPSIMD registers via %s\n", type->name);
265 if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
268 /* Try to set a known FPSIMD state via PT_REGS_SVE */
269 fpsimd = (struct user_fpsimd_state *)((char *)sve +
270 SVE_PT_FPSIMD_OFFSET);
271 for (i = 0; i < 32; ++i) {
272 p = (unsigned char *)&fpsimd->vregs[i];
274 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
278 if (set_sve(child, type, sve)) {
279 ksft_test_result_fail("set_sve(%s FPSIMD): %s\n",
280 type->name, strerror(errno));
285 /* Verify via the FPSIMD regset */
286 if (get_fpsimd(child, &new_fpsimd)) {
287 ksft_test_result_fail("get_fpsimd(): %s\n",
291 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
292 ksft_test_result_pass("%s get_fpsimd() gave same state\n",
295 ksft_test_result_fail("%s get_fpsimd() gave different state\n",
302 /* Validate attempting to set SVE data and read SVE data */
303 static void ptrace_set_sve_get_sve_data(pid_t child,
304 const struct vec_type *type,
308 void *read_buf = NULL;
309 struct user_sve_header *write_sve;
310 struct user_sve_header *read_sve;
311 size_t read_sve_size = 0;
312 unsigned int vq = sve_vq_from_vl(vl);
317 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
318 write_buf = malloc(data_size);
320 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
321 data_size, type->name, vl);
324 write_sve = write_buf;
326 /* Set up some data and write it out */
327 memset(write_sve, 0, data_size);
328 write_sve->size = data_size;
330 write_sve->flags = SVE_PT_REGS_SVE;
332 for (i = 0; i < __SVE_NUM_ZREGS; i++)
333 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
334 SVE_PT_SVE_ZREG_SIZE(vq));
336 for (i = 0; i < __SVE_NUM_PREGS; i++)
337 fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
338 SVE_PT_SVE_PREG_SIZE(vq));
340 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
341 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
343 /* TODO: Generate a valid FFR pattern */
345 ret = set_sve(child, type, write_sve);
347 ksft_test_result_fail("Failed to set %s VL %u data\n",
352 /* Read the data back */
353 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
354 ksft_test_result_fail("Failed to read %s VL %u data\n",
360 /* We might read more data if there's extensions we don't know */
361 if (read_sve->size < write_sve->size) {
362 ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
363 type->name, write_sve->size,
368 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
369 if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
370 read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
371 SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
372 printf("# Mismatch in %u Z%d\n", vl, i);
377 for (i = 0; i < __SVE_NUM_PREGS; i++) {
378 if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
379 read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
380 SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
381 printf("# Mismatch in %u P%d\n", vl, i);
386 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
387 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
388 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
389 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
391 ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
400 /* Validate attempting to set SVE data and read SVE data */
401 static void ptrace_set_sve_get_fpsimd_data(pid_t child,
402 const struct vec_type *type,
406 struct user_sve_header *write_sve;
407 unsigned int vq = sve_vq_from_vl(vl);
408 struct user_fpsimd_state fpsimd_state;
413 if (__BYTE_ORDER == __BIG_ENDIAN) {
414 ksft_test_result_skip("Big endian not supported\n");
418 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
419 write_buf = malloc(data_size);
421 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
422 data_size, type->name, vl);
425 write_sve = write_buf;
427 /* Set up some data and write it out */
428 memset(write_sve, 0, data_size);
429 write_sve->size = data_size;
431 write_sve->flags = SVE_PT_REGS_SVE;
433 for (i = 0; i < __SVE_NUM_ZREGS; i++)
434 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
435 SVE_PT_SVE_ZREG_SIZE(vq));
437 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
438 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
440 ret = set_sve(child, type, write_sve);
442 ksft_test_result_fail("Failed to set %s VL %u data\n",
447 /* Read the data back */
448 if (get_fpsimd(child, &fpsimd_state)) {
449 ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
454 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
458 * Z regs are stored endianness invariant, this won't
459 * work for big endian
461 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
464 if (tmp != fpsimd_state.vregs[i]) {
465 printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
471 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
472 &fpsimd_state.fpsr, &errors);
473 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
474 &fpsimd_state.fpcr, &errors);
476 ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
483 static int do_parent(pid_t child)
485 int ret = EXIT_FAILURE;
492 /* Attach to the child */
503 * This should never happen but it's hard to flag in
509 if (WIFEXITED(status) || WIFSIGNALED(status))
510 ksft_exit_fail_msg("Child died unexpectedly\n");
512 if (!WIFSTOPPED(status))
515 sig = WSTOPSIG(status);
517 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
521 if (errno == EINVAL) {
522 sig = 0; /* bust group-stop */
526 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
531 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
536 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
540 ksft_test_result_fail("PTRACE_CONT: %s\n",
546 for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
547 /* FPSIMD via SVE regset */
548 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
549 ptrace_sve_fpsimd(child, &vec_types[i]);
551 ksft_test_result_skip("%s FPSIMD get via SVE\n",
553 ksft_test_result_skip("%s FPSIMD set via SVE\n",
555 ksft_test_result_skip("%s set read via FPSIMD\n",
560 ptrace_set_get_inherit(child, &vec_types[i]);
562 /* Step through every possible VQ */
563 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
564 vl = sve_vl_from_vq(vq);
566 /* First, try to set this vector length */
567 if (getauxval(vec_types[i].hwcap_type) &
568 vec_types[i].hwcap) {
569 ptrace_set_get_vl(child, &vec_types[i], vl,
572 ksft_test_result_skip("%s get/set VL %d\n",
573 vec_types[i].name, vl);
574 vl_supported = false;
577 /* If the VL is supported validate data set/get */
579 ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
580 ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
582 ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
583 vec_types[i].name, vl);
584 ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
585 vec_types[i].name, vl);
593 kill(child, SIGKILL);
601 int ret = EXIT_SUCCESS;
607 ksft_set_plan(EXPECTED_TESTS);
609 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
610 ksft_exit_skip("SVE not available\n");
616 if (do_parent(child))