cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sve-ptrace.c (18356B)


      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
     33struct vec_type {
     34	const char *name;
     35	unsigned long hwcap_type;
     36	unsigned long hwcap;
     37	int regset;
     38	int prctl_set;
     39};
     40
     41static 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
     64static 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
     72static 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
     83static 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
     92static 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
    101static 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
    135error:
    136	return NULL;
    137}
    138
    139static 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 */
    150static 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 */
    204static 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
    250static 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 */
    261static 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
    311out:
    312	free(svebuf);
    313}
    314
    315/* Validate attempting to set SVE data and read SVE data */
    316static 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
    407out_read:
    408	free(read_buf);
    409out:
    410	free(write_buf);
    411}
    412
    413/* Validate attempting to set SVE data and read it via the FPSIMD regset */
    414static 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
    492out:
    493	free(write_buf);
    494}
    495
    496/* Validate attempting to set FPSIMD data and read it via the SVE regset */
    497static 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
    601out:
    602	free(read_buf);
    603}
    604
    605static 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
    724error:
    725	kill(child, SIGKILL);
    726
    727disappeared:
    728	return ret;
    729}
    730
    731int 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}