Path: blob/master/tools/testing/selftests/arm64/fp/sve-ptrace.c
29270 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2015-2021 ARM Limited.3* Original author: Dave Martin <[email protected]>4*/5#include <errno.h>6#include <stdbool.h>7#include <stddef.h>8#include <stdio.h>9#include <stdlib.h>10#include <string.h>11#include <unistd.h>12#include <sys/auxv.h>13#include <sys/prctl.h>14#include <sys/ptrace.h>15#include <sys/types.h>16#include <sys/uio.h>17#include <sys/wait.h>18#include <asm/sigcontext.h>19#include <asm/ptrace.h>2021#include "../../kselftest.h"2223/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */24#ifndef NT_ARM_SVE25#define NT_ARM_SVE 0x40526#endif2728#ifndef NT_ARM_SSVE29#define NT_ARM_SSVE 0x40b30#endif3132/*33* The architecture defines the maximum VQ as 16 but for extensibility34* the kernel specifies the SVE_VQ_MAX as 512 resulting in us running35* a *lot* more tests than are useful if we use it. Until the36* architecture is extended let's limit our coverage to what is37* currently allowed, plus one extra to ensure we cover constraining38* the VL as expected.39*/40#define TEST_VQ_MAX 174142struct vec_type {43const char *name;44unsigned long hwcap_type;45unsigned long hwcap;46int regset;47int prctl_set;48};4950static const struct vec_type vec_types[] = {51{52.name = "SVE",53.hwcap_type = AT_HWCAP,54.hwcap = HWCAP_SVE,55.regset = NT_ARM_SVE,56.prctl_set = PR_SVE_SET_VL,57},58{59.name = "Streaming SVE",60.hwcap_type = AT_HWCAP2,61.hwcap = HWCAP2_SME,62.regset = NT_ARM_SSVE,63.prctl_set = PR_SME_SET_VL,64},65};6667#define VL_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 4)68#define FLAG_TESTS 469#define FPSIMD_TESTS 27071#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))7273static void fill_buf(char *buf, size_t size)74{75int i;7677for (i = 0; i < size; i++)78buf[i] = random();79}8081static int do_child(void)82{83if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))84ksft_exit_fail_msg("ptrace(PTRACE_TRACEME) failed: %s (%d)\n",85strerror(errno), errno);8687if (raise(SIGSTOP))88ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",89strerror(errno), errno);9091return EXIT_SUCCESS;92}9394static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)95{96struct iovec iov;97int ret;9899iov.iov_base = fpsimd;100iov.iov_len = sizeof(*fpsimd);101ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);102if (ret == -1)103ksft_perror("ptrace(PTRACE_GETREGSET)");104return ret;105}106107static int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)108{109struct iovec iov;110int ret;111112iov.iov_base = fpsimd;113iov.iov_len = sizeof(*fpsimd);114ret = ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);115if (ret == -1)116ksft_perror("ptrace(PTRACE_SETREGSET)");117return ret;118}119120static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,121void **buf, size_t *size)122{123struct user_sve_header *sve;124void *p;125size_t sz = sizeof(*sve);126struct iovec iov;127int ret;128129while (1) {130if (*size < sz) {131p = realloc(*buf, sz);132if (!p) {133errno = ENOMEM;134goto error;135}136137*buf = p;138*size = sz;139}140141iov.iov_base = *buf;142iov.iov_len = sz;143ret = ptrace(PTRACE_GETREGSET, pid, type->regset, &iov);144if (ret) {145ksft_perror("ptrace(PTRACE_GETREGSET)");146goto error;147}148149sve = *buf;150if (sve->size <= sz)151break;152153sz = sve->size;154}155156return sve;157158error:159return NULL;160}161162static int set_sve(pid_t pid, const struct vec_type *type,163const struct user_sve_header *sve)164{165struct iovec iov;166int ret;167168iov.iov_base = (void *)sve;169iov.iov_len = sve->size;170ret = ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);171if (ret == -1)172ksft_perror("ptrace(PTRACE_SETREGSET)");173return ret;174}175176/* A read operation fails */177static void read_fails(pid_t child, const struct vec_type *type)178{179struct user_sve_header *new_sve = NULL;180size_t new_sve_size = 0;181void *ret;182183ret = get_sve(child, type, (void **)&new_sve, &new_sve_size);184185ksft_test_result(ret == NULL, "%s unsupported read fails\n",186type->name);187188free(new_sve);189}190191/* A write operation fails */192static void write_fails(pid_t child, const struct vec_type *type)193{194struct user_sve_header sve;195int ret;196197/* Just the header, no data */198memset(&sve, 0, sizeof(sve));199sve.size = sizeof(sve);200sve.flags = SVE_PT_REGS_SVE;201sve.vl = SVE_VL_MIN;202ret = set_sve(child, type, &sve);203204ksft_test_result(ret != 0, "%s unsupported write fails\n",205type->name);206}207208/* Validate setting and getting the inherit flag */209static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)210{211struct user_sve_header sve;212struct user_sve_header *new_sve = NULL;213size_t new_sve_size = 0;214int ret;215216/* First set the flag */217memset(&sve, 0, sizeof(sve));218sve.size = sizeof(sve);219sve.vl = sve_vl_from_vq(SVE_VQ_MIN);220sve.flags = SVE_PT_VL_INHERIT | SVE_PT_REGS_SVE;221ret = set_sve(child, type, &sve);222if (ret != 0) {223ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",224type->name);225return;226}227228/*229* Read back the new register state and verify that we have230* set the flags we expected.231*/232if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {233ksft_test_result_fail("Failed to read %s SVE flags\n",234type->name);235return;236}237238ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,239"%s SVE_PT_VL_INHERIT set\n", type->name);240241/* Now clear */242sve.flags &= ~SVE_PT_VL_INHERIT;243ret = set_sve(child, type, &sve);244if (ret != 0) {245ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",246type->name);247return;248}249250if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {251ksft_test_result_fail("Failed to read %s SVE flags\n",252type->name);253return;254}255256ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),257"%s SVE_PT_VL_INHERIT cleared\n", type->name);258259free(new_sve);260}261262/* Validate attempting to set the specfied VL via ptrace */263static void ptrace_set_get_vl(pid_t child, const struct vec_type *type,264unsigned int vl, bool *supported)265{266struct user_sve_header sve;267struct user_sve_header *new_sve = NULL;268size_t new_sve_size = 0;269int ret, prctl_vl;270271*supported = false;272273/* Check if the VL is supported in this process */274prctl_vl = prctl(type->prctl_set, vl);275if (prctl_vl == -1)276ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",277type->name, strerror(errno), errno);278279/* If the VL is not supported then a supported VL will be returned */280*supported = (prctl_vl == vl);281282/* Set the VL by doing a set with no register payload */283memset(&sve, 0, sizeof(sve));284sve.size = sizeof(sve);285sve.flags = SVE_PT_REGS_SVE;286sve.vl = vl;287ret = set_sve(child, type, &sve);288if (ret != 0) {289ksft_test_result_fail("Failed to set %s VL %u\n",290type->name, vl);291return;292}293294/*295* Read back the new register state and verify that we have the296* same VL that we got from prctl() on ourselves.297*/298if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {299ksft_test_result_fail("Failed to read %s VL %u\n",300type->name, vl);301return;302}303304ksft_test_result(new_sve->vl == prctl_vl, "Set %s VL %u\n",305type->name, vl);306307free(new_sve);308}309310static void check_u32(unsigned int vl, const char *reg,311uint32_t *in, uint32_t *out, int *errors)312{313if (*in != *out) {314printf("# VL %d %s wrote %x read %x\n",315vl, reg, *in, *out);316(*errors)++;317}318}319320/* Set out of range VLs */321static void ptrace_set_vl_ranges(pid_t child, const struct vec_type *type)322{323struct user_sve_header sve;324int ret;325326memset(&sve, 0, sizeof(sve));327sve.flags = SVE_PT_REGS_SVE;328sve.size = sizeof(sve);329330ret = set_sve(child, type, &sve);331ksft_test_result(ret != 0, "%s Set invalid VL 0\n", type->name);332333sve.vl = SVE_VL_MAX + SVE_VQ_BYTES;334ret = set_sve(child, type, &sve);335ksft_test_result(ret != 0, "%s Set invalid VL %d\n", type->name,336SVE_VL_MAX + SVE_VQ_BYTES);337}338339/* Access the FPSIMD registers via the SVE regset */340static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)341{342void *svebuf;343struct user_sve_header *sve;344struct user_fpsimd_state *fpsimd, new_fpsimd;345unsigned int i, j;346unsigned char *p;347int ret;348349svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));350if (!svebuf) {351ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");352return;353}354355memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));356sve = svebuf;357sve->flags = SVE_PT_REGS_FPSIMD;358sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);359sve->vl = 16; /* We don't care what the VL is */360361/* Try to set a known FPSIMD state via PT_REGS_SVE */362fpsimd = (struct user_fpsimd_state *)((char *)sve +363SVE_PT_FPSIMD_OFFSET);364for (i = 0; i < 32; ++i) {365p = (unsigned char *)&fpsimd->vregs[i];366367for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)368p[j] = j;369}370371/* This should only succeed for SVE */372ret = set_sve(child, type, sve);373ksft_test_result((type->regset == NT_ARM_SVE) == (ret == 0),374"%s FPSIMD set via SVE: %d\n",375type->name, ret);376if (ret)377goto out;378379/* Verify via the FPSIMD regset */380if (get_fpsimd(child, &new_fpsimd)) {381ksft_test_result_fail("get_fpsimd(): %s\n",382strerror(errno));383goto out;384}385if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)386ksft_test_result_pass("%s get_fpsimd() gave same state\n",387type->name);388else389ksft_test_result_fail("%s get_fpsimd() gave different state\n",390type->name);391392out:393free(svebuf);394}395396/* Validate attempting to set SVE data and read SVE data */397static void ptrace_set_sve_get_sve_data(pid_t child,398const struct vec_type *type,399unsigned int vl)400{401void *write_buf;402void *read_buf = NULL;403struct user_sve_header *write_sve;404struct user_sve_header *read_sve;405size_t read_sve_size = 0;406unsigned int vq = sve_vq_from_vl(vl);407int ret, i;408size_t data_size;409int errors = 0;410411data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);412write_buf = malloc(data_size);413if (!write_buf) {414ksft_test_result_fail("Error allocating %ld byte buffer for %s VL %u\n",415data_size, type->name, vl);416return;417}418write_sve = write_buf;419420/* Set up some data and write it out */421memset(write_sve, 0, data_size);422write_sve->size = data_size;423write_sve->vl = vl;424write_sve->flags = SVE_PT_REGS_SVE;425426for (i = 0; i < __SVE_NUM_ZREGS; i++)427fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),428SVE_PT_SVE_ZREG_SIZE(vq));429430for (i = 0; i < __SVE_NUM_PREGS; i++)431fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),432SVE_PT_SVE_PREG_SIZE(vq));433434fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);435fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);436437/* TODO: Generate a valid FFR pattern */438439ret = set_sve(child, type, write_sve);440if (ret != 0) {441ksft_test_result_fail("Failed to set %s VL %u data\n",442type->name, vl);443goto out;444}445446/* Read the data back */447if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {448ksft_test_result_fail("Failed to read %s VL %u data\n",449type->name, vl);450goto out;451}452read_sve = read_buf;453454/* We might read more data if there's extensions we don't know */455if (read_sve->size < write_sve->size) {456ksft_test_result_fail("%s wrote %d bytes, only read %d\n",457type->name, write_sve->size,458read_sve->size);459goto out_read;460}461462for (i = 0; i < __SVE_NUM_ZREGS; i++) {463if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),464read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),465SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {466printf("# Mismatch in %u Z%d\n", vl, i);467errors++;468}469}470471for (i = 0; i < __SVE_NUM_PREGS; i++) {472if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),473read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),474SVE_PT_SVE_PREG_SIZE(vq)) != 0) {475printf("# Mismatch in %u P%d\n", vl, i);476errors++;477}478}479480check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),481read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);482check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),483read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);484485ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",486type->name, vl);487488out_read:489free(read_buf);490out:491free(write_buf);492}493494/* Validate attempting to set SVE data and read it via the FPSIMD regset */495static void ptrace_set_sve_get_fpsimd_data(pid_t child,496const struct vec_type *type,497unsigned int vl)498{499void *write_buf;500struct user_sve_header *write_sve;501unsigned int vq = sve_vq_from_vl(vl);502struct user_fpsimd_state fpsimd_state;503int ret, i;504size_t data_size;505int errors = 0;506507if (__BYTE_ORDER == __BIG_ENDIAN) {508ksft_test_result_skip("Big endian not supported\n");509return;510}511512data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);513write_buf = malloc(data_size);514if (!write_buf) {515ksft_test_result_fail("Error allocating %ld byte buffer for %s VL %u\n",516data_size, type->name, vl);517return;518}519write_sve = write_buf;520521/* Set up some data and write it out */522memset(write_sve, 0, data_size);523write_sve->size = data_size;524write_sve->vl = vl;525write_sve->flags = SVE_PT_REGS_SVE;526527for (i = 0; i < __SVE_NUM_ZREGS; i++)528fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),529SVE_PT_SVE_ZREG_SIZE(vq));530531fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);532fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);533534ret = set_sve(child, type, write_sve);535if (ret != 0) {536ksft_test_result_fail("Failed to set %s VL %u data\n",537type->name, vl);538goto out;539}540541/* Read the data back */542if (get_fpsimd(child, &fpsimd_state)) {543ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",544type->name, vl);545goto out;546}547548for (i = 0; i < __SVE_NUM_ZREGS; i++) {549__uint128_t tmp = 0;550551/*552* Z regs are stored endianness invariant, this won't553* work for big endian554*/555memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),556sizeof(tmp));557558if (tmp != fpsimd_state.vregs[i]) {559printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",560type->name, vl, i);561errors++;562}563}564565check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),566&fpsimd_state.fpsr, &errors);567check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),568&fpsimd_state.fpcr, &errors);569570ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",571type->name, vl);572573out:574free(write_buf);575}576577/* Validate attempting to set FPSIMD data and read it via the SVE regset */578static void ptrace_set_fpsimd_get_sve_data(pid_t child,579const struct vec_type *type,580unsigned int vl)581{582void *read_buf = NULL;583unsigned char *p;584struct user_sve_header *read_sve;585unsigned int vq = sve_vq_from_vl(vl);586struct user_fpsimd_state write_fpsimd;587int ret, i, j;588size_t read_sve_size = 0;589size_t expected_size;590int errors = 0;591592if (__BYTE_ORDER == __BIG_ENDIAN) {593ksft_test_result_skip("Big endian not supported\n");594return;595}596597for (i = 0; i < 32; ++i) {598p = (unsigned char *)&write_fpsimd.vregs[i];599600for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)601p[j] = j;602}603604ret = set_fpsimd(child, &write_fpsimd);605if (ret != 0) {606ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",607ret);608return;609}610611if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {612ksft_test_result_fail("Failed to read %s VL %u data\n",613type->name, vl);614return;615}616read_sve = read_buf;617618if (read_sve->vl != vl) {619ksft_test_result_fail("Child VL != expected VL: %u != %u\n",620read_sve->vl, vl);621goto out;622}623624/* The kernel may return either SVE or FPSIMD format */625switch (read_sve->flags & SVE_PT_REGS_MASK) {626case SVE_PT_REGS_FPSIMD:627expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);628if (read_sve_size < expected_size) {629ksft_test_result_fail("Read %ld bytes, expected %ld\n",630read_sve_size, expected_size);631goto out;632}633634ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,635sizeof(write_fpsimd));636if (ret != 0) {637ksft_print_msg("Read FPSIMD data mismatch\n");638errors++;639}640break;641642case SVE_PT_REGS_SVE:643expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);644if (read_sve_size < expected_size) {645ksft_test_result_fail("Read %ld bytes, expected %ld\n",646read_sve_size, expected_size);647goto out;648}649650for (i = 0; i < __SVE_NUM_ZREGS; i++) {651__uint128_t tmp = 0;652653/*654* Z regs are stored endianness invariant, this won't655* work for big endian656*/657memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),658sizeof(tmp));659660if (tmp != write_fpsimd.vregs[i]) {661ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",662type->name, vl, i, i);663errors++;664}665}666667check_u32(vl, "FPSR", &write_fpsimd.fpsr,668read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);669check_u32(vl, "FPCR", &write_fpsimd.fpcr,670read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);671break;672default:673ksft_print_msg("Unexpected regs type %d\n",674read_sve->flags & SVE_PT_REGS_MASK);675errors++;676break;677}678679ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",680type->name, vl);681682out:683free(read_buf);684}685686static int do_parent(pid_t child)687{688int ret = EXIT_FAILURE;689pid_t pid;690int status, i;691siginfo_t si;692unsigned int vq, vl;693bool vl_supported;694695ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);696697/* Attach to the child */698while (1) {699int sig;700701pid = wait(&status);702if (pid == -1) {703perror("wait");704goto error;705}706707/*708* This should never happen but it's hard to flag in709* the framework.710*/711if (pid != child)712continue;713714if (WIFEXITED(status) || WIFSIGNALED(status))715ksft_exit_fail_msg("Child died unexpectedly\n");716717if (!WIFSTOPPED(status))718goto error;719720sig = WSTOPSIG(status);721722if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {723if (errno == ESRCH)724goto disappeared;725726if (errno == EINVAL) {727sig = 0; /* bust group-stop */728goto cont;729}730731ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",732strerror(errno));733goto error;734}735736if (sig == SIGSTOP && si.si_code == SI_TKILL &&737si.si_pid == pid)738break;739740cont:741if (ptrace(PTRACE_CONT, pid, NULL, sig)) {742if (errno == ESRCH)743goto disappeared;744745ksft_test_result_fail("PTRACE_CONT: %s\n",746strerror(errno));747goto error;748}749}750751for (i = 0; i < ARRAY_SIZE(vec_types); i++) {752/*753* If the vector type isn't supported reads and writes754* should fail.755*/756if (!(getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap)) {757read_fails(child, &vec_types[i]);758write_fails(child, &vec_types[i]);759} else {760ksft_test_result_skip("%s unsupported read fails\n",761vec_types[i].name);762ksft_test_result_skip("%s unsupported write fails\n",763vec_types[i].name);764}765766/* FPSIMD via SVE regset */767if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {768ptrace_sve_fpsimd(child, &vec_types[i]);769} else {770ksft_test_result_skip("%s FPSIMD set via SVE\n",771vec_types[i].name);772ksft_test_result_skip("%s FPSIMD read\n",773vec_types[i].name);774}775776/* prctl() flags */777if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {778ptrace_set_get_inherit(child, &vec_types[i]);779} else {780ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",781vec_types[i].name);782ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",783vec_types[i].name);784}785786/* Setting out of bounds VLs should fail */787if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {788ptrace_set_vl_ranges(child, &vec_types[i]);789} else {790ksft_test_result_skip("%s Set invalid VL 0\n",791vec_types[i].name);792ksft_test_result_skip("%s Set invalid VL %d\n",793vec_types[i].name,794SVE_VL_MAX + SVE_VQ_BYTES);795}796797/* Step through every possible VQ */798for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {799vl = sve_vl_from_vq(vq);800801/* First, try to set this vector length */802if (getauxval(vec_types[i].hwcap_type) &803vec_types[i].hwcap) {804ptrace_set_get_vl(child, &vec_types[i], vl,805&vl_supported);806} else {807ksft_test_result_skip("%s get/set VL %d\n",808vec_types[i].name, vl);809vl_supported = false;810}811812/* If the VL is supported validate data set/get */813if (vl_supported) {814ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);815ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);816ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);817} else {818ksft_test_result_skip("%s set SVE get SVE for VL %d\n",819vec_types[i].name, vl);820ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",821vec_types[i].name, vl);822ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",823vec_types[i].name, vl);824}825}826}827828ret = EXIT_SUCCESS;829830error:831kill(child, SIGKILL);832833disappeared:834return ret;835}836837int main(void)838{839int ret = EXIT_SUCCESS;840pid_t child;841842srandom(getpid());843844ksft_print_header();845ksft_set_plan(EXPECTED_TESTS);846847child = fork();848if (!child)849return do_child();850851if (do_parent(child))852ret = EXIT_FAILURE;853854ksft_print_cnts();855856return ret;857}858859860