Path: blob/master/tools/testing/selftests/arm64/fp/fp-ptrace.c
26295 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2023 ARM Limited.3* Original author: Mark Brown <[email protected]>4*/56#define _GNU_SOURCE78#include <errno.h>9#include <stdbool.h>10#include <stddef.h>11#include <stdio.h>12#include <stdlib.h>13#include <string.h>14#include <unistd.h>1516#include <sys/auxv.h>17#include <sys/prctl.h>18#include <sys/ptrace.h>19#include <sys/types.h>20#include <sys/uio.h>21#include <sys/wait.h>2223#include <linux/kernel.h>2425#include <asm/sigcontext.h>26#include <asm/sve_context.h>27#include <asm/ptrace.h>2829#include "../../kselftest.h"3031#include "fp-ptrace.h"3233#include <linux/bits.h>3435#define FPMR_LSCALE2_MASK GENMASK(37, 32)36#define FPMR_NSCALE_MASK GENMASK(31, 24)37#define FPMR_LSCALE_MASK GENMASK(22, 16)38#define FPMR_OSC_MASK GENMASK(15, 15)39#define FPMR_OSM_MASK GENMASK(14, 14)4041/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */42#ifndef NT_ARM_SVE43#define NT_ARM_SVE 0x40544#endif4546#ifndef NT_ARM_SSVE47#define NT_ARM_SSVE 0x40b48#endif4950#ifndef NT_ARM_ZA51#define NT_ARM_ZA 0x40c52#endif5354#ifndef NT_ARM_ZT55#define NT_ARM_ZT 0x40d56#endif5758#ifndef NT_ARM_FPMR59#define NT_ARM_FPMR 0x40e60#endif6162#define ARCH_VQ_MAX 2566364/* VL 128..2048 in powers of 2 */65#define MAX_NUM_VLS 56667/*68* FPMR bits we can set without doing feature checks to see if values69* are valid.70*/71#define FPMR_SAFE_BITS (FPMR_LSCALE2_MASK | FPMR_NSCALE_MASK | \72FPMR_LSCALE_MASK | FPMR_OSC_MASK | FPMR_OSM_MASK)7374#define NUM_FPR 3275__uint128_t v_in[NUM_FPR];76__uint128_t v_expected[NUM_FPR];77__uint128_t v_out[NUM_FPR];7879char z_in[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];80char z_expected[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];81char z_out[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];8283char p_in[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];84char p_expected[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];85char p_out[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];8687char ffr_in[__SVE_PREG_SIZE(ARCH_VQ_MAX)];88char ffr_expected[__SVE_PREG_SIZE(ARCH_VQ_MAX)];89char ffr_out[__SVE_PREG_SIZE(ARCH_VQ_MAX)];9091char za_in[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];92char za_expected[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];93char za_out[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];9495char zt_in[ZT_SIG_REG_BYTES];96char zt_expected[ZT_SIG_REG_BYTES];97char zt_out[ZT_SIG_REG_BYTES];9899uint64_t fpmr_in, fpmr_expected, fpmr_out;100101uint64_t sve_vl_out;102uint64_t sme_vl_out;103uint64_t svcr_in, svcr_expected, svcr_out;104105void load_and_save(int flags);106107static bool got_alarm;108109static void handle_alarm(int sig, siginfo_t *info, void *context)110{111got_alarm = true;112}113114#ifdef CONFIG_CPU_BIG_ENDIAN115static __uint128_t arm64_cpu_to_le128(__uint128_t x)116{117u64 a = swab64(x);118u64 b = swab64(x >> 64);119120return ((__uint128_t)a << 64) | b;121}122#else123static __uint128_t arm64_cpu_to_le128(__uint128_t x)124{125return x;126}127#endif128129#define arm64_le128_to_cpu(x) arm64_cpu_to_le128(x)130131static bool sve_supported(void)132{133return getauxval(AT_HWCAP) & HWCAP_SVE;134}135136static bool sme_supported(void)137{138return getauxval(AT_HWCAP2) & HWCAP2_SME;139}140141static bool sme2_supported(void)142{143return getauxval(AT_HWCAP2) & HWCAP2_SME2;144}145146static bool fa64_supported(void)147{148return getauxval(AT_HWCAP2) & HWCAP2_SME_FA64;149}150151static bool fpmr_supported(void)152{153return getauxval(AT_HWCAP2) & HWCAP2_FPMR;154}155156static bool compare_buffer(const char *name, void *out,157void *expected, size_t size)158{159void *tmp;160161if (memcmp(out, expected, size) == 0)162return true;163164ksft_print_msg("Mismatch in %s\n", name);165166/* Did we just get zeros back? */167tmp = malloc(size);168if (!tmp) {169ksft_print_msg("OOM allocating %lu bytes for %s\n",170size, name);171ksft_exit_fail();172}173memset(tmp, 0, size);174175if (memcmp(out, tmp, size) == 0)176ksft_print_msg("%s is zero\n", name);177178free(tmp);179180return false;181}182183struct test_config {184int sve_vl_in;185int sve_vl_expected;186int sme_vl_in;187int sme_vl_expected;188int svcr_in;189int svcr_expected;190};191192struct test_definition {193const char *name;194bool sve_vl_change;195bool (*supported)(struct test_config *config);196void (*set_expected_values)(struct test_config *config);197void (*modify_values)(pid_t child, struct test_config *test_config);198};199200static int vl_in(struct test_config *config)201{202int vl;203204if (config->svcr_in & SVCR_SM)205vl = config->sme_vl_in;206else207vl = config->sve_vl_in;208209return vl;210}211212static int vl_expected(struct test_config *config)213{214int vl;215216if (config->svcr_expected & SVCR_SM)217vl = config->sme_vl_expected;218else219vl = config->sve_vl_expected;220221return vl;222}223224static void run_child(struct test_config *config)225{226int ret, flags;227228/* Let the parent attach to us */229ret = ptrace(PTRACE_TRACEME, 0, 0, 0);230if (ret < 0)231ksft_exit_fail_msg("PTRACE_TRACEME failed: %s (%d)\n",232strerror(errno), errno);233234/* VL setup */235if (sve_supported()) {236ret = prctl(PR_SVE_SET_VL, config->sve_vl_in);237if (ret != config->sve_vl_in) {238ksft_print_msg("Failed to set SVE VL %d: %d\n",239config->sve_vl_in, ret);240}241}242243if (sme_supported()) {244ret = prctl(PR_SME_SET_VL, config->sme_vl_in);245if (ret != config->sme_vl_in) {246ksft_print_msg("Failed to set SME VL %d: %d\n",247config->sme_vl_in, ret);248}249}250251/* Load values and wait for the parent */252flags = 0;253if (sve_supported())254flags |= HAVE_SVE;255if (sme_supported())256flags |= HAVE_SME;257if (sme2_supported())258flags |= HAVE_SME2;259if (fa64_supported())260flags |= HAVE_FA64;261if (fpmr_supported())262flags |= HAVE_FPMR;263264load_and_save(flags);265266exit(0);267}268269static void read_one_child_regs(pid_t child, char *name,270struct iovec *iov_parent,271struct iovec *iov_child)272{273int len = iov_parent->iov_len;274int ret;275276ret = process_vm_readv(child, iov_parent, 1, iov_child, 1, 0);277if (ret == -1)278ksft_print_msg("%s read failed: %s (%d)\n",279name, strerror(errno), errno);280else if (ret != len)281ksft_print_msg("Short read of %s: %d\n", name, ret);282}283284static void read_child_regs(pid_t child)285{286struct iovec iov_parent, iov_child;287288/*289* Since the child fork()ed from us the buffer addresses are290* the same in parent and child.291*/292iov_parent.iov_base = &v_out;293iov_parent.iov_len = sizeof(v_out);294iov_child.iov_base = &v_out;295iov_child.iov_len = sizeof(v_out);296read_one_child_regs(child, "FPSIMD", &iov_parent, &iov_child);297298if (sve_supported() || sme_supported()) {299iov_parent.iov_base = &sve_vl_out;300iov_parent.iov_len = sizeof(sve_vl_out);301iov_child.iov_base = &sve_vl_out;302iov_child.iov_len = sizeof(sve_vl_out);303read_one_child_regs(child, "SVE VL", &iov_parent, &iov_child);304305iov_parent.iov_base = &z_out;306iov_parent.iov_len = sizeof(z_out);307iov_child.iov_base = &z_out;308iov_child.iov_len = sizeof(z_out);309read_one_child_regs(child, "Z", &iov_parent, &iov_child);310311iov_parent.iov_base = &p_out;312iov_parent.iov_len = sizeof(p_out);313iov_child.iov_base = &p_out;314iov_child.iov_len = sizeof(p_out);315read_one_child_regs(child, "P", &iov_parent, &iov_child);316317iov_parent.iov_base = &ffr_out;318iov_parent.iov_len = sizeof(ffr_out);319iov_child.iov_base = &ffr_out;320iov_child.iov_len = sizeof(ffr_out);321read_one_child_regs(child, "FFR", &iov_parent, &iov_child);322}323324if (sme_supported()) {325iov_parent.iov_base = &sme_vl_out;326iov_parent.iov_len = sizeof(sme_vl_out);327iov_child.iov_base = &sme_vl_out;328iov_child.iov_len = sizeof(sme_vl_out);329read_one_child_regs(child, "SME VL", &iov_parent, &iov_child);330331iov_parent.iov_base = &svcr_out;332iov_parent.iov_len = sizeof(svcr_out);333iov_child.iov_base = &svcr_out;334iov_child.iov_len = sizeof(svcr_out);335read_one_child_regs(child, "SVCR", &iov_parent, &iov_child);336337iov_parent.iov_base = &za_out;338iov_parent.iov_len = sizeof(za_out);339iov_child.iov_base = &za_out;340iov_child.iov_len = sizeof(za_out);341read_one_child_regs(child, "ZA", &iov_parent, &iov_child);342}343344if (sme2_supported()) {345iov_parent.iov_base = &zt_out;346iov_parent.iov_len = sizeof(zt_out);347iov_child.iov_base = &zt_out;348iov_child.iov_len = sizeof(zt_out);349read_one_child_regs(child, "ZT", &iov_parent, &iov_child);350}351352if (fpmr_supported()) {353iov_parent.iov_base = &fpmr_out;354iov_parent.iov_len = sizeof(fpmr_out);355iov_child.iov_base = &fpmr_out;356iov_child.iov_len = sizeof(fpmr_out);357read_one_child_regs(child, "FPMR", &iov_parent, &iov_child);358}359}360361static bool continue_breakpoint(pid_t child,362enum __ptrace_request restart_type)363{364struct user_pt_regs pt_regs;365struct iovec iov;366int ret;367368/* Get PC */369iov.iov_base = &pt_regs;370iov.iov_len = sizeof(pt_regs);371ret = ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &iov);372if (ret < 0) {373ksft_print_msg("Failed to get PC: %s (%d)\n",374strerror(errno), errno);375return false;376}377378/* Skip over the BRK */379pt_regs.pc += 4;380ret = ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, &iov);381if (ret < 0) {382ksft_print_msg("Failed to skip BRK: %s (%d)\n",383strerror(errno), errno);384return false;385}386387/* Restart */388ret = ptrace(restart_type, child, 0, 0);389if (ret < 0) {390ksft_print_msg("Failed to restart child: %s (%d)\n",391strerror(errno), errno);392return false;393}394395return true;396}397398static bool check_ptrace_values_sve(pid_t child, struct test_config *config)399{400struct user_sve_header *sve;401struct user_fpsimd_state *fpsimd;402struct iovec iov;403int ret, vq;404bool pass = true;405406if (!sve_supported())407return true;408409vq = __sve_vq_from_vl(config->sve_vl_in);410411iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);412iov.iov_base = malloc(iov.iov_len);413if (!iov.iov_base) {414ksft_print_msg("OOM allocating %lu byte SVE buffer\n",415iov.iov_len);416return false;417}418419ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_SVE, &iov);420if (ret != 0) {421ksft_print_msg("Failed to read initial SVE: %s (%d)\n",422strerror(errno), errno);423pass = false;424goto out;425}426427sve = iov.iov_base;428429if (sve->vl != config->sve_vl_in) {430ksft_print_msg("Mismatch in initial SVE VL: %d != %d\n",431sve->vl, config->sve_vl_in);432pass = false;433}434435/* If we are in streaming mode we should just read FPSIMD */436if ((config->svcr_in & SVCR_SM) && (sve->flags & SVE_PT_REGS_SVE)) {437ksft_print_msg("NT_ARM_SVE reports SVE with PSTATE.SM\n");438pass = false;439}440441if (svcr_in & SVCR_SM) {442if (sve->size != sizeof(sve)) {443ksft_print_msg("NT_ARM_SVE reports data with PSTATE.SM\n");444pass = false;445}446} else {447if (sve->size != SVE_PT_SIZE(vq, sve->flags)) {448ksft_print_msg("Mismatch in SVE header size: %d != %lu\n",449sve->size, SVE_PT_SIZE(vq, sve->flags));450pass = false;451}452}453454/* The registers might be in completely different formats! */455if (sve->flags & SVE_PT_REGS_SVE) {456if (!compare_buffer("initial SVE Z",457iov.iov_base + SVE_PT_SVE_ZREG_OFFSET(vq, 0),458z_in, SVE_PT_SVE_ZREGS_SIZE(vq)))459pass = false;460461if (!compare_buffer("initial SVE P",462iov.iov_base + SVE_PT_SVE_PREG_OFFSET(vq, 0),463p_in, SVE_PT_SVE_PREGS_SIZE(vq)))464pass = false;465466if (!compare_buffer("initial SVE FFR",467iov.iov_base + SVE_PT_SVE_FFR_OFFSET(vq),468ffr_in, SVE_PT_SVE_PREG_SIZE(vq)))469pass = false;470} else {471fpsimd = iov.iov_base + SVE_PT_FPSIMD_OFFSET;472if (!compare_buffer("initial V via SVE", &fpsimd->vregs[0],473v_in, sizeof(v_in)))474pass = false;475}476477out:478free(iov.iov_base);479return pass;480}481482static bool check_ptrace_values_ssve(pid_t child, struct test_config *config)483{484struct user_sve_header *sve;485struct user_fpsimd_state *fpsimd;486struct iovec iov;487int ret, vq;488bool pass = true;489490if (!sme_supported())491return true;492493vq = __sve_vq_from_vl(config->sme_vl_in);494495iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);496iov.iov_base = malloc(iov.iov_len);497if (!iov.iov_base) {498ksft_print_msg("OOM allocating %lu byte SSVE buffer\n",499iov.iov_len);500return false;501}502503ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_SSVE, &iov);504if (ret != 0) {505ksft_print_msg("Failed to read initial SSVE: %s (%d)\n",506strerror(errno), errno);507pass = false;508goto out;509}510511sve = iov.iov_base;512513if (sve->vl != config->sme_vl_in) {514ksft_print_msg("Mismatch in initial SSVE VL: %d != %d\n",515sve->vl, config->sme_vl_in);516pass = false;517}518519if ((config->svcr_in & SVCR_SM) && !(sve->flags & SVE_PT_REGS_SVE)) {520ksft_print_msg("NT_ARM_SSVE reports FPSIMD with PSTATE.SM\n");521pass = false;522}523524if (!(svcr_in & SVCR_SM)) {525if (sve->size != sizeof(sve)) {526ksft_print_msg("NT_ARM_SSVE reports data without PSTATE.SM\n");527pass = false;528}529} else {530if (sve->size != SVE_PT_SIZE(vq, sve->flags)) {531ksft_print_msg("Mismatch in SSVE header size: %d != %lu\n",532sve->size, SVE_PT_SIZE(vq, sve->flags));533pass = false;534}535}536537/* The registers might be in completely different formats! */538if (sve->flags & SVE_PT_REGS_SVE) {539if (!compare_buffer("initial SSVE Z",540iov.iov_base + SVE_PT_SVE_ZREG_OFFSET(vq, 0),541z_in, SVE_PT_SVE_ZREGS_SIZE(vq)))542pass = false;543544if (!compare_buffer("initial SSVE P",545iov.iov_base + SVE_PT_SVE_PREG_OFFSET(vq, 0),546p_in, SVE_PT_SVE_PREGS_SIZE(vq)))547pass = false;548549if (!compare_buffer("initial SSVE FFR",550iov.iov_base + SVE_PT_SVE_FFR_OFFSET(vq),551ffr_in, SVE_PT_SVE_PREG_SIZE(vq)))552pass = false;553} else {554fpsimd = iov.iov_base + SVE_PT_FPSIMD_OFFSET;555if (!compare_buffer("initial V via SSVE",556&fpsimd->vregs[0], v_in, sizeof(v_in)))557pass = false;558}559560out:561free(iov.iov_base);562return pass;563}564565static bool check_ptrace_values_za(pid_t child, struct test_config *config)566{567struct user_za_header *za;568struct iovec iov;569int ret, vq;570bool pass = true;571572if (!sme_supported())573return true;574575vq = __sve_vq_from_vl(config->sme_vl_in);576577iov.iov_len = ZA_SIG_CONTEXT_SIZE(vq);578iov.iov_base = malloc(iov.iov_len);579if (!iov.iov_base) {580ksft_print_msg("OOM allocating %lu byte ZA buffer\n",581iov.iov_len);582return false;583}584585ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_ZA, &iov);586if (ret != 0) {587ksft_print_msg("Failed to read initial ZA: %s (%d)\n",588strerror(errno), errno);589pass = false;590goto out;591}592593za = iov.iov_base;594595if (za->vl != config->sme_vl_in) {596ksft_print_msg("Mismatch in initial SME VL: %d != %d\n",597za->vl, config->sme_vl_in);598pass = false;599}600601/* If PSTATE.ZA is not set we should just read the header */602if (config->svcr_in & SVCR_ZA) {603if (za->size != ZA_PT_SIZE(vq)) {604ksft_print_msg("Unexpected ZA ptrace read size: %d != %lu\n",605za->size, ZA_PT_SIZE(vq));606pass = false;607}608609if (!compare_buffer("initial ZA",610iov.iov_base + ZA_PT_ZA_OFFSET,611za_in, ZA_PT_ZA_SIZE(vq)))612pass = false;613} else {614if (za->size != sizeof(*za)) {615ksft_print_msg("Unexpected ZA ptrace read size: %d != %lu\n",616za->size, sizeof(*za));617pass = false;618}619}620621out:622free(iov.iov_base);623return pass;624}625626static bool check_ptrace_values_zt(pid_t child, struct test_config *config)627{628uint8_t buf[512];629struct iovec iov;630int ret;631632if (!sme2_supported())633return true;634635iov.iov_base = &buf;636iov.iov_len = ZT_SIG_REG_BYTES;637ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_ZT, &iov);638if (ret != 0) {639ksft_print_msg("Failed to read initial ZT: %s (%d)\n",640strerror(errno), errno);641return false;642}643644return compare_buffer("initial ZT", buf, zt_in, ZT_SIG_REG_BYTES);645}646647static bool check_ptrace_values_fpmr(pid_t child, struct test_config *config)648{649uint64_t val;650struct iovec iov;651int ret;652653if (!fpmr_supported())654return true;655656iov.iov_base = &val;657iov.iov_len = sizeof(val);658ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_FPMR, &iov);659if (ret != 0) {660ksft_print_msg("Failed to read initial FPMR: %s (%d)\n",661strerror(errno), errno);662return false;663}664665return compare_buffer("initial FPMR", &val, &fpmr_in, sizeof(val));666}667668static bool check_ptrace_values(pid_t child, struct test_config *config)669{670bool pass = true;671struct user_fpsimd_state fpsimd;672struct iovec iov;673int ret;674675iov.iov_base = &fpsimd;676iov.iov_len = sizeof(fpsimd);677ret = ptrace(PTRACE_GETREGSET, child, NT_PRFPREG, &iov);678if (ret == 0) {679if (!compare_buffer("initial V", &fpsimd.vregs, v_in,680sizeof(v_in))) {681pass = false;682}683} else {684ksft_print_msg("Failed to read initial V: %s (%d)\n",685strerror(errno), errno);686pass = false;687}688689if (!check_ptrace_values_sve(child, config))690pass = false;691692if (!check_ptrace_values_ssve(child, config))693pass = false;694695if (!check_ptrace_values_za(child, config))696pass = false;697698if (!check_ptrace_values_zt(child, config))699pass = false;700701if (!check_ptrace_values_fpmr(child, config))702pass = false;703704return pass;705}706707static bool run_parent(pid_t child, struct test_definition *test,708struct test_config *config)709{710int wait_status, ret;711pid_t pid;712bool pass;713714/* Initial attach */715while (1) {716pid = waitpid(child, &wait_status, 0);717if (pid < 0) {718if (errno == EINTR)719continue;720ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",721strerror(errno), errno);722}723724if (pid == child)725break;726}727728if (WIFEXITED(wait_status)) {729ksft_print_msg("Child exited loading values with status %d\n",730WEXITSTATUS(wait_status));731pass = false;732goto out;733}734735if (WIFSIGNALED(wait_status)) {736ksft_print_msg("Child died from signal %d loading values\n",737WTERMSIG(wait_status));738pass = false;739goto out;740}741742/* Read initial values via ptrace */743pass = check_ptrace_values(child, config);744745/* Do whatever writes we want to do */746if (test->modify_values)747test->modify_values(child, config);748749if (!continue_breakpoint(child, PTRACE_CONT))750goto cleanup;751752while (1) {753pid = waitpid(child, &wait_status, 0);754if (pid < 0) {755if (errno == EINTR)756continue;757ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",758strerror(errno), errno);759}760761if (pid == child)762break;763}764765if (WIFEXITED(wait_status)) {766ksft_print_msg("Child exited saving values with status %d\n",767WEXITSTATUS(wait_status));768pass = false;769goto out;770}771772if (WIFSIGNALED(wait_status)) {773ksft_print_msg("Child died from signal %d saving values\n",774WTERMSIG(wait_status));775pass = false;776goto out;777}778779/* See what happened as a result */780read_child_regs(child);781782if (!continue_breakpoint(child, PTRACE_DETACH))783goto cleanup;784785/* The child should exit cleanly */786got_alarm = false;787alarm(1);788while (1) {789if (got_alarm) {790ksft_print_msg("Wait for child timed out\n");791goto cleanup;792}793794pid = waitpid(child, &wait_status, 0);795if (pid < 0) {796if (errno == EINTR)797continue;798ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",799strerror(errno), errno);800}801802if (pid == child)803break;804}805alarm(0);806807if (got_alarm) {808ksft_print_msg("Timed out waiting for child\n");809pass = false;810goto cleanup;811}812813if (pid == child && WIFSIGNALED(wait_status)) {814ksft_print_msg("Child died from signal %d cleaning up\n",815WTERMSIG(wait_status));816pass = false;817goto out;818}819820if (pid == child && WIFEXITED(wait_status)) {821if (WEXITSTATUS(wait_status) != 0) {822ksft_print_msg("Child exited with error %d\n",823WEXITSTATUS(wait_status));824pass = false;825}826} else {827ksft_print_msg("Child did not exit cleanly\n");828pass = false;829goto cleanup;830}831832goto out;833834cleanup:835ret = kill(child, SIGKILL);836if (ret != 0) {837ksft_print_msg("kill() failed: %s (%d)\n",838strerror(errno), errno);839return false;840}841842while (1) {843pid = waitpid(child, &wait_status, 0);844if (pid < 0) {845if (errno == EINTR)846continue;847ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",848strerror(errno), errno);849}850851if (pid == child)852break;853}854855out:856return pass;857}858859static void fill_random(void *buf, size_t size)860{861int i;862uint32_t *lbuf = buf;863864/* random() returns a 32 bit number regardless of the size of long */865for (i = 0; i < size / sizeof(uint32_t); i++)866lbuf[i] = random();867}868869static void fill_random_ffr(void *buf, size_t vq)870{871uint8_t *lbuf = buf;872int bits, i;873874/*875* Only values with a continuous set of 0..n bits set are876* valid for FFR, set all bits then clear a random number of877* high bits.878*/879memset(buf, 0, __SVE_FFR_SIZE(vq));880881bits = random() % (__SVE_FFR_SIZE(vq) * 8);882for (i = 0; i < bits / 8; i++)883lbuf[i] = 0xff;884if (bits / 8 != __SVE_FFR_SIZE(vq))885lbuf[i] = (1 << (bits % 8)) - 1;886}887888static void fpsimd_to_sve(__uint128_t *v, char *z, int vl)889{890int vq = __sve_vq_from_vl(vl);891int i;892__uint128_t *p;893894if (!vl)895return;896897for (i = 0; i < __SVE_NUM_ZREGS; i++) {898p = (__uint128_t *)&z[__SVE_ZREG_OFFSET(vq, i)];899*p = arm64_cpu_to_le128(v[i]);900}901}902903static void set_initial_values(struct test_config *config)904{905int vq = __sve_vq_from_vl(vl_in(config));906int sme_vq = __sve_vq_from_vl(config->sme_vl_in);907908svcr_in = config->svcr_in;909svcr_expected = config->svcr_expected;910svcr_out = 0;911912fill_random(&v_in, sizeof(v_in));913memcpy(v_expected, v_in, sizeof(v_in));914memset(v_out, 0, sizeof(v_out));915916/* Changes will be handled in the test case */917if (sve_supported() || (config->svcr_in & SVCR_SM)) {918/* The low 128 bits of Z are shared with the V registers */919fill_random(&z_in, __SVE_ZREGS_SIZE(vq));920fpsimd_to_sve(v_in, z_in, vl_in(config));921memcpy(z_expected, z_in, __SVE_ZREGS_SIZE(vq));922memset(z_out, 0, sizeof(z_out));923924fill_random(&p_in, __SVE_PREGS_SIZE(vq));925memcpy(p_expected, p_in, __SVE_PREGS_SIZE(vq));926memset(p_out, 0, sizeof(p_out));927928if ((config->svcr_in & SVCR_SM) && !fa64_supported())929memset(ffr_in, 0, __SVE_PREG_SIZE(vq));930else931fill_random_ffr(&ffr_in, vq);932memcpy(ffr_expected, ffr_in, __SVE_PREG_SIZE(vq));933memset(ffr_out, 0, __SVE_PREG_SIZE(vq));934}935936if (config->svcr_in & SVCR_ZA)937fill_random(za_in, ZA_SIG_REGS_SIZE(sme_vq));938else939memset(za_in, 0, ZA_SIG_REGS_SIZE(sme_vq));940if (config->svcr_expected & SVCR_ZA)941memcpy(za_expected, za_in, ZA_SIG_REGS_SIZE(sme_vq));942else943memset(za_expected, 0, ZA_SIG_REGS_SIZE(sme_vq));944if (sme_supported())945memset(za_out, 0, sizeof(za_out));946947if (sme2_supported()) {948if (config->svcr_in & SVCR_ZA)949fill_random(zt_in, ZT_SIG_REG_BYTES);950else951memset(zt_in, 0, ZT_SIG_REG_BYTES);952if (config->svcr_expected & SVCR_ZA)953memcpy(zt_expected, zt_in, ZT_SIG_REG_BYTES);954else955memset(zt_expected, 0, ZT_SIG_REG_BYTES);956memset(zt_out, 0, sizeof(zt_out));957}958959if (fpmr_supported()) {960fill_random(&fpmr_in, sizeof(fpmr_in));961fpmr_in &= FPMR_SAFE_BITS;962fpmr_expected = fpmr_in;963} else {964fpmr_in = 0;965fpmr_expected = 0;966fpmr_out = 0;967}968}969970static bool check_memory_values(struct test_config *config)971{972bool pass = true;973int vq, sme_vq;974975if (!compare_buffer("saved V", v_out, v_expected, sizeof(v_out)))976pass = false;977978vq = __sve_vq_from_vl(vl_expected(config));979sme_vq = __sve_vq_from_vl(config->sme_vl_expected);980981if (svcr_out != svcr_expected) {982ksft_print_msg("Mismatch in saved SVCR %lx != %lx\n",983svcr_out, svcr_expected);984pass = false;985}986987if (sve_vl_out != config->sve_vl_expected) {988ksft_print_msg("Mismatch in SVE VL: %ld != %d\n",989sve_vl_out, config->sve_vl_expected);990pass = false;991}992993if (sme_vl_out != config->sme_vl_expected) {994ksft_print_msg("Mismatch in SME VL: %ld != %d\n",995sme_vl_out, config->sme_vl_expected);996pass = false;997}998999if (!compare_buffer("saved Z", z_out, z_expected,1000__SVE_ZREGS_SIZE(vq)))1001pass = false;10021003if (!compare_buffer("saved P", p_out, p_expected,1004__SVE_PREGS_SIZE(vq)))1005pass = false;10061007if (!compare_buffer("saved FFR", ffr_out, ffr_expected,1008__SVE_PREG_SIZE(vq)))1009pass = false;10101011if (!compare_buffer("saved ZA", za_out, za_expected,1012ZA_PT_ZA_SIZE(sme_vq)))1013pass = false;10141015if (!compare_buffer("saved ZT", zt_out, zt_expected, ZT_SIG_REG_BYTES))1016pass = false;10171018if (fpmr_out != fpmr_expected) {1019ksft_print_msg("Mismatch in saved FPMR: %lx != %lx\n",1020fpmr_out, fpmr_expected);1021pass = false;1022}10231024return pass;1025}10261027static bool sve_sme_same(struct test_config *config)1028{1029if (config->sve_vl_in != config->sve_vl_expected)1030return false;10311032if (config->sme_vl_in != config->sme_vl_expected)1033return false;10341035if (config->svcr_in != config->svcr_expected)1036return false;10371038return true;1039}10401041static bool sve_write_supported(struct test_config *config)1042{1043if (!sve_supported() && !sme_supported())1044return false;10451046if ((config->svcr_in & SVCR_ZA) != (config->svcr_expected & SVCR_ZA))1047return false;10481049if (config->svcr_expected & SVCR_SM) {1050if (config->sve_vl_in != config->sve_vl_expected) {1051return false;1052}10531054/* Changing the SME VL disables ZA */1055if ((config->svcr_expected & SVCR_ZA) &&1056(config->sme_vl_in != config->sme_vl_expected)) {1057return false;1058}1059} else {1060if (config->sme_vl_in != config->sme_vl_expected) {1061return false;1062}10631064if (!sve_supported())1065return false;1066}10671068return true;1069}10701071static bool sve_write_fpsimd_supported(struct test_config *config)1072{1073if (!sve_supported())1074return false;10751076if ((config->svcr_in & SVCR_ZA) != (config->svcr_expected & SVCR_ZA))1077return false;10781079if (config->svcr_expected & SVCR_SM)1080return false;10811082if (config->sme_vl_in != config->sme_vl_expected)1083return false;10841085return true;1086}10871088static void fpsimd_write_expected(struct test_config *config)1089{1090int vl;10911092fill_random(&v_expected, sizeof(v_expected));10931094/* The SVE registers are flushed by a FPSIMD write */1095vl = vl_expected(config);10961097memset(z_expected, 0, __SVE_ZREGS_SIZE(__sve_vq_from_vl(vl)));1098memset(p_expected, 0, __SVE_PREGS_SIZE(__sve_vq_from_vl(vl)));1099memset(ffr_expected, 0, __SVE_PREG_SIZE(__sve_vq_from_vl(vl)));11001101fpsimd_to_sve(v_expected, z_expected, vl);1102}11031104static void fpsimd_write(pid_t child, struct test_config *test_config)1105{1106struct user_fpsimd_state fpsimd;1107struct iovec iov;1108int ret;11091110memset(&fpsimd, 0, sizeof(fpsimd));1111memcpy(&fpsimd.vregs, v_expected, sizeof(v_expected));11121113iov.iov_base = &fpsimd;1114iov.iov_len = sizeof(fpsimd);1115ret = ptrace(PTRACE_SETREGSET, child, NT_PRFPREG, &iov);1116if (ret == -1)1117ksft_print_msg("FPSIMD set failed: (%s) %d\n",1118strerror(errno), errno);1119}11201121static bool fpmr_write_supported(struct test_config *config)1122{1123if (!fpmr_supported())1124return false;11251126if (!sve_sme_same(config))1127return false;11281129return true;1130}11311132static void fpmr_write_expected(struct test_config *config)1133{1134fill_random(&fpmr_expected, sizeof(fpmr_expected));1135fpmr_expected &= FPMR_SAFE_BITS;1136}11371138static void fpmr_write(pid_t child, struct test_config *config)1139{1140struct iovec iov;1141int ret;11421143iov.iov_len = sizeof(fpmr_expected);1144iov.iov_base = &fpmr_expected;1145ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_FPMR, &iov);1146if (ret != 0)1147ksft_print_msg("Failed to write FPMR: %s (%d)\n",1148strerror(errno), errno);1149}11501151static void sve_write_expected(struct test_config *config)1152{1153int vl = vl_expected(config);1154int sme_vq = __sve_vq_from_vl(config->sme_vl_expected);11551156if (!vl)1157return;11581159fill_random(z_expected, __SVE_ZREGS_SIZE(__sve_vq_from_vl(vl)));1160fill_random(p_expected, __SVE_PREGS_SIZE(__sve_vq_from_vl(vl)));11611162if ((svcr_expected & SVCR_SM) && !fa64_supported())1163memset(ffr_expected, 0, __SVE_PREG_SIZE(sme_vq));1164else1165fill_random_ffr(ffr_expected, __sve_vq_from_vl(vl));11661167/* Share the low bits of Z with V */1168fill_random(&v_expected, sizeof(v_expected));1169fpsimd_to_sve(v_expected, z_expected, vl);11701171if (config->sme_vl_in != config->sme_vl_expected) {1172memset(za_expected, 0, ZA_PT_ZA_SIZE(sme_vq));1173memset(zt_expected, 0, sizeof(zt_expected));1174}1175}11761177static void sve_write_sve(pid_t child, struct test_config *config)1178{1179struct user_sve_header *sve;1180struct iovec iov;1181int ret, vl, vq, regset;11821183vl = vl_expected(config);1184vq = __sve_vq_from_vl(vl);11851186if (!vl)1187return;11881189iov.iov_len = SVE_PT_SIZE(vq, SVE_PT_REGS_SVE);1190iov.iov_base = malloc(iov.iov_len);1191if (!iov.iov_base) {1192ksft_print_msg("Failed allocating %lu byte SVE write buffer\n",1193iov.iov_len);1194return;1195}1196memset(iov.iov_base, 0, iov.iov_len);11971198sve = iov.iov_base;1199sve->size = iov.iov_len;1200sve->flags = SVE_PT_REGS_SVE;1201sve->vl = vl;12021203memcpy(iov.iov_base + SVE_PT_SVE_ZREG_OFFSET(vq, 0),1204z_expected, SVE_PT_SVE_ZREGS_SIZE(vq));1205memcpy(iov.iov_base + SVE_PT_SVE_PREG_OFFSET(vq, 0),1206p_expected, SVE_PT_SVE_PREGS_SIZE(vq));1207memcpy(iov.iov_base + SVE_PT_SVE_FFR_OFFSET(vq),1208ffr_expected, SVE_PT_SVE_PREG_SIZE(vq));12091210if (svcr_expected & SVCR_SM)1211regset = NT_ARM_SSVE;1212else1213regset = NT_ARM_SVE;12141215ret = ptrace(PTRACE_SETREGSET, child, regset, &iov);1216if (ret != 0)1217ksft_print_msg("Failed to write SVE: %s (%d)\n",1218strerror(errno), errno);12191220free(iov.iov_base);1221}12221223static void sve_write_fpsimd(pid_t child, struct test_config *config)1224{1225struct user_sve_header *sve;1226struct user_fpsimd_state *fpsimd;1227struct iovec iov;1228int ret, vl, vq;12291230vl = vl_expected(config);1231vq = __sve_vq_from_vl(vl);12321233if (!vl)1234return;12351236iov.iov_len = SVE_PT_SIZE(vq, SVE_PT_REGS_FPSIMD);1237iov.iov_base = malloc(iov.iov_len);1238if (!iov.iov_base) {1239ksft_print_msg("Failed allocating %lu byte SVE write buffer\n",1240iov.iov_len);1241return;1242}1243memset(iov.iov_base, 0, iov.iov_len);12441245sve = iov.iov_base;1246sve->size = iov.iov_len;1247sve->flags = SVE_PT_REGS_FPSIMD;1248sve->vl = vl;12491250fpsimd = iov.iov_base + SVE_PT_REGS_OFFSET;1251memcpy(&fpsimd->vregs, v_expected, sizeof(v_expected));12521253ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_SVE, &iov);1254if (ret != 0)1255ksft_print_msg("Failed to write SVE: %s (%d)\n",1256strerror(errno), errno);12571258free(iov.iov_base);1259}12601261static bool za_write_supported(struct test_config *config)1262{1263if ((config->svcr_in & SVCR_SM) != (config->svcr_expected & SVCR_SM))1264return false;12651266return true;1267}12681269static void za_write_expected(struct test_config *config)1270{1271int sme_vq, sve_vq;12721273sme_vq = __sve_vq_from_vl(config->sme_vl_expected);12741275if (config->svcr_expected & SVCR_ZA) {1276fill_random(za_expected, ZA_PT_ZA_SIZE(sme_vq));1277} else {1278memset(za_expected, 0, ZA_PT_ZA_SIZE(sme_vq));1279memset(zt_expected, 0, sizeof(zt_expected));1280}12811282/* Changing the SME VL flushes ZT, SVE state */1283if (config->sme_vl_in != config->sme_vl_expected) {1284sve_vq = __sve_vq_from_vl(vl_expected(config));1285memset(z_expected, 0, __SVE_ZREGS_SIZE(sve_vq));1286memset(p_expected, 0, __SVE_PREGS_SIZE(sve_vq));1287memset(ffr_expected, 0, __SVE_PREG_SIZE(sve_vq));1288memset(zt_expected, 0, sizeof(zt_expected));12891290fpsimd_to_sve(v_expected, z_expected, vl_expected(config));1291}1292}12931294static void za_write(pid_t child, struct test_config *config)1295{1296struct user_za_header *za;1297struct iovec iov;1298int ret, vq;12991300vq = __sve_vq_from_vl(config->sme_vl_expected);13011302if (config->svcr_expected & SVCR_ZA)1303iov.iov_len = ZA_PT_SIZE(vq);1304else1305iov.iov_len = sizeof(*za);1306iov.iov_base = malloc(iov.iov_len);1307if (!iov.iov_base) {1308ksft_print_msg("Failed allocating %lu byte ZA write buffer\n",1309iov.iov_len);1310return;1311}1312memset(iov.iov_base, 0, iov.iov_len);13131314za = iov.iov_base;1315za->size = iov.iov_len;1316za->vl = config->sme_vl_expected;1317if (config->svcr_expected & SVCR_ZA)1318memcpy(iov.iov_base + ZA_PT_ZA_OFFSET, za_expected,1319ZA_PT_ZA_SIZE(vq));13201321ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_ZA, &iov);1322if (ret != 0)1323ksft_print_msg("Failed to write ZA: %s (%d)\n",1324strerror(errno), errno);13251326free(iov.iov_base);1327}13281329static bool zt_write_supported(struct test_config *config)1330{1331if (!sme2_supported())1332return false;1333if (config->sme_vl_in != config->sme_vl_expected)1334return false;1335if (!(config->svcr_expected & SVCR_ZA))1336return false;1337if ((config->svcr_in & SVCR_SM) != (config->svcr_expected & SVCR_SM))1338return false;13391340return true;1341}13421343static void zt_write_expected(struct test_config *config)1344{1345int sme_vq;13461347sme_vq = __sve_vq_from_vl(config->sme_vl_expected);13481349if (config->svcr_expected & SVCR_ZA) {1350fill_random(zt_expected, sizeof(zt_expected));1351} else {1352memset(za_expected, 0, ZA_PT_ZA_SIZE(sme_vq));1353memset(zt_expected, 0, sizeof(zt_expected));1354}1355}13561357static void zt_write(pid_t child, struct test_config *config)1358{1359struct iovec iov;1360int ret;13611362iov.iov_len = ZT_SIG_REG_BYTES;1363iov.iov_base = zt_expected;1364ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_ZT, &iov);1365if (ret != 0)1366ksft_print_msg("Failed to write ZT: %s (%d)\n",1367strerror(errno), errno);1368}13691370/* Actually run a test */1371static void run_test(struct test_definition *test, struct test_config *config)1372{1373pid_t child;1374char name[1024];1375bool pass;13761377if (sve_supported() && sme_supported())1378snprintf(name, sizeof(name), "%s, SVE %d->%d, SME %d/%x->%d/%x",1379test->name,1380config->sve_vl_in, config->sve_vl_expected,1381config->sme_vl_in, config->svcr_in,1382config->sme_vl_expected, config->svcr_expected);1383else if (sve_supported())1384snprintf(name, sizeof(name), "%s, SVE %d->%d", test->name,1385config->sve_vl_in, config->sve_vl_expected);1386else if (sme_supported())1387snprintf(name, sizeof(name), "%s, SME %d/%x->%d/%x",1388test->name,1389config->sme_vl_in, config->svcr_in,1390config->sme_vl_expected, config->svcr_expected);1391else1392snprintf(name, sizeof(name), "%s", test->name);13931394if (test->supported && !test->supported(config)) {1395ksft_test_result_skip("%s\n", name);1396return;1397}13981399set_initial_values(config);14001401if (test->set_expected_values)1402test->set_expected_values(config);14031404child = fork();1405if (child < 0)1406ksft_exit_fail_msg("fork() failed: %s (%d)\n",1407strerror(errno), errno);1408/* run_child() never returns */1409if (child == 0)1410run_child(config);14111412pass = run_parent(child, test, config);1413if (!check_memory_values(config))1414pass = false;14151416ksft_test_result(pass, "%s\n", name);1417}14181419static void run_tests(struct test_definition defs[], int count,1420struct test_config *config)1421{1422int i;14231424for (i = 0; i < count; i++)1425run_test(&defs[i], config);1426}14271428static struct test_definition base_test_defs[] = {1429{1430.name = "No writes",1431.supported = sve_sme_same,1432},1433{1434.name = "FPSIMD write",1435.supported = sve_sme_same,1436.set_expected_values = fpsimd_write_expected,1437.modify_values = fpsimd_write,1438},1439{1440.name = "FPMR write",1441.supported = fpmr_write_supported,1442.set_expected_values = fpmr_write_expected,1443.modify_values = fpmr_write,1444},1445};14461447static struct test_definition sve_test_defs[] = {1448{1449.name = "SVE write",1450.supported = sve_write_supported,1451.set_expected_values = sve_write_expected,1452.modify_values = sve_write_sve,1453},1454{1455.name = "SVE write FPSIMD format",1456.supported = sve_write_fpsimd_supported,1457.set_expected_values = fpsimd_write_expected,1458.modify_values = sve_write_fpsimd,1459},1460};14611462static struct test_definition za_test_defs[] = {1463{1464.name = "ZA write",1465.supported = za_write_supported,1466.set_expected_values = za_write_expected,1467.modify_values = za_write,1468},1469};14701471static struct test_definition zt_test_defs[] = {1472{1473.name = "ZT write",1474.supported = zt_write_supported,1475.set_expected_values = zt_write_expected,1476.modify_values = zt_write,1477},1478};14791480static int sve_vls[MAX_NUM_VLS], sme_vls[MAX_NUM_VLS];1481static int sve_vl_count, sme_vl_count;14821483static void probe_vls(const char *name, int vls[], int *vl_count, int set_vl)1484{1485unsigned int vq;1486int vl;14871488*vl_count = 0;14891490for (vq = ARCH_VQ_MAX; vq > 0; vq /= 2) {1491vl = prctl(set_vl, vq * 16);1492if (vl == -1)1493ksft_exit_fail_msg("SET_VL failed: %s (%d)\n",1494strerror(errno), errno);14951496vl &= PR_SVE_VL_LEN_MASK;14971498if (*vl_count && (vl == vls[*vl_count - 1]))1499break;15001501vq = sve_vq_from_vl(vl);15021503vls[*vl_count] = vl;1504*vl_count += 1;1505}15061507if (*vl_count > 2) {1508/* Just use the minimum and maximum */1509vls[1] = vls[*vl_count - 1];1510ksft_print_msg("%d %s VLs, using %d and %d\n",1511*vl_count, name, vls[0], vls[1]);1512*vl_count = 2;1513} else {1514ksft_print_msg("%d %s VLs\n", *vl_count, name);1515}1516}15171518static struct {1519int svcr_in, svcr_expected;1520} svcr_combinations[] = {1521{ .svcr_in = 0, .svcr_expected = 0, },1522{ .svcr_in = 0, .svcr_expected = SVCR_SM, },1523{ .svcr_in = 0, .svcr_expected = SVCR_ZA, },1524/* Can't enable both SM and ZA with a single ptrace write */15251526{ .svcr_in = SVCR_SM, .svcr_expected = 0, },1527{ .svcr_in = SVCR_SM, .svcr_expected = SVCR_SM, },1528{ .svcr_in = SVCR_SM, .svcr_expected = SVCR_ZA, },1529{ .svcr_in = SVCR_SM, .svcr_expected = SVCR_SM | SVCR_ZA, },15301531{ .svcr_in = SVCR_ZA, .svcr_expected = 0, },1532{ .svcr_in = SVCR_ZA, .svcr_expected = SVCR_SM, },1533{ .svcr_in = SVCR_ZA, .svcr_expected = SVCR_ZA, },1534{ .svcr_in = SVCR_ZA, .svcr_expected = SVCR_SM | SVCR_ZA, },15351536{ .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = 0, },1537{ .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = SVCR_SM, },1538{ .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = SVCR_ZA, },1539{ .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = SVCR_SM | SVCR_ZA, },1540};15411542static void run_sve_tests(void)1543{1544struct test_config test_config;1545int i, j;15461547if (!sve_supported())1548return;15491550test_config.sme_vl_in = sme_vls[0];1551test_config.sme_vl_expected = sme_vls[0];1552test_config.svcr_in = 0;1553test_config.svcr_expected = 0;15541555for (i = 0; i < sve_vl_count; i++) {1556test_config.sve_vl_in = sve_vls[i];15571558for (j = 0; j < sve_vl_count; j++) {1559test_config.sve_vl_expected = sve_vls[j];15601561run_tests(base_test_defs,1562ARRAY_SIZE(base_test_defs),1563&test_config);1564if (sve_supported())1565run_tests(sve_test_defs,1566ARRAY_SIZE(sve_test_defs),1567&test_config);1568}1569}15701571}15721573static void run_sme_tests(void)1574{1575struct test_config test_config;1576int i, j, k;15771578if (!sme_supported())1579return;15801581test_config.sve_vl_in = sve_vls[0];1582test_config.sve_vl_expected = sve_vls[0];15831584/*1585* Every SME VL/SVCR combination1586*/1587for (i = 0; i < sme_vl_count; i++) {1588test_config.sme_vl_in = sme_vls[i];15891590for (j = 0; j < sme_vl_count; j++) {1591test_config.sme_vl_expected = sme_vls[j];15921593for (k = 0; k < ARRAY_SIZE(svcr_combinations); k++) {1594test_config.svcr_in = svcr_combinations[k].svcr_in;1595test_config.svcr_expected = svcr_combinations[k].svcr_expected;15961597run_tests(base_test_defs,1598ARRAY_SIZE(base_test_defs),1599&test_config);1600run_tests(sve_test_defs,1601ARRAY_SIZE(sve_test_defs),1602&test_config);1603run_tests(za_test_defs,1604ARRAY_SIZE(za_test_defs),1605&test_config);16061607if (sme2_supported())1608run_tests(zt_test_defs,1609ARRAY_SIZE(zt_test_defs),1610&test_config);1611}1612}1613}1614}16151616int main(void)1617{1618struct test_config test_config;1619struct sigaction sa;1620int tests, ret, tmp;16211622srandom(getpid());16231624ksft_print_header();16251626if (sve_supported()) {1627probe_vls("SVE", sve_vls, &sve_vl_count, PR_SVE_SET_VL);16281629tests = ARRAY_SIZE(base_test_defs) +1630ARRAY_SIZE(sve_test_defs);1631tests *= sve_vl_count * sve_vl_count;1632} else {1633/* Only run the FPSIMD tests */1634sve_vl_count = 1;1635tests = ARRAY_SIZE(base_test_defs);1636}16371638if (sme_supported()) {1639probe_vls("SME", sme_vls, &sme_vl_count, PR_SME_SET_VL);16401641tmp = ARRAY_SIZE(base_test_defs) + ARRAY_SIZE(sve_test_defs)1642+ ARRAY_SIZE(za_test_defs);16431644if (sme2_supported())1645tmp += ARRAY_SIZE(zt_test_defs);16461647tmp *= sme_vl_count * sme_vl_count;1648tmp *= ARRAY_SIZE(svcr_combinations);1649tests += tmp;1650} else {1651sme_vl_count = 1;1652}16531654if (sme2_supported())1655ksft_print_msg("SME2 supported\n");16561657if (fa64_supported())1658ksft_print_msg("FA64 supported\n");16591660if (fpmr_supported())1661ksft_print_msg("FPMR supported\n");16621663ksft_set_plan(tests);16641665/* Get signal handers ready before we start any children */1666memset(&sa, 0, sizeof(sa));1667sa.sa_sigaction = handle_alarm;1668sa.sa_flags = SA_RESTART | SA_SIGINFO;1669sigemptyset(&sa.sa_mask);1670ret = sigaction(SIGALRM, &sa, NULL);1671if (ret < 0)1672ksft_print_msg("Failed to install SIGALRM handler: %s (%d)\n",1673strerror(errno), errno);16741675/*1676* Run the test set if there is no SVE or SME, with those we1677* have to pick a VL for each run.1678*/1679if (!sve_supported() && !sme_supported()) {1680test_config.sve_vl_in = 0;1681test_config.sve_vl_expected = 0;1682test_config.sme_vl_in = 0;1683test_config.sme_vl_expected = 0;1684test_config.svcr_in = 0;1685test_config.svcr_expected = 0;16861687run_tests(base_test_defs, ARRAY_SIZE(base_test_defs),1688&test_config);1689}16901691run_sve_tests();1692run_sme_tests();16931694ksft_finished();1695}169616971698