blob: a3c1e67441f9ec795688b85d518f876bf30d7a4d [file] [log] [blame]
Mark Brown0dca2762020-08-19 12:48:33 +01001// SPDX-License-Identifier: GPL-2.0-only
2/*
Mark Browna1d71112021-09-13 13:55:04 +01003 * Copyright (C) 2015-2021 ARM Limited.
Mark Brown0dca2762020-08-19 12:48:33 +01004 * Original author: Dave Martin <Dave.Martin@arm.com>
5 */
6#include <errno.h>
Mark Browna1d71112021-09-13 13:55:04 +01007#include <stdbool.h>
Mark Brown0dca2762020-08-19 12:48:33 +01008#include <stddef.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13#include <sys/auxv.h>
Mark Browna1d71112021-09-13 13:55:04 +010014#include <sys/prctl.h>
Mark Brown0dca2762020-08-19 12:48:33 +010015#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
Mark Brown18edbb62021-12-10 18:41:00 +000024#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
Mark Brown78d2d812021-09-13 13:54:58 +010025
Mark Brown0dca2762020-08-19 12:48:33 +010026/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
27#ifndef NT_ARM_SVE
28#define NT_ARM_SVE 0x405
29#endif
30
Mark Brown18edbb62021-12-10 18:41:00 +000031struct vec_type {
32 const char *name;
33 unsigned long hwcap_type;
34 unsigned long hwcap;
35 int regset;
36 int prctl_set;
37};
38
39static const struct vec_type vec_types[] = {
40 {
41 .name = "SVE",
42 .hwcap_type = AT_HWCAP,
43 .hwcap = HWCAP_SVE,
44 .regset = NT_ARM_SVE,
45 .prctl_set = PR_SVE_SET_VL,
46 },
47};
48
49#define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
50#define FLAG_TESTS 2
51#define FPSIMD_TESTS 3
52
53#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
54
Mark Browna1d71112021-09-13 13:55:04 +010055static void fill_buf(char *buf, size_t size)
Mark Brown0dca2762020-08-19 12:48:33 +010056{
Mark Browna1d71112021-09-13 13:55:04 +010057 int i;
Mark Brown0dca2762020-08-19 12:48:33 +010058
Mark Browna1d71112021-09-13 13:55:04 +010059 for (i = 0; i < size; i++)
60 buf[i] = random();
Mark Brown0dca2762020-08-19 12:48:33 +010061}
62
Mark Brown0dca2762020-08-19 12:48:33 +010063static int do_child(void)
64{
65 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
66 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
67
68 if (raise(SIGSTOP))
69 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
70
71 return EXIT_SUCCESS;
72}
73
Mark Brown9f7d03a2021-09-13 13:55:03 +010074static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
75{
76 struct iovec iov;
77
78 iov.iov_base = fpsimd;
79 iov.iov_len = sizeof(*fpsimd);
80 return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
81}
82
Mark Brown18edbb62021-12-10 18:41:00 +000083static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
84 void **buf, size_t *size)
Mark Brown0dca2762020-08-19 12:48:33 +010085{
86 struct user_sve_header *sve;
87 void *p;
88 size_t sz = sizeof *sve;
89 struct iovec iov;
90
91 while (1) {
92 if (*size < sz) {
93 p = realloc(*buf, sz);
94 if (!p) {
95 errno = ENOMEM;
96 goto error;
97 }
98
99 *buf = p;
100 *size = sz;
101 }
102
103 iov.iov_base = *buf;
104 iov.iov_len = sz;
Mark Brown18edbb62021-12-10 18:41:00 +0000105 if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov))
Mark Brown0dca2762020-08-19 12:48:33 +0100106 goto error;
107
108 sve = *buf;
109 if (sve->size <= sz)
110 break;
111
112 sz = sve->size;
113 }
114
115 return sve;
116
117error:
118 return NULL;
119}
120
Mark Brown18edbb62021-12-10 18:41:00 +0000121static int set_sve(pid_t pid, const struct vec_type *type,
122 const struct user_sve_header *sve)
Mark Brown0dca2762020-08-19 12:48:33 +0100123{
124 struct iovec iov;
125
126 iov.iov_base = (void *)sve;
127 iov.iov_len = sve->size;
Mark Brown18edbb62021-12-10 18:41:00 +0000128 return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
Mark Brown0dca2762020-08-19 12:48:33 +0100129}
130
Mark Brown0ba1ce12021-10-05 13:35:37 +0100131/* Validate setting and getting the inherit flag */
Mark Brown18edbb62021-12-10 18:41:00 +0000132static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)
Mark Brown0ba1ce12021-10-05 13:35:37 +0100133{
134 struct user_sve_header sve;
135 struct user_sve_header *new_sve = NULL;
136 size_t new_sve_size = 0;
137 int ret;
138
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;
Mark Brown18edbb62021-12-10 18:41:00 +0000144 ret = set_sve(child, type, &sve);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100145 if (ret != 0) {
Mark Brown18edbb62021-12-10 18:41:00 +0000146 ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",
147 type->name);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100148 return;
149 }
150
151 /*
152 * Read back the new register state and verify that we have
153 * set the flags we expected.
154 */
Mark Brown18edbb62021-12-10 18:41:00 +0000155 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
156 ksft_test_result_fail("Failed to read %s SVE flags\n",
157 type->name);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100158 return;
159 }
160
161 ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
Mark Brown18edbb62021-12-10 18:41:00 +0000162 "%s SVE_PT_VL_INHERIT set\n", type->name);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100163
164 /* Now clear */
165 sve.flags &= ~SVE_PT_VL_INHERIT;
Mark Brown18edbb62021-12-10 18:41:00 +0000166 ret = set_sve(child, type, &sve);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100167 if (ret != 0) {
Mark Brown18edbb62021-12-10 18:41:00 +0000168 ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",
169 type->name);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100170 return;
171 }
172
Mark Brown18edbb62021-12-10 18:41:00 +0000173 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);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100176 return;
177 }
178
179 ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
Mark Brown18edbb62021-12-10 18:41:00 +0000180 "%s SVE_PT_VL_INHERIT cleared\n", type->name);
Mark Brown0ba1ce12021-10-05 13:35:37 +0100181
182 free(new_sve);
183}
184
Mark Browna1d71112021-09-13 13:55:04 +0100185/* Validate attempting to set the specfied VL via ptrace */
Mark Brown18edbb62021-12-10 18:41:00 +0000186static void ptrace_set_get_vl(pid_t child, const struct vec_type *type,
187 unsigned int vl, bool *supported)
Mark Brown0dca2762020-08-19 12:48:33 +0100188{
Mark Browna1d71112021-09-13 13:55:04 +0100189 struct user_sve_header sve;
190 struct user_sve_header *new_sve = NULL;
191 size_t new_sve_size = 0;
192 int ret, prctl_vl;
Mark Brown0dca2762020-08-19 12:48:33 +0100193
Mark Browna1d71112021-09-13 13:55:04 +0100194 *supported = false;
Mark Brown0dca2762020-08-19 12:48:33 +0100195
Mark Browna1d71112021-09-13 13:55:04 +0100196 /* Check if the VL is supported in this process */
Mark Brown18edbb62021-12-10 18:41:00 +0000197 prctl_vl = prctl(type->prctl_set, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100198 if (prctl_vl == -1)
Mark Brown18edbb62021-12-10 18:41:00 +0000199 ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",
200 type->name, strerror(errno), errno);
Mark Brown0dca2762020-08-19 12:48:33 +0100201
Mark Browna1d71112021-09-13 13:55:04 +0100202 /* If the VL is not supported then a supported VL will be returned */
203 *supported = (prctl_vl == vl);
204
205 /* Set the VL by doing a set with no register payload */
206 memset(&sve, 0, sizeof(sve));
207 sve.size = sizeof(sve);
208 sve.vl = vl;
Mark Brown18edbb62021-12-10 18:41:00 +0000209 ret = set_sve(child, type, &sve);
Mark Browna1d71112021-09-13 13:55:04 +0100210 if (ret != 0) {
Mark Brown18edbb62021-12-10 18:41:00 +0000211 ksft_test_result_fail("Failed to set %s VL %u\n",
212 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100213 return;
Mark Brown0dca2762020-08-19 12:48:33 +0100214 }
Mark Browna1d71112021-09-13 13:55:04 +0100215
216 /*
217 * Read back the new register state and verify that we have the
218 * same VL that we got from prctl() on ourselves.
219 */
Mark Brown18edbb62021-12-10 18:41:00 +0000220 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
221 ksft_test_result_fail("Failed to read %s VL %u\n",
222 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100223 return;
224 }
225
Mark Brown18edbb62021-12-10 18:41:00 +0000226 ksft_test_result(new_sve->vl = prctl_vl, "Set %s VL %u\n",
227 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100228
229 free(new_sve);
230}
231
232static void check_u32(unsigned int vl, const char *reg,
233 uint32_t *in, uint32_t *out, int *errors)
234{
235 if (*in != *out) {
236 printf("# VL %d %s wrote %x read %x\n",
237 vl, reg, *in, *out);
238 (*errors)++;
239 }
240}
241
Mark Brown34785032021-09-13 13:55:05 +0100242/* Access the FPSIMD registers via the SVE regset */
Mark Brown18edbb62021-12-10 18:41:00 +0000243static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
Mark Brown34785032021-09-13 13:55:05 +0100244{
245 void *svebuf = NULL;
246 size_t svebufsz = 0;
247 struct user_sve_header *sve;
248 struct user_fpsimd_state *fpsimd, new_fpsimd;
249 unsigned int i, j;
250 unsigned char *p;
251
252 /* New process should start with FPSIMD registers only */
Mark Brown18edbb62021-12-10 18:41:00 +0000253 sve = get_sve(child, type, &svebuf, &svebufsz);
Mark Brown34785032021-09-13 13:55:05 +0100254 if (!sve) {
Mark Brown18edbb62021-12-10 18:41:00 +0000255 ksft_test_result_fail("get_sve(%s): %s\n",
256 type->name, strerror(errno));
Mark Brown34785032021-09-13 13:55:05 +0100257
258 return;
259 } else {
Mark Brown18edbb62021-12-10 18:41:00 +0000260 ksft_test_result_pass("get_sve(%s FPSIMD)\n", type->name);
Mark Brown34785032021-09-13 13:55:05 +0100261 }
262
263 ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
Mark Brown9ae279e2022-01-24 17:55:27 +0000264 "Got FPSIMD registers via %s\n", type->name);
Mark Brown34785032021-09-13 13:55:05 +0100265 if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
266 goto out;
267
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];
273
274 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
275 p[j] = j;
276 }
277
Mark Brown18edbb62021-12-10 18:41:00 +0000278 if (set_sve(child, type, sve)) {
279 ksft_test_result_fail("set_sve(%s FPSIMD): %s\n",
280 type->name, strerror(errno));
Mark Brown34785032021-09-13 13:55:05 +0100281
282 goto out;
283 }
284
285 /* Verify via the FPSIMD regset */
286 if (get_fpsimd(child, &new_fpsimd)) {
287 ksft_test_result_fail("get_fpsimd(): %s\n",
288 strerror(errno));
289 goto out;
290 }
291 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
Mark Brown18edbb62021-12-10 18:41:00 +0000292 ksft_test_result_pass("%s get_fpsimd() gave same state\n",
293 type->name);
Mark Brown34785032021-09-13 13:55:05 +0100294 else
Mark Brown18edbb62021-12-10 18:41:00 +0000295 ksft_test_result_fail("%s get_fpsimd() gave different state\n",
296 type->name);
Mark Brown34785032021-09-13 13:55:05 +0100297
298out:
299 free(svebuf);
300}
301
Mark Browna1d71112021-09-13 13:55:04 +0100302/* Validate attempting to set SVE data and read SVE data */
Mark Brown18edbb62021-12-10 18:41:00 +0000303static void ptrace_set_sve_get_sve_data(pid_t child,
304 const struct vec_type *type,
305 unsigned int vl)
Mark Browna1d71112021-09-13 13:55:04 +0100306{
307 void *write_buf;
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);
313 int ret, i;
314 size_t data_size;
315 int errors = 0;
316
317 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
318 write_buf = malloc(data_size);
319 if (!write_buf) {
Mark Brown18edbb62021-12-10 18:41:00 +0000320 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
321 data_size, type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100322 return;
323 }
324 write_sve = write_buf;
325
326 /* Set up some data and write it out */
327 memset(write_sve, 0, data_size);
328 write_sve->size = data_size;
329 write_sve->vl = vl;
330 write_sve->flags = SVE_PT_REGS_SVE;
331
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));
335
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));
339
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);
342
343 /* TODO: Generate a valid FFR pattern */
344
Mark Brown18edbb62021-12-10 18:41:00 +0000345 ret = set_sve(child, type, write_sve);
Mark Browna1d71112021-09-13 13:55:04 +0100346 if (ret != 0) {
Mark Brown18edbb62021-12-10 18:41:00 +0000347 ksft_test_result_fail("Failed to set %s VL %u data\n",
348 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100349 goto out;
350 }
351
352 /* Read the data back */
Mark Brown18edbb62021-12-10 18:41:00 +0000353 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
354 ksft_test_result_fail("Failed to read %s VL %u data\n",
355 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100356 goto out;
357 }
358 read_sve = read_buf;
359
360 /* We might read more data if there's extensions we don't know */
361 if (read_sve->size < write_sve->size) {
Mark Brown18edbb62021-12-10 18:41:00 +0000362 ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
363 type->name, write_sve->size,
364 read_sve->size);
Mark Browna1d71112021-09-13 13:55:04 +0100365 goto out_read;
366 }
367
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);
373 errors++;
374 }
375 }
376
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);
382 errors++;
383 }
384 }
385
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);
390
Mark Brown18edbb62021-12-10 18:41:00 +0000391 ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
392 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100393
394out_read:
395 free(read_buf);
396out:
397 free(write_buf);
398}
399
400/* Validate attempting to set SVE data and read SVE data */
Mark Brown18edbb62021-12-10 18:41:00 +0000401static void ptrace_set_sve_get_fpsimd_data(pid_t child,
402 const struct vec_type *type,
403 unsigned int vl)
Mark Browna1d71112021-09-13 13:55:04 +0100404{
405 void *write_buf;
406 struct user_sve_header *write_sve;
407 unsigned int vq = sve_vq_from_vl(vl);
408 struct user_fpsimd_state fpsimd_state;
409 int ret, i;
410 size_t data_size;
411 int errors = 0;
412
413 if (__BYTE_ORDER == __BIG_ENDIAN) {
414 ksft_test_result_skip("Big endian not supported\n");
415 return;
416 }
417
418 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
419 write_buf = malloc(data_size);
420 if (!write_buf) {
Mark Brown18edbb62021-12-10 18:41:00 +0000421 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
422 data_size, type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100423 return;
424 }
425 write_sve = write_buf;
426
427 /* Set up some data and write it out */
428 memset(write_sve, 0, data_size);
429 write_sve->size = data_size;
430 write_sve->vl = vl;
431 write_sve->flags = SVE_PT_REGS_SVE;
432
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));
436
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);
439
Mark Brown18edbb62021-12-10 18:41:00 +0000440 ret = set_sve(child, type, write_sve);
Mark Browna1d71112021-09-13 13:55:04 +0100441 if (ret != 0) {
Mark Brown18edbb62021-12-10 18:41:00 +0000442 ksft_test_result_fail("Failed to set %s VL %u data\n",
443 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100444 goto out;
445 }
446
447 /* Read the data back */
448 if (get_fpsimd(child, &fpsimd_state)) {
Mark Brown18edbb62021-12-10 18:41:00 +0000449 ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
450 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100451 goto out;
452 }
453
454 for (i = 0; i < __SVE_NUM_ZREGS; i++) {
455 __uint128_t tmp = 0;
456
457 /*
458 * Z regs are stored endianness invariant, this won't
459 * work for big endian
460 */
461 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
462 sizeof(tmp));
463
464 if (tmp != fpsimd_state.vregs[i]) {
Mark Brown18edbb62021-12-10 18:41:00 +0000465 printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
466 type->name, vl, i);
Mark Browna1d71112021-09-13 13:55:04 +0100467 errors++;
468 }
469 }
470
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);
475
Mark Brown18edbb62021-12-10 18:41:00 +0000476 ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
477 type->name, vl);
Mark Browna1d71112021-09-13 13:55:04 +0100478
479out:
480 free(write_buf);
Mark Brown0dca2762020-08-19 12:48:33 +0100481}
482
483static int do_parent(pid_t child)
484{
485 int ret = EXIT_FAILURE;
486 pid_t pid;
Mark Brown18edbb62021-12-10 18:41:00 +0000487 int status, i;
Mark Brown0dca2762020-08-19 12:48:33 +0100488 siginfo_t si;
Mark Browna1d71112021-09-13 13:55:04 +0100489 unsigned int vq, vl;
490 bool vl_supported;
Mark Brown0dca2762020-08-19 12:48:33 +0100491
492 /* Attach to the child */
493 while (1) {
494 int sig;
495
496 pid = wait(&status);
497 if (pid == -1) {
498 perror("wait");
499 goto error;
500 }
501
502 /*
503 * This should never happen but it's hard to flag in
504 * the framework.
505 */
506 if (pid != child)
507 continue;
508
509 if (WIFEXITED(status) || WIFSIGNALED(status))
510 ksft_exit_fail_msg("Child died unexpectedly\n");
511
Mark Brown0dca2762020-08-19 12:48:33 +0100512 if (!WIFSTOPPED(status))
513 goto error;
514
515 sig = WSTOPSIG(status);
516
517 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
518 if (errno == ESRCH)
519 goto disappeared;
520
521 if (errno == EINVAL) {
522 sig = 0; /* bust group-stop */
523 goto cont;
524 }
525
526 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
527 strerror(errno));
528 goto error;
529 }
530
531 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
532 si.si_pid == pid)
533 break;
534
535 cont:
536 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
537 if (errno == ESRCH)
538 goto disappeared;
539
540 ksft_test_result_fail("PTRACE_CONT: %s\n",
541 strerror(errno));
542 goto error;
543 }
544 }
545
Mark Brown18edbb62021-12-10 18:41:00 +0000546 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]);
Mark Browna1d71112021-09-13 13:55:04 +0100550 } else {
Mark Brown18edbb62021-12-10 18:41:00 +0000551 ksft_test_result_skip("%s FPSIMD get via SVE\n",
552 vec_types[i].name);
553 ksft_test_result_skip("%s FPSIMD set via SVE\n",
554 vec_types[i].name);
555 ksft_test_result_skip("%s set read via FPSIMD\n",
556 vec_types[i].name);
557 }
558
559 /* prctl() flags */
Mark Brown50806fd2022-01-24 17:55:26 +0000560 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
561 ptrace_set_get_inherit(child, &vec_types[i]);
562 } else {
563 ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
564 vec_types[i].name);
565 ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
566 vec_types[i].name);
567 }
Mark Brown18edbb62021-12-10 18:41:00 +0000568
569 /* Step through every possible VQ */
570 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
571 vl = sve_vl_from_vq(vq);
572
573 /* First, try to set this vector length */
574 if (getauxval(vec_types[i].hwcap_type) &
575 vec_types[i].hwcap) {
576 ptrace_set_get_vl(child, &vec_types[i], vl,
577 &vl_supported);
578 } else {
579 ksft_test_result_skip("%s get/set VL %d\n",
580 vec_types[i].name, vl);
581 vl_supported = false;
582 }
583
584 /* If the VL is supported validate data set/get */
585 if (vl_supported) {
586 ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
587 ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
588 } else {
589 ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
590 vec_types[i].name, vl);
591 ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
592 vec_types[i].name, vl);
593 }
Mark Browna1d71112021-09-13 13:55:04 +0100594 }
Mark Brown0dca2762020-08-19 12:48:33 +0100595 }
596
597 ret = EXIT_SUCCESS;
598
599error:
600 kill(child, SIGKILL);
601
602disappeared:
603 return ret;
604}
605
606int main(void)
607{
608 int ret = EXIT_SUCCESS;
Mark Brown0dca2762020-08-19 12:48:33 +0100609 pid_t child;
610
Mark Browna1d71112021-09-13 13:55:04 +0100611 srandom(getpid());
612
Mark Brown0dca2762020-08-19 12:48:33 +0100613 ksft_print_header();
Mark Brown78d2d812021-09-13 13:54:58 +0100614 ksft_set_plan(EXPECTED_TESTS);
Mark Brown0dca2762020-08-19 12:48:33 +0100615
616 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
617 ksft_exit_skip("SVE not available\n");
618
Mark Brown0dca2762020-08-19 12:48:33 +0100619 child = fork();
620 if (!child)
621 return do_child();
622
623 if (do_parent(child))
624 ret = EXIT_FAILURE;
625
626 ksft_print_cnts();
627
Mark Brown07e64482021-03-09 19:03:04 +0000628 return ret;
Mark Brown0dca2762020-08-19 12:48:33 +0100629}