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