brintos

brintos / linux-shallow public Read only

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