162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015-2021 ARM Limited.
462306a36Sopenharmony_ci * Original author: Dave Martin <Dave.Martin@arm.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <errno.h>
762306a36Sopenharmony_ci#include <stdbool.h>
862306a36Sopenharmony_ci#include <stddef.h>
962306a36Sopenharmony_ci#include <stdio.h>
1062306a36Sopenharmony_ci#include <stdlib.h>
1162306a36Sopenharmony_ci#include <string.h>
1262306a36Sopenharmony_ci#include <unistd.h>
1362306a36Sopenharmony_ci#include <sys/auxv.h>
1462306a36Sopenharmony_ci#include <sys/prctl.h>
1562306a36Sopenharmony_ci#include <sys/ptrace.h>
1662306a36Sopenharmony_ci#include <sys/types.h>
1762306a36Sopenharmony_ci#include <sys/uio.h>
1862306a36Sopenharmony_ci#include <sys/wait.h>
1962306a36Sopenharmony_ci#include <asm/sigcontext.h>
2062306a36Sopenharmony_ci#include <asm/ptrace.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "../../kselftest.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
2562306a36Sopenharmony_ci#ifndef NT_ARM_SVE
2662306a36Sopenharmony_ci#define NT_ARM_SVE 0x405
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#ifndef NT_ARM_SSVE
3062306a36Sopenharmony_ci#define NT_ARM_SSVE 0x40b
3162306a36Sopenharmony_ci#endif
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * The architecture defines the maximum VQ as 16 but for extensibility
3562306a36Sopenharmony_ci * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
3662306a36Sopenharmony_ci * a *lot* more tests than are useful if we use it.  Until the
3762306a36Sopenharmony_ci * architecture is extended let's limit our coverage to what is
3862306a36Sopenharmony_ci * currently allowed, plus one extra to ensure we cover constraining
3962306a36Sopenharmony_ci * the VL as expected.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci#define TEST_VQ_MAX 17
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct vec_type {
4462306a36Sopenharmony_ci	const char *name;
4562306a36Sopenharmony_ci	unsigned long hwcap_type;
4662306a36Sopenharmony_ci	unsigned long hwcap;
4762306a36Sopenharmony_ci	int regset;
4862306a36Sopenharmony_ci	int prctl_set;
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const struct vec_type vec_types[] = {
5262306a36Sopenharmony_ci	{
5362306a36Sopenharmony_ci		.name = "SVE",
5462306a36Sopenharmony_ci		.hwcap_type = AT_HWCAP,
5562306a36Sopenharmony_ci		.hwcap = HWCAP_SVE,
5662306a36Sopenharmony_ci		.regset = NT_ARM_SVE,
5762306a36Sopenharmony_ci		.prctl_set = PR_SVE_SET_VL,
5862306a36Sopenharmony_ci	},
5962306a36Sopenharmony_ci	{
6062306a36Sopenharmony_ci		.name = "Streaming SVE",
6162306a36Sopenharmony_ci		.hwcap_type = AT_HWCAP2,
6262306a36Sopenharmony_ci		.hwcap = HWCAP2_SME,
6362306a36Sopenharmony_ci		.regset = NT_ARM_SSVE,
6462306a36Sopenharmony_ci		.prctl_set = PR_SME_SET_VL,
6562306a36Sopenharmony_ci	},
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define VL_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
6962306a36Sopenharmony_ci#define FLAG_TESTS 2
7062306a36Sopenharmony_ci#define FPSIMD_TESTS 2
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void fill_buf(char *buf, size_t size)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	int i;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	for (i = 0; i < size; i++)
7962306a36Sopenharmony_ci		buf[i] = random();
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int do_child(void)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
8562306a36Sopenharmony_ci		ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (raise(SIGSTOP))
8862306a36Sopenharmony_ci		ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return EXIT_SUCCESS;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct iovec iov;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	iov.iov_base = fpsimd;
9862306a36Sopenharmony_ci	iov.iov_len = sizeof(*fpsimd);
9962306a36Sopenharmony_ci	return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct iovec iov;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	iov.iov_base = fpsimd;
10762306a36Sopenharmony_ci	iov.iov_len = sizeof(*fpsimd);
10862306a36Sopenharmony_ci	return ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
11262306a36Sopenharmony_ci				       void **buf, size_t *size)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct user_sve_header *sve;
11562306a36Sopenharmony_ci	void *p;
11662306a36Sopenharmony_ci	size_t sz = sizeof *sve;
11762306a36Sopenharmony_ci	struct iovec iov;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	while (1) {
12062306a36Sopenharmony_ci		if (*size < sz) {
12162306a36Sopenharmony_ci			p = realloc(*buf, sz);
12262306a36Sopenharmony_ci			if (!p) {
12362306a36Sopenharmony_ci				errno = ENOMEM;
12462306a36Sopenharmony_ci				goto error;
12562306a36Sopenharmony_ci			}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci			*buf = p;
12862306a36Sopenharmony_ci			*size = sz;
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		iov.iov_base = *buf;
13262306a36Sopenharmony_ci		iov.iov_len = sz;
13362306a36Sopenharmony_ci		if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov))
13462306a36Sopenharmony_ci			goto error;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		sve = *buf;
13762306a36Sopenharmony_ci		if (sve->size <= sz)
13862306a36Sopenharmony_ci			break;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		sz = sve->size;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return sve;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cierror:
14662306a36Sopenharmony_ci	return NULL;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int set_sve(pid_t pid, const struct vec_type *type,
15062306a36Sopenharmony_ci		   const struct user_sve_header *sve)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct iovec iov;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	iov.iov_base = (void *)sve;
15562306a36Sopenharmony_ci	iov.iov_len = sve->size;
15662306a36Sopenharmony_ci	return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/* Validate setting and getting the inherit flag */
16062306a36Sopenharmony_cistatic void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct user_sve_header sve;
16362306a36Sopenharmony_ci	struct user_sve_header *new_sve = NULL;
16462306a36Sopenharmony_ci	size_t new_sve_size = 0;
16562306a36Sopenharmony_ci	int ret;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* First set the flag */
16862306a36Sopenharmony_ci	memset(&sve, 0, sizeof(sve));
16962306a36Sopenharmony_ci	sve.size = sizeof(sve);
17062306a36Sopenharmony_ci	sve.vl = sve_vl_from_vq(SVE_VQ_MIN);
17162306a36Sopenharmony_ci	sve.flags = SVE_PT_VL_INHERIT;
17262306a36Sopenharmony_ci	ret = set_sve(child, type, &sve);
17362306a36Sopenharmony_ci	if (ret != 0) {
17462306a36Sopenharmony_ci		ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",
17562306a36Sopenharmony_ci				      type->name);
17662306a36Sopenharmony_ci		return;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/*
18062306a36Sopenharmony_ci	 * Read back the new register state and verify that we have
18162306a36Sopenharmony_ci	 * set the flags we expected.
18262306a36Sopenharmony_ci	 */
18362306a36Sopenharmony_ci	if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
18462306a36Sopenharmony_ci		ksft_test_result_fail("Failed to read %s SVE flags\n",
18562306a36Sopenharmony_ci				      type->name);
18662306a36Sopenharmony_ci		return;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
19062306a36Sopenharmony_ci			 "%s SVE_PT_VL_INHERIT set\n", type->name);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Now clear */
19362306a36Sopenharmony_ci	sve.flags &= ~SVE_PT_VL_INHERIT;
19462306a36Sopenharmony_ci	ret = set_sve(child, type, &sve);
19562306a36Sopenharmony_ci	if (ret != 0) {
19662306a36Sopenharmony_ci		ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",
19762306a36Sopenharmony_ci				      type->name);
19862306a36Sopenharmony_ci		return;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
20262306a36Sopenharmony_ci		ksft_test_result_fail("Failed to read %s SVE flags\n",
20362306a36Sopenharmony_ci				      type->name);
20462306a36Sopenharmony_ci		return;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
20862306a36Sopenharmony_ci			 "%s SVE_PT_VL_INHERIT cleared\n", type->name);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	free(new_sve);
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/* Validate attempting to set the specfied VL via ptrace */
21462306a36Sopenharmony_cistatic void ptrace_set_get_vl(pid_t child, const struct vec_type *type,
21562306a36Sopenharmony_ci			      unsigned int vl, bool *supported)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct user_sve_header sve;
21862306a36Sopenharmony_ci	struct user_sve_header *new_sve = NULL;
21962306a36Sopenharmony_ci	size_t new_sve_size = 0;
22062306a36Sopenharmony_ci	int ret, prctl_vl;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	*supported = false;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Check if the VL is supported in this process */
22562306a36Sopenharmony_ci	prctl_vl = prctl(type->prctl_set, vl);
22662306a36Sopenharmony_ci	if (prctl_vl == -1)
22762306a36Sopenharmony_ci		ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",
22862306a36Sopenharmony_ci				   type->name, strerror(errno), errno);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* If the VL is not supported then a supported VL will be returned */
23162306a36Sopenharmony_ci	*supported = (prctl_vl == vl);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Set the VL by doing a set with no register payload */
23462306a36Sopenharmony_ci	memset(&sve, 0, sizeof(sve));
23562306a36Sopenharmony_ci	sve.size = sizeof(sve);
23662306a36Sopenharmony_ci	sve.vl = vl;
23762306a36Sopenharmony_ci	ret = set_sve(child, type, &sve);
23862306a36Sopenharmony_ci	if (ret != 0) {
23962306a36Sopenharmony_ci		ksft_test_result_fail("Failed to set %s VL %u\n",
24062306a36Sopenharmony_ci				      type->name, vl);
24162306a36Sopenharmony_ci		return;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * Read back the new register state and verify that we have the
24662306a36Sopenharmony_ci	 * same VL that we got from prctl() on ourselves.
24762306a36Sopenharmony_ci	 */
24862306a36Sopenharmony_ci	if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
24962306a36Sopenharmony_ci		ksft_test_result_fail("Failed to read %s VL %u\n",
25062306a36Sopenharmony_ci				      type->name, vl);
25162306a36Sopenharmony_ci		return;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	ksft_test_result(new_sve->vl = prctl_vl, "Set %s VL %u\n",
25562306a36Sopenharmony_ci			 type->name, vl);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	free(new_sve);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic void check_u32(unsigned int vl, const char *reg,
26162306a36Sopenharmony_ci		      uint32_t *in, uint32_t *out, int *errors)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	if (*in != *out) {
26462306a36Sopenharmony_ci		printf("# VL %d %s wrote %x read %x\n",
26562306a36Sopenharmony_ci		       vl, reg, *in, *out);
26662306a36Sopenharmony_ci		(*errors)++;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/* Access the FPSIMD registers via the SVE regset */
27162306a36Sopenharmony_cistatic void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	void *svebuf;
27462306a36Sopenharmony_ci	struct user_sve_header *sve;
27562306a36Sopenharmony_ci	struct user_fpsimd_state *fpsimd, new_fpsimd;
27662306a36Sopenharmony_ci	unsigned int i, j;
27762306a36Sopenharmony_ci	unsigned char *p;
27862306a36Sopenharmony_ci	int ret;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
28162306a36Sopenharmony_ci	if (!svebuf) {
28262306a36Sopenharmony_ci		ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");
28362306a36Sopenharmony_ci		return;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
28762306a36Sopenharmony_ci	sve = svebuf;
28862306a36Sopenharmony_ci	sve->flags = SVE_PT_REGS_FPSIMD;
28962306a36Sopenharmony_ci	sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);
29062306a36Sopenharmony_ci	sve->vl = 16;  /* We don't care what the VL is */
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/* Try to set a known FPSIMD state via PT_REGS_SVE */
29362306a36Sopenharmony_ci	fpsimd = (struct user_fpsimd_state *)((char *)sve +
29462306a36Sopenharmony_ci					      SVE_PT_FPSIMD_OFFSET);
29562306a36Sopenharmony_ci	for (i = 0; i < 32; ++i) {
29662306a36Sopenharmony_ci		p = (unsigned char *)&fpsimd->vregs[i];
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
29962306a36Sopenharmony_ci			p[j] = j;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	ret = set_sve(child, type, sve);
30362306a36Sopenharmony_ci	ksft_test_result(ret == 0, "%s FPSIMD set via SVE: %d\n",
30462306a36Sopenharmony_ci			 type->name, ret);
30562306a36Sopenharmony_ci	if (ret)
30662306a36Sopenharmony_ci		goto out;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Verify via the FPSIMD regset */
30962306a36Sopenharmony_ci	if (get_fpsimd(child, &new_fpsimd)) {
31062306a36Sopenharmony_ci		ksft_test_result_fail("get_fpsimd(): %s\n",
31162306a36Sopenharmony_ci				      strerror(errno));
31262306a36Sopenharmony_ci		goto out;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
31562306a36Sopenharmony_ci		ksft_test_result_pass("%s get_fpsimd() gave same state\n",
31662306a36Sopenharmony_ci				      type->name);
31762306a36Sopenharmony_ci	else
31862306a36Sopenharmony_ci		ksft_test_result_fail("%s get_fpsimd() gave different state\n",
31962306a36Sopenharmony_ci				      type->name);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciout:
32262306a36Sopenharmony_ci	free(svebuf);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/* Validate attempting to set SVE data and read SVE data */
32662306a36Sopenharmony_cistatic void ptrace_set_sve_get_sve_data(pid_t child,
32762306a36Sopenharmony_ci					const struct vec_type *type,
32862306a36Sopenharmony_ci					unsigned int vl)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	void *write_buf;
33162306a36Sopenharmony_ci	void *read_buf = NULL;
33262306a36Sopenharmony_ci	struct user_sve_header *write_sve;
33362306a36Sopenharmony_ci	struct user_sve_header *read_sve;
33462306a36Sopenharmony_ci	size_t read_sve_size = 0;
33562306a36Sopenharmony_ci	unsigned int vq = sve_vq_from_vl(vl);
33662306a36Sopenharmony_ci	int ret, i;
33762306a36Sopenharmony_ci	size_t data_size;
33862306a36Sopenharmony_ci	int errors = 0;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
34162306a36Sopenharmony_ci	write_buf = malloc(data_size);
34262306a36Sopenharmony_ci	if (!write_buf) {
34362306a36Sopenharmony_ci		ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
34462306a36Sopenharmony_ci				      data_size, type->name, vl);
34562306a36Sopenharmony_ci		return;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci	write_sve = write_buf;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Set up some data and write it out */
35062306a36Sopenharmony_ci	memset(write_sve, 0, data_size);
35162306a36Sopenharmony_ci	write_sve->size = data_size;
35262306a36Sopenharmony_ci	write_sve->vl = vl;
35362306a36Sopenharmony_ci	write_sve->flags = SVE_PT_REGS_SVE;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	for (i = 0; i < __SVE_NUM_ZREGS; i++)
35662306a36Sopenharmony_ci		fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
35762306a36Sopenharmony_ci			 SVE_PT_SVE_ZREG_SIZE(vq));
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	for (i = 0; i < __SVE_NUM_PREGS; i++)
36062306a36Sopenharmony_ci		fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
36162306a36Sopenharmony_ci			 SVE_PT_SVE_PREG_SIZE(vq));
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
36462306a36Sopenharmony_ci	fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* TODO: Generate a valid FFR pattern */
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	ret = set_sve(child, type, write_sve);
36962306a36Sopenharmony_ci	if (ret != 0) {
37062306a36Sopenharmony_ci		ksft_test_result_fail("Failed to set %s VL %u data\n",
37162306a36Sopenharmony_ci				      type->name, vl);
37262306a36Sopenharmony_ci		goto out;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* Read the data back */
37662306a36Sopenharmony_ci	if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
37762306a36Sopenharmony_ci		ksft_test_result_fail("Failed to read %s VL %u data\n",
37862306a36Sopenharmony_ci				      type->name, vl);
37962306a36Sopenharmony_ci		goto out;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci	read_sve = read_buf;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/* We might read more data if there's extensions we don't know */
38462306a36Sopenharmony_ci	if (read_sve->size < write_sve->size) {
38562306a36Sopenharmony_ci		ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
38662306a36Sopenharmony_ci				      type->name, write_sve->size,
38762306a36Sopenharmony_ci				      read_sve->size);
38862306a36Sopenharmony_ci		goto out_read;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	for (i = 0; i < __SVE_NUM_ZREGS; i++) {
39262306a36Sopenharmony_ci		if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
39362306a36Sopenharmony_ci			   read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
39462306a36Sopenharmony_ci			   SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
39562306a36Sopenharmony_ci			printf("# Mismatch in %u Z%d\n", vl, i);
39662306a36Sopenharmony_ci			errors++;
39762306a36Sopenharmony_ci		}
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	for (i = 0; i < __SVE_NUM_PREGS; i++) {
40162306a36Sopenharmony_ci		if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
40262306a36Sopenharmony_ci			   read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
40362306a36Sopenharmony_ci			   SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
40462306a36Sopenharmony_ci			printf("# Mismatch in %u P%d\n", vl, i);
40562306a36Sopenharmony_ci			errors++;
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
41062306a36Sopenharmony_ci		  read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
41162306a36Sopenharmony_ci	check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
41262306a36Sopenharmony_ci		  read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
41562306a36Sopenharmony_ci			 type->name, vl);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciout_read:
41862306a36Sopenharmony_ci	free(read_buf);
41962306a36Sopenharmony_ciout:
42062306a36Sopenharmony_ci	free(write_buf);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/* Validate attempting to set SVE data and read it via the FPSIMD regset */
42462306a36Sopenharmony_cistatic void ptrace_set_sve_get_fpsimd_data(pid_t child,
42562306a36Sopenharmony_ci					   const struct vec_type *type,
42662306a36Sopenharmony_ci					   unsigned int vl)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	void *write_buf;
42962306a36Sopenharmony_ci	struct user_sve_header *write_sve;
43062306a36Sopenharmony_ci	unsigned int vq = sve_vq_from_vl(vl);
43162306a36Sopenharmony_ci	struct user_fpsimd_state fpsimd_state;
43262306a36Sopenharmony_ci	int ret, i;
43362306a36Sopenharmony_ci	size_t data_size;
43462306a36Sopenharmony_ci	int errors = 0;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (__BYTE_ORDER == __BIG_ENDIAN) {
43762306a36Sopenharmony_ci		ksft_test_result_skip("Big endian not supported\n");
43862306a36Sopenharmony_ci		return;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
44262306a36Sopenharmony_ci	write_buf = malloc(data_size);
44362306a36Sopenharmony_ci	if (!write_buf) {
44462306a36Sopenharmony_ci		ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
44562306a36Sopenharmony_ci				      data_size, type->name, vl);
44662306a36Sopenharmony_ci		return;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci	write_sve = write_buf;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* Set up some data and write it out */
45162306a36Sopenharmony_ci	memset(write_sve, 0, data_size);
45262306a36Sopenharmony_ci	write_sve->size = data_size;
45362306a36Sopenharmony_ci	write_sve->vl = vl;
45462306a36Sopenharmony_ci	write_sve->flags = SVE_PT_REGS_SVE;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	for (i = 0; i < __SVE_NUM_ZREGS; i++)
45762306a36Sopenharmony_ci		fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
45862306a36Sopenharmony_ci			 SVE_PT_SVE_ZREG_SIZE(vq));
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
46162306a36Sopenharmony_ci	fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	ret = set_sve(child, type, write_sve);
46462306a36Sopenharmony_ci	if (ret != 0) {
46562306a36Sopenharmony_ci		ksft_test_result_fail("Failed to set %s VL %u data\n",
46662306a36Sopenharmony_ci				      type->name, vl);
46762306a36Sopenharmony_ci		goto out;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* Read the data back */
47162306a36Sopenharmony_ci	if (get_fpsimd(child, &fpsimd_state)) {
47262306a36Sopenharmony_ci		ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
47362306a36Sopenharmony_ci				      type->name, vl);
47462306a36Sopenharmony_ci		goto out;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	for (i = 0; i < __SVE_NUM_ZREGS; i++) {
47862306a36Sopenharmony_ci		__uint128_t tmp = 0;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		/*
48162306a36Sopenharmony_ci		 * Z regs are stored endianness invariant, this won't
48262306a36Sopenharmony_ci		 * work for big endian
48362306a36Sopenharmony_ci		 */
48462306a36Sopenharmony_ci		memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
48562306a36Sopenharmony_ci		       sizeof(tmp));
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		if (tmp != fpsimd_state.vregs[i]) {
48862306a36Sopenharmony_ci			printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
48962306a36Sopenharmony_ci			       type->name, vl, i);
49062306a36Sopenharmony_ci			errors++;
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
49562306a36Sopenharmony_ci		  &fpsimd_state.fpsr, &errors);
49662306a36Sopenharmony_ci	check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
49762306a36Sopenharmony_ci		  &fpsimd_state.fpcr, &errors);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
50062306a36Sopenharmony_ci			 type->name, vl);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciout:
50362306a36Sopenharmony_ci	free(write_buf);
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/* Validate attempting to set FPSIMD data and read it via the SVE regset */
50762306a36Sopenharmony_cistatic void ptrace_set_fpsimd_get_sve_data(pid_t child,
50862306a36Sopenharmony_ci					   const struct vec_type *type,
50962306a36Sopenharmony_ci					   unsigned int vl)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	void *read_buf = NULL;
51262306a36Sopenharmony_ci	unsigned char *p;
51362306a36Sopenharmony_ci	struct user_sve_header *read_sve;
51462306a36Sopenharmony_ci	unsigned int vq = sve_vq_from_vl(vl);
51562306a36Sopenharmony_ci	struct user_fpsimd_state write_fpsimd;
51662306a36Sopenharmony_ci	int ret, i, j;
51762306a36Sopenharmony_ci	size_t read_sve_size = 0;
51862306a36Sopenharmony_ci	size_t expected_size;
51962306a36Sopenharmony_ci	int errors = 0;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (__BYTE_ORDER == __BIG_ENDIAN) {
52262306a36Sopenharmony_ci		ksft_test_result_skip("Big endian not supported\n");
52362306a36Sopenharmony_ci		return;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	for (i = 0; i < 32; ++i) {
52762306a36Sopenharmony_ci		p = (unsigned char *)&write_fpsimd.vregs[i];
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)
53062306a36Sopenharmony_ci			p[j] = j;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	ret = set_fpsimd(child, &write_fpsimd);
53462306a36Sopenharmony_ci	if (ret != 0) {
53562306a36Sopenharmony_ci		ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",
53662306a36Sopenharmony_ci				      ret);
53762306a36Sopenharmony_ci		return;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
54162306a36Sopenharmony_ci		ksft_test_result_fail("Failed to read %s VL %u data\n",
54262306a36Sopenharmony_ci				      type->name, vl);
54362306a36Sopenharmony_ci		return;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci	read_sve = read_buf;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (read_sve->vl != vl) {
54862306a36Sopenharmony_ci		ksft_test_result_fail("Child VL != expected VL %d\n",
54962306a36Sopenharmony_ci				      read_sve->vl, vl);
55062306a36Sopenharmony_ci		goto out;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* The kernel may return either SVE or FPSIMD format */
55462306a36Sopenharmony_ci	switch (read_sve->flags & SVE_PT_REGS_MASK) {
55562306a36Sopenharmony_ci	case SVE_PT_REGS_FPSIMD:
55662306a36Sopenharmony_ci		expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);
55762306a36Sopenharmony_ci		if (read_sve_size < expected_size) {
55862306a36Sopenharmony_ci			ksft_test_result_fail("Read %d bytes, expected %d\n",
55962306a36Sopenharmony_ci					      read_sve_size, expected_size);
56062306a36Sopenharmony_ci			goto out;
56162306a36Sopenharmony_ci		}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,
56462306a36Sopenharmony_ci			     sizeof(write_fpsimd));
56562306a36Sopenharmony_ci		if (ret != 0) {
56662306a36Sopenharmony_ci			ksft_print_msg("Read FPSIMD data mismatch\n");
56762306a36Sopenharmony_ci			errors++;
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci		break;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	case SVE_PT_REGS_SVE:
57262306a36Sopenharmony_ci		expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
57362306a36Sopenharmony_ci		if (read_sve_size < expected_size) {
57462306a36Sopenharmony_ci			ksft_test_result_fail("Read %d bytes, expected %d\n",
57562306a36Sopenharmony_ci					      read_sve_size, expected_size);
57662306a36Sopenharmony_ci			goto out;
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		for (i = 0; i < __SVE_NUM_ZREGS; i++) {
58062306a36Sopenharmony_ci			__uint128_t tmp = 0;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci			/*
58362306a36Sopenharmony_ci			 * Z regs are stored endianness invariant, this won't
58462306a36Sopenharmony_ci			 * work for big endian
58562306a36Sopenharmony_ci			 */
58662306a36Sopenharmony_ci			memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
58762306a36Sopenharmony_ci			       sizeof(tmp));
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci			if (tmp != write_fpsimd.vregs[i]) {
59062306a36Sopenharmony_ci				ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",
59162306a36Sopenharmony_ci					       type->name, vl, i, i);
59262306a36Sopenharmony_ci				errors++;
59362306a36Sopenharmony_ci			}
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		check_u32(vl, "FPSR", &write_fpsimd.fpsr,
59762306a36Sopenharmony_ci			  read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
59862306a36Sopenharmony_ci		check_u32(vl, "FPCR", &write_fpsimd.fpcr,
59962306a36Sopenharmony_ci			  read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
60062306a36Sopenharmony_ci		break;
60162306a36Sopenharmony_ci	default:
60262306a36Sopenharmony_ci		ksft_print_msg("Unexpected regs type %d\n",
60362306a36Sopenharmony_ci			       read_sve->flags & SVE_PT_REGS_MASK);
60462306a36Sopenharmony_ci		errors++;
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",
60962306a36Sopenharmony_ci			 type->name, vl);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ciout:
61262306a36Sopenharmony_ci	free(read_buf);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic int do_parent(pid_t child)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	int ret = EXIT_FAILURE;
61862306a36Sopenharmony_ci	pid_t pid;
61962306a36Sopenharmony_ci	int status, i;
62062306a36Sopenharmony_ci	siginfo_t si;
62162306a36Sopenharmony_ci	unsigned int vq, vl;
62262306a36Sopenharmony_ci	bool vl_supported;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* Attach to the child */
62762306a36Sopenharmony_ci	while (1) {
62862306a36Sopenharmony_ci		int sig;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		pid = wait(&status);
63162306a36Sopenharmony_ci		if (pid == -1) {
63262306a36Sopenharmony_ci			perror("wait");
63362306a36Sopenharmony_ci			goto error;
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		/*
63762306a36Sopenharmony_ci		 * This should never happen but it's hard to flag in
63862306a36Sopenharmony_ci		 * the framework.
63962306a36Sopenharmony_ci		 */
64062306a36Sopenharmony_ci		if (pid != child)
64162306a36Sopenharmony_ci			continue;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		if (WIFEXITED(status) || WIFSIGNALED(status))
64462306a36Sopenharmony_ci			ksft_exit_fail_msg("Child died unexpectedly\n");
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		if (!WIFSTOPPED(status))
64762306a36Sopenharmony_ci			goto error;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		sig = WSTOPSIG(status);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
65262306a36Sopenharmony_ci			if (errno == ESRCH)
65362306a36Sopenharmony_ci				goto disappeared;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci			if (errno == EINVAL) {
65662306a36Sopenharmony_ci				sig = 0; /* bust group-stop */
65762306a36Sopenharmony_ci				goto cont;
65862306a36Sopenharmony_ci			}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci			ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
66162306a36Sopenharmony_ci					      strerror(errno));
66262306a36Sopenharmony_ci			goto error;
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		if (sig == SIGSTOP && si.si_code == SI_TKILL &&
66662306a36Sopenharmony_ci		    si.si_pid == pid)
66762306a36Sopenharmony_ci			break;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	cont:
67062306a36Sopenharmony_ci		if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
67162306a36Sopenharmony_ci			if (errno == ESRCH)
67262306a36Sopenharmony_ci				goto disappeared;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci			ksft_test_result_fail("PTRACE_CONT: %s\n",
67562306a36Sopenharmony_ci					      strerror(errno));
67662306a36Sopenharmony_ci			goto error;
67762306a36Sopenharmony_ci		}
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
68162306a36Sopenharmony_ci		/* FPSIMD via SVE regset */
68262306a36Sopenharmony_ci		if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
68362306a36Sopenharmony_ci			ptrace_sve_fpsimd(child, &vec_types[i]);
68462306a36Sopenharmony_ci		} else {
68562306a36Sopenharmony_ci			ksft_test_result_skip("%s FPSIMD set via SVE\n",
68662306a36Sopenharmony_ci					      vec_types[i].name);
68762306a36Sopenharmony_ci			ksft_test_result_skip("%s FPSIMD read\n",
68862306a36Sopenharmony_ci					      vec_types[i].name);
68962306a36Sopenharmony_ci		}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		/* prctl() flags */
69262306a36Sopenharmony_ci		if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
69362306a36Sopenharmony_ci			ptrace_set_get_inherit(child, &vec_types[i]);
69462306a36Sopenharmony_ci		} else {
69562306a36Sopenharmony_ci			ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
69662306a36Sopenharmony_ci					      vec_types[i].name);
69762306a36Sopenharmony_ci			ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
69862306a36Sopenharmony_ci					      vec_types[i].name);
69962306a36Sopenharmony_ci		}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		/* Step through every possible VQ */
70262306a36Sopenharmony_ci		for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
70362306a36Sopenharmony_ci			vl = sve_vl_from_vq(vq);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci			/* First, try to set this vector length */
70662306a36Sopenharmony_ci			if (getauxval(vec_types[i].hwcap_type) &
70762306a36Sopenharmony_ci			    vec_types[i].hwcap) {
70862306a36Sopenharmony_ci				ptrace_set_get_vl(child, &vec_types[i], vl,
70962306a36Sopenharmony_ci						  &vl_supported);
71062306a36Sopenharmony_ci			} else {
71162306a36Sopenharmony_ci				ksft_test_result_skip("%s get/set VL %d\n",
71262306a36Sopenharmony_ci						      vec_types[i].name, vl);
71362306a36Sopenharmony_ci				vl_supported = false;
71462306a36Sopenharmony_ci			}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci			/* If the VL is supported validate data set/get */
71762306a36Sopenharmony_ci			if (vl_supported) {
71862306a36Sopenharmony_ci				ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
71962306a36Sopenharmony_ci				ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
72062306a36Sopenharmony_ci				ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);
72162306a36Sopenharmony_ci			} else {
72262306a36Sopenharmony_ci				ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
72362306a36Sopenharmony_ci						      vec_types[i].name, vl);
72462306a36Sopenharmony_ci				ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
72562306a36Sopenharmony_ci						      vec_types[i].name, vl);
72662306a36Sopenharmony_ci				ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",
72762306a36Sopenharmony_ci						      vec_types[i].name, vl);
72862306a36Sopenharmony_ci			}
72962306a36Sopenharmony_ci		}
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	ret = EXIT_SUCCESS;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cierror:
73562306a36Sopenharmony_ci	kill(child, SIGKILL);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cidisappeared:
73862306a36Sopenharmony_ci	return ret;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ciint main(void)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	int ret = EXIT_SUCCESS;
74462306a36Sopenharmony_ci	pid_t child;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	srandom(getpid());
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	ksft_print_header();
74962306a36Sopenharmony_ci	ksft_set_plan(EXPECTED_TESTS);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
75262306a36Sopenharmony_ci		ksft_exit_skip("SVE not available\n");
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	child = fork();
75562306a36Sopenharmony_ci	if (!child)
75662306a36Sopenharmony_ci		return do_child();
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (do_parent(child))
75962306a36Sopenharmony_ci		ret = EXIT_FAILURE;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	ksft_print_cnts();
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	return ret;
76462306a36Sopenharmony_ci}
765