Path: blob/master/tools/testing/selftests/arm64/fp/sve-ptrace.c
48893 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/* Write the FPSIMD registers via the SVE regset when SVE is not supported */397static void ptrace_sve_fpsimd_no_sve(pid_t child)398{399void *svebuf;400struct user_sve_header *sve;401struct user_fpsimd_state *fpsimd, new_fpsimd;402unsigned int i, j;403unsigned char *p;404int ret;405406svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));407if (!svebuf) {408ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");409return;410}411412/* On a system without SVE the VL should be set to 0 */413memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));414sve = svebuf;415sve->flags = SVE_PT_REGS_FPSIMD;416sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);417sve->vl = 0;418419/* Try to set a known FPSIMD state via PT_REGS_SVE */420fpsimd = (struct user_fpsimd_state *)((char *)sve +421SVE_PT_FPSIMD_OFFSET);422for (i = 0; i < 32; ++i) {423p = (unsigned char *)&fpsimd->vregs[i];424425for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)426p[j] = j;427}428429ret = set_sve(child, &vec_types[0], sve);430ksft_test_result(ret == 0, "FPSIMD write via SVE\n");431if (ret) {432ksft_test_result_skip("Verify FPSIMD write via SVE\n");433goto out;434}435436/* Verify via the FPSIMD regset */437if (get_fpsimd(child, &new_fpsimd)) {438ksft_test_result_skip("Verify FPSIMD write via SVE\n");439goto out;440}441ksft_test_result(memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0,442"Verify FPSIMD write via SVE\n");443444out:445free(svebuf);446}447448/* Validate attempting to set SVE data and read SVE data */449static void ptrace_set_sve_get_sve_data(pid_t child,450const struct vec_type *type,451unsigned int vl)452{453void *write_buf;454void *read_buf = NULL;455struct user_sve_header *write_sve;456struct user_sve_header *read_sve;457size_t read_sve_size = 0;458unsigned int vq = sve_vq_from_vl(vl);459int ret, i;460size_t data_size;461int errors = 0;462463data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);464write_buf = malloc(data_size);465if (!write_buf) {466ksft_test_result_fail("Error allocating %ld byte buffer for %s VL %u\n",467data_size, type->name, vl);468return;469}470write_sve = write_buf;471472/* Set up some data and write it out */473memset(write_sve, 0, data_size);474write_sve->size = data_size;475write_sve->vl = vl;476write_sve->flags = SVE_PT_REGS_SVE;477478for (i = 0; i < __SVE_NUM_ZREGS; i++)479fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),480SVE_PT_SVE_ZREG_SIZE(vq));481482for (i = 0; i < __SVE_NUM_PREGS; i++)483fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),484SVE_PT_SVE_PREG_SIZE(vq));485486fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);487fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);488489/* TODO: Generate a valid FFR pattern */490491ret = set_sve(child, type, write_sve);492if (ret != 0) {493ksft_test_result_fail("Failed to set %s VL %u data\n",494type->name, vl);495goto out;496}497498/* Read the data back */499if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {500ksft_test_result_fail("Failed to read %s VL %u data\n",501type->name, vl);502goto out;503}504read_sve = read_buf;505506/* We might read more data if there's extensions we don't know */507if (read_sve->size < write_sve->size) {508ksft_test_result_fail("%s wrote %d bytes, only read %d\n",509type->name, write_sve->size,510read_sve->size);511goto out_read;512}513514for (i = 0; i < __SVE_NUM_ZREGS; i++) {515if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),516read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),517SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {518printf("# Mismatch in %u Z%d\n", vl, i);519errors++;520}521}522523for (i = 0; i < __SVE_NUM_PREGS; i++) {524if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),525read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),526SVE_PT_SVE_PREG_SIZE(vq)) != 0) {527printf("# Mismatch in %u P%d\n", vl, i);528errors++;529}530}531532check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),533read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);534check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),535read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);536537ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",538type->name, vl);539540out_read:541free(read_buf);542out:543free(write_buf);544}545546/* Validate attempting to set SVE data and read it via the FPSIMD regset */547static void ptrace_set_sve_get_fpsimd_data(pid_t child,548const struct vec_type *type,549unsigned int vl)550{551void *write_buf;552struct user_sve_header *write_sve;553unsigned int vq = sve_vq_from_vl(vl);554struct user_fpsimd_state fpsimd_state;555int ret, i;556size_t data_size;557int errors = 0;558559if (__BYTE_ORDER == __BIG_ENDIAN) {560ksft_test_result_skip("Big endian not supported\n");561return;562}563564data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);565write_buf = malloc(data_size);566if (!write_buf) {567ksft_test_result_fail("Error allocating %ld byte buffer for %s VL %u\n",568data_size, type->name, vl);569return;570}571write_sve = write_buf;572573/* Set up some data and write it out */574memset(write_sve, 0, data_size);575write_sve->size = data_size;576write_sve->vl = vl;577write_sve->flags = SVE_PT_REGS_SVE;578579for (i = 0; i < __SVE_NUM_ZREGS; i++)580fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),581SVE_PT_SVE_ZREG_SIZE(vq));582583fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);584fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);585586ret = set_sve(child, type, write_sve);587if (ret != 0) {588ksft_test_result_fail("Failed to set %s VL %u data\n",589type->name, vl);590goto out;591}592593/* Read the data back */594if (get_fpsimd(child, &fpsimd_state)) {595ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",596type->name, vl);597goto out;598}599600for (i = 0; i < __SVE_NUM_ZREGS; i++) {601__uint128_t tmp = 0;602603/*604* Z regs are stored endianness invariant, this won't605* work for big endian606*/607memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),608sizeof(tmp));609610if (tmp != fpsimd_state.vregs[i]) {611printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",612type->name, vl, i);613errors++;614}615}616617check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),618&fpsimd_state.fpsr, &errors);619check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),620&fpsimd_state.fpcr, &errors);621622ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",623type->name, vl);624625out:626free(write_buf);627}628629/* Validate attempting to set FPSIMD data and read it via the SVE regset */630static void ptrace_set_fpsimd_get_sve_data(pid_t child,631const struct vec_type *type,632unsigned int vl)633{634void *read_buf = NULL;635unsigned char *p;636struct user_sve_header *read_sve;637unsigned int vq = sve_vq_from_vl(vl);638struct user_fpsimd_state write_fpsimd;639int ret, i, j;640size_t read_sve_size = 0;641size_t expected_size;642int errors = 0;643644if (__BYTE_ORDER == __BIG_ENDIAN) {645ksft_test_result_skip("Big endian not supported\n");646return;647}648649for (i = 0; i < 32; ++i) {650p = (unsigned char *)&write_fpsimd.vregs[i];651652for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)653p[j] = j;654}655656ret = set_fpsimd(child, &write_fpsimd);657if (ret != 0) {658ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",659ret);660return;661}662663if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {664ksft_test_result_fail("Failed to read %s VL %u data\n",665type->name, vl);666return;667}668read_sve = read_buf;669670if (read_sve->vl != vl) {671ksft_test_result_fail("Child VL != expected VL: %u != %u\n",672read_sve->vl, vl);673goto out;674}675676/* The kernel may return either SVE or FPSIMD format */677switch (read_sve->flags & SVE_PT_REGS_MASK) {678case SVE_PT_REGS_FPSIMD:679expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);680if (read_sve_size < expected_size) {681ksft_test_result_fail("Read %ld bytes, expected %ld\n",682read_sve_size, expected_size);683goto out;684}685686ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,687sizeof(write_fpsimd));688if (ret != 0) {689ksft_print_msg("Read FPSIMD data mismatch\n");690errors++;691}692break;693694case SVE_PT_REGS_SVE:695expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);696if (read_sve_size < expected_size) {697ksft_test_result_fail("Read %ld bytes, expected %ld\n",698read_sve_size, expected_size);699goto out;700}701702for (i = 0; i < __SVE_NUM_ZREGS; i++) {703__uint128_t tmp = 0;704705/*706* Z regs are stored endianness invariant, this won't707* work for big endian708*/709memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),710sizeof(tmp));711712if (tmp != write_fpsimd.vregs[i]) {713ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",714type->name, vl, i, i);715errors++;716}717}718719check_u32(vl, "FPSR", &write_fpsimd.fpsr,720read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);721check_u32(vl, "FPCR", &write_fpsimd.fpcr,722read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);723break;724default:725ksft_print_msg("Unexpected regs type %d\n",726read_sve->flags & SVE_PT_REGS_MASK);727errors++;728break;729}730731ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",732type->name, vl);733734out:735free(read_buf);736}737738static int do_parent(pid_t child)739{740int ret = EXIT_FAILURE;741pid_t pid;742int status, i;743siginfo_t si;744unsigned int vq, vl;745bool vl_supported;746747ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);748749/* Attach to the child */750while (1) {751int sig;752753pid = wait(&status);754if (pid == -1) {755perror("wait");756goto error;757}758759/*760* This should never happen but it's hard to flag in761* the framework.762*/763if (pid != child)764continue;765766if (WIFEXITED(status) || WIFSIGNALED(status))767ksft_exit_fail_msg("Child died unexpectedly\n");768769if (!WIFSTOPPED(status))770goto error;771772sig = WSTOPSIG(status);773774if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {775if (errno == ESRCH)776goto disappeared;777778if (errno == EINVAL) {779sig = 0; /* bust group-stop */780goto cont;781}782783ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",784strerror(errno));785goto error;786}787788if (sig == SIGSTOP && si.si_code == SI_TKILL &&789si.si_pid == pid)790break;791792cont:793if (ptrace(PTRACE_CONT, pid, NULL, sig)) {794if (errno == ESRCH)795goto disappeared;796797ksft_test_result_fail("PTRACE_CONT: %s\n",798strerror(errno));799goto error;800}801}802803for (i = 0; i < ARRAY_SIZE(vec_types); i++) {804/*805* If the vector type isn't supported reads and writes806* should fail.807*/808if (!(getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap)) {809read_fails(child, &vec_types[i]);810write_fails(child, &vec_types[i]);811} else {812ksft_test_result_skip("%s unsupported read fails\n",813vec_types[i].name);814ksft_test_result_skip("%s unsupported write fails\n",815vec_types[i].name);816}817818/* FPSIMD via SVE regset */819if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {820ptrace_sve_fpsimd(child, &vec_types[i]);821} else {822ksft_test_result_skip("%s FPSIMD set via SVE\n",823vec_types[i].name);824ksft_test_result_skip("%s FPSIMD read\n",825vec_types[i].name);826}827828/* prctl() flags */829if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {830ptrace_set_get_inherit(child, &vec_types[i]);831} else {832ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",833vec_types[i].name);834ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",835vec_types[i].name);836}837838/* Setting out of bounds VLs should fail */839if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {840ptrace_set_vl_ranges(child, &vec_types[i]);841} else {842ksft_test_result_skip("%s Set invalid VL 0\n",843vec_types[i].name);844ksft_test_result_skip("%s Set invalid VL %d\n",845vec_types[i].name,846SVE_VL_MAX + SVE_VQ_BYTES);847}848849/* Step through every possible VQ */850for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {851vl = sve_vl_from_vq(vq);852853/* First, try to set this vector length */854if (getauxval(vec_types[i].hwcap_type) &855vec_types[i].hwcap) {856ptrace_set_get_vl(child, &vec_types[i], vl,857&vl_supported);858} else {859ksft_test_result_skip("%s get/set VL %d\n",860vec_types[i].name, vl);861vl_supported = false;862}863864/* If the VL is supported validate data set/get */865if (vl_supported) {866ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);867ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);868ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);869} else {870ksft_test_result_skip("%s set SVE get SVE for VL %d\n",871vec_types[i].name, vl);872ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",873vec_types[i].name, vl);874ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",875vec_types[i].name, vl);876}877}878}879880/* We support SVE writes of FPSMID format on SME only systems */881if (!(getauxval(AT_HWCAP) & HWCAP_SVE) &&882(getauxval(AT_HWCAP2) & HWCAP2_SME)) {883ptrace_sve_fpsimd_no_sve(child);884} else {885ksft_test_result_skip("FPSIMD write via SVE\n");886ksft_test_result_skip("Verify FPSIMD write via SVE\n");887}888889ret = EXIT_SUCCESS;890891error:892kill(child, SIGKILL);893894disappeared:895return ret;896}897898int main(void)899{900int ret = EXIT_SUCCESS;901pid_t child;902903srandom(getpid());904905ksft_print_header();906ksft_set_plan(EXPECTED_TESTS);907908child = fork();909if (!child)910return do_child();911912if (do_parent(child))913ret = EXIT_FAILURE;914915ksft_print_cnts();916917return ret;918}919920921