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