1504 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2023 ARM Limited.4 * Original author: Mark Brown <broonie@kernel.org>5 */6 7#define _GNU_SOURCE8 9#include <errno.h>10#include <stdbool.h>11#include <stddef.h>12#include <stdio.h>13#include <stdlib.h>14#include <string.h>15#include <unistd.h>16 17#include <sys/auxv.h>18#include <sys/prctl.h>19#include <sys/ptrace.h>20#include <sys/types.h>21#include <sys/uio.h>22#include <sys/wait.h>23 24#include <linux/kernel.h>25 26#include <asm/sigcontext.h>27#include <asm/sve_context.h>28#include <asm/ptrace.h>29 30#include "../../kselftest.h"31 32#include "fp-ptrace.h"33 34/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */35#ifndef NT_ARM_SVE36#define NT_ARM_SVE 0x40537#endif38 39#ifndef NT_ARM_SSVE40#define NT_ARM_SSVE 0x40b41#endif42 43#ifndef NT_ARM_ZA44#define NT_ARM_ZA 0x40c45#endif46 47#ifndef NT_ARM_ZT48#define NT_ARM_ZT 0x40d49#endif50 51#define ARCH_VQ_MAX 25652 53/* VL 128..2048 in powers of 2 */54#define MAX_NUM_VLS 555 56#define NUM_FPR 3257__uint128_t v_in[NUM_FPR];58__uint128_t v_expected[NUM_FPR];59__uint128_t v_out[NUM_FPR];60 61char z_in[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];62char z_expected[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];63char z_out[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];64 65char p_in[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];66char p_expected[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];67char p_out[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];68 69char ffr_in[__SVE_PREG_SIZE(ARCH_VQ_MAX)];70char ffr_expected[__SVE_PREG_SIZE(ARCH_VQ_MAX)];71char ffr_out[__SVE_PREG_SIZE(ARCH_VQ_MAX)];72 73char za_in[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];74char za_expected[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];75char za_out[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];76 77char zt_in[ZT_SIG_REG_BYTES];78char zt_expected[ZT_SIG_REG_BYTES];79char zt_out[ZT_SIG_REG_BYTES];80 81uint64_t sve_vl_out;82uint64_t sme_vl_out;83uint64_t svcr_in, svcr_expected, svcr_out;84 85void load_and_save(int sve, int sme, int sme2, int fa64);86 87static bool got_alarm;88 89static void handle_alarm(int sig, siginfo_t *info, void *context)90{91 got_alarm = true;92}93 94#ifdef CONFIG_CPU_BIG_ENDIAN95static __uint128_t arm64_cpu_to_le128(__uint128_t x)96{97 u64 a = swab64(x);98 u64 b = swab64(x >> 64);99 100 return ((__uint128_t)a << 64) | b;101}102#else103static __uint128_t arm64_cpu_to_le128(__uint128_t x)104{105 return x;106}107#endif108 109#define arm64_le128_to_cpu(x) arm64_cpu_to_le128(x)110 111static bool sve_supported(void)112{113 return getauxval(AT_HWCAP) & HWCAP_SVE;114}115 116static bool sme_supported(void)117{118 return getauxval(AT_HWCAP2) & HWCAP2_SME;119}120 121static bool sme2_supported(void)122{123 return getauxval(AT_HWCAP2) & HWCAP2_SME2;124}125 126static bool fa64_supported(void)127{128 return getauxval(AT_HWCAP2) & HWCAP2_SME_FA64;129}130 131static bool compare_buffer(const char *name, void *out,132 void *expected, size_t size)133{134 void *tmp;135 136 if (memcmp(out, expected, size) == 0)137 return true;138 139 ksft_print_msg("Mismatch in %s\n", name);140 141 /* Did we just get zeros back? */142 tmp = malloc(size);143 if (!tmp) {144 ksft_print_msg("OOM allocating %lu bytes for %s\n",145 size, name);146 ksft_exit_fail();147 }148 memset(tmp, 0, size);149 150 if (memcmp(out, tmp, size) == 0)151 ksft_print_msg("%s is zero\n", name);152 153 free(tmp);154 155 return false;156}157 158struct test_config {159 int sve_vl_in;160 int sve_vl_expected;161 int sme_vl_in;162 int sme_vl_expected;163 int svcr_in;164 int svcr_expected;165};166 167struct test_definition {168 const char *name;169 bool sve_vl_change;170 bool (*supported)(struct test_config *config);171 void (*set_expected_values)(struct test_config *config);172 void (*modify_values)(pid_t child, struct test_config *test_config);173};174 175static int vl_in(struct test_config *config)176{177 int vl;178 179 if (config->svcr_in & SVCR_SM)180 vl = config->sme_vl_in;181 else182 vl = config->sve_vl_in;183 184 return vl;185}186 187static int vl_expected(struct test_config *config)188{189 int vl;190 191 if (config->svcr_expected & SVCR_SM)192 vl = config->sme_vl_expected;193 else194 vl = config->sve_vl_expected;195 196 return vl;197}198 199static void run_child(struct test_config *config)200{201 int ret;202 203 /* Let the parent attach to us */204 ret = ptrace(PTRACE_TRACEME, 0, 0, 0);205 if (ret < 0)206 ksft_exit_fail_msg("PTRACE_TRACEME failed: %s (%d)\n",207 strerror(errno), errno);208 209 /* VL setup */210 if (sve_supported()) {211 ret = prctl(PR_SVE_SET_VL, config->sve_vl_in);212 if (ret != config->sve_vl_in) {213 ksft_print_msg("Failed to set SVE VL %d: %d\n",214 config->sve_vl_in, ret);215 }216 }217 218 if (sme_supported()) {219 ret = prctl(PR_SME_SET_VL, config->sme_vl_in);220 if (ret != config->sme_vl_in) {221 ksft_print_msg("Failed to set SME VL %d: %d\n",222 config->sme_vl_in, ret);223 }224 }225 226 /* Load values and wait for the parent */227 load_and_save(sve_supported(), sme_supported(),228 sme2_supported(), fa64_supported());229 230 exit(0);231}232 233static void read_one_child_regs(pid_t child, char *name,234 struct iovec *iov_parent,235 struct iovec *iov_child)236{237 int len = iov_parent->iov_len;238 int ret;239 240 ret = process_vm_readv(child, iov_parent, 1, iov_child, 1, 0);241 if (ret == -1)242 ksft_print_msg("%s read failed: %s (%d)\n",243 name, strerror(errno), errno);244 else if (ret != len)245 ksft_print_msg("Short read of %s: %d\n", name, ret);246}247 248static void read_child_regs(pid_t child)249{250 struct iovec iov_parent, iov_child;251 252 /*253 * Since the child fork()ed from us the buffer addresses are254 * the same in parent and child.255 */256 iov_parent.iov_base = &v_out;257 iov_parent.iov_len = sizeof(v_out);258 iov_child.iov_base = &v_out;259 iov_child.iov_len = sizeof(v_out);260 read_one_child_regs(child, "FPSIMD", &iov_parent, &iov_child);261 262 if (sve_supported() || sme_supported()) {263 iov_parent.iov_base = &sve_vl_out;264 iov_parent.iov_len = sizeof(sve_vl_out);265 iov_child.iov_base = &sve_vl_out;266 iov_child.iov_len = sizeof(sve_vl_out);267 read_one_child_regs(child, "SVE VL", &iov_parent, &iov_child);268 269 iov_parent.iov_base = &z_out;270 iov_parent.iov_len = sizeof(z_out);271 iov_child.iov_base = &z_out;272 iov_child.iov_len = sizeof(z_out);273 read_one_child_regs(child, "Z", &iov_parent, &iov_child);274 275 iov_parent.iov_base = &p_out;276 iov_parent.iov_len = sizeof(p_out);277 iov_child.iov_base = &p_out;278 iov_child.iov_len = sizeof(p_out);279 read_one_child_regs(child, "P", &iov_parent, &iov_child);280 281 iov_parent.iov_base = &ffr_out;282 iov_parent.iov_len = sizeof(ffr_out);283 iov_child.iov_base = &ffr_out;284 iov_child.iov_len = sizeof(ffr_out);285 read_one_child_regs(child, "FFR", &iov_parent, &iov_child);286 }287 288 if (sme_supported()) {289 iov_parent.iov_base = &sme_vl_out;290 iov_parent.iov_len = sizeof(sme_vl_out);291 iov_child.iov_base = &sme_vl_out;292 iov_child.iov_len = sizeof(sme_vl_out);293 read_one_child_regs(child, "SME VL", &iov_parent, &iov_child);294 295 iov_parent.iov_base = &svcr_out;296 iov_parent.iov_len = sizeof(svcr_out);297 iov_child.iov_base = &svcr_out;298 iov_child.iov_len = sizeof(svcr_out);299 read_one_child_regs(child, "SVCR", &iov_parent, &iov_child);300 301 iov_parent.iov_base = &za_out;302 iov_parent.iov_len = sizeof(za_out);303 iov_child.iov_base = &za_out;304 iov_child.iov_len = sizeof(za_out);305 read_one_child_regs(child, "ZA", &iov_parent, &iov_child);306 }307 308 if (sme2_supported()) {309 iov_parent.iov_base = &zt_out;310 iov_parent.iov_len = sizeof(zt_out);311 iov_child.iov_base = &zt_out;312 iov_child.iov_len = sizeof(zt_out);313 read_one_child_regs(child, "ZT", &iov_parent, &iov_child);314 }315}316 317static bool continue_breakpoint(pid_t child,318 enum __ptrace_request restart_type)319{320 struct user_pt_regs pt_regs;321 struct iovec iov;322 int ret;323 324 /* Get PC */325 iov.iov_base = &pt_regs;326 iov.iov_len = sizeof(pt_regs);327 ret = ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &iov);328 if (ret < 0) {329 ksft_print_msg("Failed to get PC: %s (%d)\n",330 strerror(errno), errno);331 return false;332 }333 334 /* Skip over the BRK */335 pt_regs.pc += 4;336 ret = ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, &iov);337 if (ret < 0) {338 ksft_print_msg("Failed to skip BRK: %s (%d)\n",339 strerror(errno), errno);340 return false;341 }342 343 /* Restart */344 ret = ptrace(restart_type, child, 0, 0);345 if (ret < 0) {346 ksft_print_msg("Failed to restart child: %s (%d)\n",347 strerror(errno), errno);348 return false;349 }350 351 return true;352}353 354static bool check_ptrace_values_sve(pid_t child, struct test_config *config)355{356 struct user_sve_header *sve;357 struct user_fpsimd_state *fpsimd;358 struct iovec iov;359 int ret, vq;360 bool pass = true;361 362 if (!sve_supported())363 return true;364 365 vq = __sve_vq_from_vl(config->sve_vl_in);366 367 iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);368 iov.iov_base = malloc(iov.iov_len);369 if (!iov.iov_base) {370 ksft_print_msg("OOM allocating %lu byte SVE buffer\n",371 iov.iov_len);372 return false;373 }374 375 ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_SVE, &iov);376 if (ret != 0) {377 ksft_print_msg("Failed to read initial SVE: %s (%d)\n",378 strerror(errno), errno);379 pass = false;380 goto out;381 }382 383 sve = iov.iov_base;384 385 if (sve->vl != config->sve_vl_in) {386 ksft_print_msg("Mismatch in initial SVE VL: %d != %d\n",387 sve->vl, config->sve_vl_in);388 pass = false;389 }390 391 /* If we are in streaming mode we should just read FPSIMD */392 if ((config->svcr_in & SVCR_SM) && (sve->flags & SVE_PT_REGS_SVE)) {393 ksft_print_msg("NT_ARM_SVE reports SVE with PSTATE.SM\n");394 pass = false;395 }396 397 if (sve->size != SVE_PT_SIZE(vq, sve->flags)) {398 ksft_print_msg("Mismatch in SVE header size: %d != %lu\n",399 sve->size, SVE_PT_SIZE(vq, sve->flags));400 pass = false;401 }402 403 /* The registers might be in completely different formats! */404 if (sve->flags & SVE_PT_REGS_SVE) {405 if (!compare_buffer("initial SVE Z",406 iov.iov_base + SVE_PT_SVE_ZREG_OFFSET(vq, 0),407 z_in, SVE_PT_SVE_ZREGS_SIZE(vq)))408 pass = false;409 410 if (!compare_buffer("initial SVE P",411 iov.iov_base + SVE_PT_SVE_PREG_OFFSET(vq, 0),412 p_in, SVE_PT_SVE_PREGS_SIZE(vq)))413 pass = false;414 415 if (!compare_buffer("initial SVE FFR",416 iov.iov_base + SVE_PT_SVE_FFR_OFFSET(vq),417 ffr_in, SVE_PT_SVE_PREG_SIZE(vq)))418 pass = false;419 } else {420 fpsimd = iov.iov_base + SVE_PT_FPSIMD_OFFSET;421 if (!compare_buffer("initial V via SVE", &fpsimd->vregs[0],422 v_in, sizeof(v_in)))423 pass = false;424 }425 426out:427 free(iov.iov_base);428 return pass;429}430 431static bool check_ptrace_values_ssve(pid_t child, struct test_config *config)432{433 struct user_sve_header *sve;434 struct user_fpsimd_state *fpsimd;435 struct iovec iov;436 int ret, vq;437 bool pass = true;438 439 if (!sme_supported())440 return true;441 442 vq = __sve_vq_from_vl(config->sme_vl_in);443 444 iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);445 iov.iov_base = malloc(iov.iov_len);446 if (!iov.iov_base) {447 ksft_print_msg("OOM allocating %lu byte SSVE buffer\n",448 iov.iov_len);449 return false;450 }451 452 ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_SSVE, &iov);453 if (ret != 0) {454 ksft_print_msg("Failed to read initial SSVE: %s (%d)\n",455 strerror(errno), errno);456 pass = false;457 goto out;458 }459 460 sve = iov.iov_base;461 462 if (sve->vl != config->sme_vl_in) {463 ksft_print_msg("Mismatch in initial SSVE VL: %d != %d\n",464 sve->vl, config->sme_vl_in);465 pass = false;466 }467 468 if ((config->svcr_in & SVCR_SM) && !(sve->flags & SVE_PT_REGS_SVE)) {469 ksft_print_msg("NT_ARM_SSVE reports FPSIMD with PSTATE.SM\n");470 pass = false;471 }472 473 if (sve->size != SVE_PT_SIZE(vq, sve->flags)) {474 ksft_print_msg("Mismatch in SSVE header size: %d != %lu\n",475 sve->size, SVE_PT_SIZE(vq, sve->flags));476 pass = false;477 }478 479 /* The registers might be in completely different formats! */480 if (sve->flags & SVE_PT_REGS_SVE) {481 if (!compare_buffer("initial SSVE Z",482 iov.iov_base + SVE_PT_SVE_ZREG_OFFSET(vq, 0),483 z_in, SVE_PT_SVE_ZREGS_SIZE(vq)))484 pass = false;485 486 if (!compare_buffer("initial SSVE P",487 iov.iov_base + SVE_PT_SVE_PREG_OFFSET(vq, 0),488 p_in, SVE_PT_SVE_PREGS_SIZE(vq)))489 pass = false;490 491 if (!compare_buffer("initial SSVE FFR",492 iov.iov_base + SVE_PT_SVE_FFR_OFFSET(vq),493 ffr_in, SVE_PT_SVE_PREG_SIZE(vq)))494 pass = false;495 } else {496 fpsimd = iov.iov_base + SVE_PT_FPSIMD_OFFSET;497 if (!compare_buffer("initial V via SSVE",498 &fpsimd->vregs[0], v_in, sizeof(v_in)))499 pass = false;500 }501 502out:503 free(iov.iov_base);504 return pass;505}506 507static bool check_ptrace_values_za(pid_t child, struct test_config *config)508{509 struct user_za_header *za;510 struct iovec iov;511 int ret, vq;512 bool pass = true;513 514 if (!sme_supported())515 return true;516 517 vq = __sve_vq_from_vl(config->sme_vl_in);518 519 iov.iov_len = ZA_SIG_CONTEXT_SIZE(vq);520 iov.iov_base = malloc(iov.iov_len);521 if (!iov.iov_base) {522 ksft_print_msg("OOM allocating %lu byte ZA buffer\n",523 iov.iov_len);524 return false;525 }526 527 ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_ZA, &iov);528 if (ret != 0) {529 ksft_print_msg("Failed to read initial ZA: %s (%d)\n",530 strerror(errno), errno);531 pass = false;532 goto out;533 }534 535 za = iov.iov_base;536 537 if (za->vl != config->sme_vl_in) {538 ksft_print_msg("Mismatch in initial SME VL: %d != %d\n",539 za->vl, config->sme_vl_in);540 pass = false;541 }542 543 /* If PSTATE.ZA is not set we should just read the header */544 if (config->svcr_in & SVCR_ZA) {545 if (za->size != ZA_PT_SIZE(vq)) {546 ksft_print_msg("Unexpected ZA ptrace read size: %d != %lu\n",547 za->size, ZA_PT_SIZE(vq));548 pass = false;549 }550 551 if (!compare_buffer("initial ZA",552 iov.iov_base + ZA_PT_ZA_OFFSET,553 za_in, ZA_PT_ZA_SIZE(vq)))554 pass = false;555 } else {556 if (za->size != sizeof(*za)) {557 ksft_print_msg("Unexpected ZA ptrace read size: %d != %lu\n",558 za->size, sizeof(*za));559 pass = false;560 }561 }562 563out:564 free(iov.iov_base);565 return pass;566}567 568static bool check_ptrace_values_zt(pid_t child, struct test_config *config)569{570 uint8_t buf[512];571 struct iovec iov;572 int ret;573 574 if (!sme2_supported())575 return true;576 577 iov.iov_base = &buf;578 iov.iov_len = ZT_SIG_REG_BYTES;579 ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_ZT, &iov);580 if (ret != 0) {581 ksft_print_msg("Failed to read initial ZT: %s (%d)\n",582 strerror(errno), errno);583 return false;584 }585 586 return compare_buffer("initial ZT", buf, zt_in, ZT_SIG_REG_BYTES);587}588 589 590static bool check_ptrace_values(pid_t child, struct test_config *config)591{592 bool pass = true;593 struct user_fpsimd_state fpsimd;594 struct iovec iov;595 int ret;596 597 iov.iov_base = &fpsimd;598 iov.iov_len = sizeof(fpsimd);599 ret = ptrace(PTRACE_GETREGSET, child, NT_PRFPREG, &iov);600 if (ret == 0) {601 if (!compare_buffer("initial V", &fpsimd.vregs, v_in,602 sizeof(v_in))) {603 pass = false;604 }605 } else {606 ksft_print_msg("Failed to read initial V: %s (%d)\n",607 strerror(errno), errno);608 pass = false;609 }610 611 if (!check_ptrace_values_sve(child, config))612 pass = false;613 614 if (!check_ptrace_values_ssve(child, config))615 pass = false;616 617 if (!check_ptrace_values_za(child, config))618 pass = false;619 620 if (!check_ptrace_values_zt(child, config))621 pass = false;622 623 return pass;624}625 626static bool run_parent(pid_t child, struct test_definition *test,627 struct test_config *config)628{629 int wait_status, ret;630 pid_t pid;631 bool pass;632 633 /* Initial attach */634 while (1) {635 pid = waitpid(child, &wait_status, 0);636 if (pid < 0) {637 if (errno == EINTR)638 continue;639 ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",640 strerror(errno), errno);641 }642 643 if (pid == child)644 break;645 }646 647 if (WIFEXITED(wait_status)) {648 ksft_print_msg("Child exited loading values with status %d\n",649 WEXITSTATUS(wait_status));650 pass = false;651 goto out;652 }653 654 if (WIFSIGNALED(wait_status)) {655 ksft_print_msg("Child died from signal %d loading values\n",656 WTERMSIG(wait_status));657 pass = false;658 goto out;659 }660 661 /* Read initial values via ptrace */662 pass = check_ptrace_values(child, config);663 664 /* Do whatever writes we want to do */665 if (test->modify_values)666 test->modify_values(child, config);667 668 if (!continue_breakpoint(child, PTRACE_CONT))669 goto cleanup;670 671 while (1) {672 pid = waitpid(child, &wait_status, 0);673 if (pid < 0) {674 if (errno == EINTR)675 continue;676 ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",677 strerror(errno), errno);678 }679 680 if (pid == child)681 break;682 }683 684 if (WIFEXITED(wait_status)) {685 ksft_print_msg("Child exited saving values with status %d\n",686 WEXITSTATUS(wait_status));687 pass = false;688 goto out;689 }690 691 if (WIFSIGNALED(wait_status)) {692 ksft_print_msg("Child died from signal %d saving values\n",693 WTERMSIG(wait_status));694 pass = false;695 goto out;696 }697 698 /* See what happened as a result */699 read_child_regs(child);700 701 if (!continue_breakpoint(child, PTRACE_DETACH))702 goto cleanup;703 704 /* The child should exit cleanly */705 got_alarm = false;706 alarm(1);707 while (1) {708 if (got_alarm) {709 ksft_print_msg("Wait for child timed out\n");710 goto cleanup;711 }712 713 pid = waitpid(child, &wait_status, 0);714 if (pid < 0) {715 if (errno == EINTR)716 continue;717 ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",718 strerror(errno), errno);719 }720 721 if (pid == child)722 break;723 }724 alarm(0);725 726 if (got_alarm) {727 ksft_print_msg("Timed out waiting for child\n");728 pass = false;729 goto cleanup;730 }731 732 if (pid == child && WIFSIGNALED(wait_status)) {733 ksft_print_msg("Child died from signal %d cleaning up\n",734 WTERMSIG(wait_status));735 pass = false;736 goto out;737 }738 739 if (pid == child && WIFEXITED(wait_status)) {740 if (WEXITSTATUS(wait_status) != 0) {741 ksft_print_msg("Child exited with error %d\n",742 WEXITSTATUS(wait_status));743 pass = false;744 }745 } else {746 ksft_print_msg("Child did not exit cleanly\n");747 pass = false;748 goto cleanup;749 }750 751 goto out;752 753cleanup:754 ret = kill(child, SIGKILL);755 if (ret != 0) {756 ksft_print_msg("kill() failed: %s (%d)\n",757 strerror(errno), errno);758 return false;759 }760 761 while (1) {762 pid = waitpid(child, &wait_status, 0);763 if (pid < 0) {764 if (errno == EINTR)765 continue;766 ksft_exit_fail_msg("waitpid() failed: %s (%d)\n",767 strerror(errno), errno);768 }769 770 if (pid == child)771 break;772 }773 774out:775 return pass;776}777 778static void fill_random(void *buf, size_t size)779{780 int i;781 uint32_t *lbuf = buf;782 783 /* random() returns a 32 bit number regardless of the size of long */784 for (i = 0; i < size / sizeof(uint32_t); i++)785 lbuf[i] = random();786}787 788static void fill_random_ffr(void *buf, size_t vq)789{790 uint8_t *lbuf = buf;791 int bits, i;792 793 /*794 * Only values with a continuous set of 0..n bits set are795 * valid for FFR, set all bits then clear a random number of796 * high bits.797 */798 memset(buf, 0, __SVE_FFR_SIZE(vq));799 800 bits = random() % (__SVE_FFR_SIZE(vq) * 8);801 for (i = 0; i < bits / 8; i++)802 lbuf[i] = 0xff;803 if (bits / 8 != __SVE_FFR_SIZE(vq))804 lbuf[i] = (1 << (bits % 8)) - 1;805}806 807static void fpsimd_to_sve(__uint128_t *v, char *z, int vl)808{809 int vq = __sve_vq_from_vl(vl);810 int i;811 __uint128_t *p;812 813 if (!vl)814 return;815 816 for (i = 0; i < __SVE_NUM_ZREGS; i++) {817 p = (__uint128_t *)&z[__SVE_ZREG_OFFSET(vq, i)];818 *p = arm64_cpu_to_le128(v[i]);819 }820}821 822static void set_initial_values(struct test_config *config)823{824 int vq = __sve_vq_from_vl(vl_in(config));825 int sme_vq = __sve_vq_from_vl(config->sme_vl_in);826 827 svcr_in = config->svcr_in;828 svcr_expected = config->svcr_expected;829 svcr_out = 0;830 831 fill_random(&v_in, sizeof(v_in));832 memcpy(v_expected, v_in, sizeof(v_in));833 memset(v_out, 0, sizeof(v_out));834 835 /* Changes will be handled in the test case */836 if (sve_supported() || (config->svcr_in & SVCR_SM)) {837 /* The low 128 bits of Z are shared with the V registers */838 fill_random(&z_in, __SVE_ZREGS_SIZE(vq));839 fpsimd_to_sve(v_in, z_in, vl_in(config));840 memcpy(z_expected, z_in, __SVE_ZREGS_SIZE(vq));841 memset(z_out, 0, sizeof(z_out));842 843 fill_random(&p_in, __SVE_PREGS_SIZE(vq));844 memcpy(p_expected, p_in, __SVE_PREGS_SIZE(vq));845 memset(p_out, 0, sizeof(p_out));846 847 if ((config->svcr_in & SVCR_SM) && !fa64_supported())848 memset(ffr_in, 0, __SVE_PREG_SIZE(vq));849 else850 fill_random_ffr(&ffr_in, vq);851 memcpy(ffr_expected, ffr_in, __SVE_PREG_SIZE(vq));852 memset(ffr_out, 0, __SVE_PREG_SIZE(vq));853 }854 855 if (config->svcr_in & SVCR_ZA)856 fill_random(za_in, ZA_SIG_REGS_SIZE(sme_vq));857 else858 memset(za_in, 0, ZA_SIG_REGS_SIZE(sme_vq));859 if (config->svcr_expected & SVCR_ZA)860 memcpy(za_expected, za_in, ZA_SIG_REGS_SIZE(sme_vq));861 else862 memset(za_expected, 0, ZA_SIG_REGS_SIZE(sme_vq));863 if (sme_supported())864 memset(za_out, 0, sizeof(za_out));865 866 if (sme2_supported()) {867 if (config->svcr_in & SVCR_ZA)868 fill_random(zt_in, ZT_SIG_REG_BYTES);869 else870 memset(zt_in, 0, ZT_SIG_REG_BYTES);871 if (config->svcr_expected & SVCR_ZA)872 memcpy(zt_expected, zt_in, ZT_SIG_REG_BYTES);873 else874 memset(zt_expected, 0, ZT_SIG_REG_BYTES);875 memset(zt_out, 0, sizeof(zt_out));876 }877}878 879static bool check_memory_values(struct test_config *config)880{881 bool pass = true;882 int vq, sme_vq;883 884 if (!compare_buffer("saved V", v_out, v_expected, sizeof(v_out)))885 pass = false;886 887 vq = __sve_vq_from_vl(vl_expected(config));888 sme_vq = __sve_vq_from_vl(config->sme_vl_expected);889 890 if (svcr_out != svcr_expected) {891 ksft_print_msg("Mismatch in saved SVCR %lx != %lx\n",892 svcr_out, svcr_expected);893 pass = false;894 }895 896 if (sve_vl_out != config->sve_vl_expected) {897 ksft_print_msg("Mismatch in SVE VL: %ld != %d\n",898 sve_vl_out, config->sve_vl_expected);899 pass = false;900 }901 902 if (sme_vl_out != config->sme_vl_expected) {903 ksft_print_msg("Mismatch in SME VL: %ld != %d\n",904 sme_vl_out, config->sme_vl_expected);905 pass = false;906 }907 908 if (!compare_buffer("saved Z", z_out, z_expected,909 __SVE_ZREGS_SIZE(vq)))910 pass = false;911 912 if (!compare_buffer("saved P", p_out, p_expected,913 __SVE_PREGS_SIZE(vq)))914 pass = false;915 916 if (!compare_buffer("saved FFR", ffr_out, ffr_expected,917 __SVE_PREG_SIZE(vq)))918 pass = false;919 920 if (!compare_buffer("saved ZA", za_out, za_expected,921 ZA_PT_ZA_SIZE(sme_vq)))922 pass = false;923 924 if (!compare_buffer("saved ZT", zt_out, zt_expected, ZT_SIG_REG_BYTES))925 pass = false;926 927 return pass;928}929 930static bool sve_sme_same(struct test_config *config)931{932 if (config->sve_vl_in != config->sve_vl_expected)933 return false;934 935 if (config->sme_vl_in != config->sme_vl_expected)936 return false;937 938 if (config->svcr_in != config->svcr_expected)939 return false;940 941 return true;942}943 944static bool sve_write_supported(struct test_config *config)945{946 if (!sve_supported() && !sme_supported())947 return false;948 949 if ((config->svcr_in & SVCR_ZA) != (config->svcr_expected & SVCR_ZA))950 return false;951 952 if (config->svcr_expected & SVCR_SM) {953 if (config->sve_vl_in != config->sve_vl_expected) {954 return false;955 }956 957 /* Changing the SME VL disables ZA */958 if ((config->svcr_expected & SVCR_ZA) &&959 (config->sme_vl_in != config->sme_vl_expected)) {960 return false;961 }962 } else {963 if (config->sme_vl_in != config->sme_vl_expected) {964 return false;965 }966 }967 968 return true;969}970 971static void fpsimd_write_expected(struct test_config *config)972{973 int vl;974 975 fill_random(&v_expected, sizeof(v_expected));976 977 /* The SVE registers are flushed by a FPSIMD write */978 vl = vl_expected(config);979 980 memset(z_expected, 0, __SVE_ZREGS_SIZE(__sve_vq_from_vl(vl)));981 memset(p_expected, 0, __SVE_PREGS_SIZE(__sve_vq_from_vl(vl)));982 memset(ffr_expected, 0, __SVE_PREG_SIZE(__sve_vq_from_vl(vl)));983 984 fpsimd_to_sve(v_expected, z_expected, vl);985}986 987static void fpsimd_write(pid_t child, struct test_config *test_config)988{989 struct user_fpsimd_state fpsimd;990 struct iovec iov;991 int ret;992 993 memset(&fpsimd, 0, sizeof(fpsimd));994 memcpy(&fpsimd.vregs, v_expected, sizeof(v_expected));995 996 iov.iov_base = &fpsimd;997 iov.iov_len = sizeof(fpsimd);998 ret = ptrace(PTRACE_SETREGSET, child, NT_PRFPREG, &iov);999 if (ret == -1)1000 ksft_print_msg("FPSIMD set failed: (%s) %d\n",1001 strerror(errno), errno);1002}1003 1004static void sve_write_expected(struct test_config *config)1005{1006 int vl = vl_expected(config);1007 int sme_vq = __sve_vq_from_vl(config->sme_vl_expected);1008 1009 fill_random(z_expected, __SVE_ZREGS_SIZE(__sve_vq_from_vl(vl)));1010 fill_random(p_expected, __SVE_PREGS_SIZE(__sve_vq_from_vl(vl)));1011 1012 if ((svcr_expected & SVCR_SM) && !fa64_supported())1013 memset(ffr_expected, 0, __SVE_PREG_SIZE(sme_vq));1014 else1015 fill_random_ffr(ffr_expected, __sve_vq_from_vl(vl));1016 1017 /* Share the low bits of Z with V */1018 fill_random(&v_expected, sizeof(v_expected));1019 fpsimd_to_sve(v_expected, z_expected, vl);1020 1021 if (config->sme_vl_in != config->sme_vl_expected) {1022 memset(za_expected, 0, ZA_PT_ZA_SIZE(sme_vq));1023 memset(zt_expected, 0, sizeof(zt_expected));1024 }1025}1026 1027static void sve_write(pid_t child, struct test_config *config)1028{1029 struct user_sve_header *sve;1030 struct iovec iov;1031 int ret, vl, vq, regset;1032 1033 vl = vl_expected(config);1034 vq = __sve_vq_from_vl(vl);1035 1036 iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);1037 iov.iov_base = malloc(iov.iov_len);1038 if (!iov.iov_base) {1039 ksft_print_msg("Failed allocating %lu byte SVE write buffer\n",1040 iov.iov_len);1041 return;1042 }1043 memset(iov.iov_base, 0, iov.iov_len);1044 1045 sve = iov.iov_base;1046 sve->size = iov.iov_len;1047 sve->flags = SVE_PT_REGS_SVE;1048 sve->vl = vl;1049 1050 memcpy(iov.iov_base + SVE_PT_SVE_ZREG_OFFSET(vq, 0),1051 z_expected, SVE_PT_SVE_ZREGS_SIZE(vq));1052 memcpy(iov.iov_base + SVE_PT_SVE_PREG_OFFSET(vq, 0),1053 p_expected, SVE_PT_SVE_PREGS_SIZE(vq));1054 memcpy(iov.iov_base + SVE_PT_SVE_FFR_OFFSET(vq),1055 ffr_expected, SVE_PT_SVE_PREG_SIZE(vq));1056 1057 if (svcr_expected & SVCR_SM)1058 regset = NT_ARM_SSVE;1059 else1060 regset = NT_ARM_SVE;1061 1062 ret = ptrace(PTRACE_SETREGSET, child, regset, &iov);1063 if (ret != 0)1064 ksft_print_msg("Failed to write SVE: %s (%d)\n",1065 strerror(errno), errno);1066 1067 free(iov.iov_base);1068}1069 1070static bool za_write_supported(struct test_config *config)1071{1072 if (config->svcr_expected & SVCR_SM) {1073 if (!(config->svcr_in & SVCR_SM))1074 return false;1075 1076 /* Changing the SME VL exits streaming mode */1077 if (config->sme_vl_in != config->sme_vl_expected) {1078 return false;1079 }1080 }1081 1082 /* Can't disable SM outside a VL change */1083 if ((config->svcr_in & SVCR_SM) &&1084 !(config->svcr_expected & SVCR_SM))1085 return false;1086 1087 return true;1088}1089 1090static void za_write_expected(struct test_config *config)1091{1092 int sme_vq, sve_vq;1093 1094 sme_vq = __sve_vq_from_vl(config->sme_vl_expected);1095 1096 if (config->svcr_expected & SVCR_ZA) {1097 fill_random(za_expected, ZA_PT_ZA_SIZE(sme_vq));1098 } else {1099 memset(za_expected, 0, ZA_PT_ZA_SIZE(sme_vq));1100 memset(zt_expected, 0, sizeof(zt_expected));1101 }1102 1103 /* Changing the SME VL flushes ZT, SVE state and exits SM */1104 if (config->sme_vl_in != config->sme_vl_expected) {1105 svcr_expected &= ~SVCR_SM;1106 1107 sve_vq = __sve_vq_from_vl(vl_expected(config));1108 memset(z_expected, 0, __SVE_ZREGS_SIZE(sve_vq));1109 memset(p_expected, 0, __SVE_PREGS_SIZE(sve_vq));1110 memset(ffr_expected, 0, __SVE_PREG_SIZE(sve_vq));1111 memset(zt_expected, 0, sizeof(zt_expected));1112 1113 fpsimd_to_sve(v_expected, z_expected, vl_expected(config));1114 }1115}1116 1117static void za_write(pid_t child, struct test_config *config)1118{1119 struct user_za_header *za;1120 struct iovec iov;1121 int ret, vq;1122 1123 vq = __sve_vq_from_vl(config->sme_vl_expected);1124 1125 if (config->svcr_expected & SVCR_ZA)1126 iov.iov_len = ZA_PT_SIZE(vq);1127 else1128 iov.iov_len = sizeof(*za);1129 iov.iov_base = malloc(iov.iov_len);1130 if (!iov.iov_base) {1131 ksft_print_msg("Failed allocating %lu byte ZA write buffer\n",1132 iov.iov_len);1133 return;1134 }1135 memset(iov.iov_base, 0, iov.iov_len);1136 1137 za = iov.iov_base;1138 za->size = iov.iov_len;1139 za->vl = config->sme_vl_expected;1140 if (config->svcr_expected & SVCR_ZA)1141 memcpy(iov.iov_base + ZA_PT_ZA_OFFSET, za_expected,1142 ZA_PT_ZA_SIZE(vq));1143 1144 ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_ZA, &iov);1145 if (ret != 0)1146 ksft_print_msg("Failed to write ZA: %s (%d)\n",1147 strerror(errno), errno);1148 1149 free(iov.iov_base);1150}1151 1152static bool zt_write_supported(struct test_config *config)1153{1154 if (!sme2_supported())1155 return false;1156 if (config->sme_vl_in != config->sme_vl_expected)1157 return false;1158 if (!(config->svcr_expected & SVCR_ZA))1159 return false;1160 if ((config->svcr_in & SVCR_SM) != (config->svcr_expected & SVCR_SM))1161 return false;1162 1163 return true;1164}1165 1166static void zt_write_expected(struct test_config *config)1167{1168 int sme_vq;1169 1170 sme_vq = __sve_vq_from_vl(config->sme_vl_expected);1171 1172 if (config->svcr_expected & SVCR_ZA) {1173 fill_random(zt_expected, sizeof(zt_expected));1174 } else {1175 memset(za_expected, 0, ZA_PT_ZA_SIZE(sme_vq));1176 memset(zt_expected, 0, sizeof(zt_expected));1177 }1178}1179 1180static void zt_write(pid_t child, struct test_config *config)1181{1182 struct iovec iov;1183 int ret;1184 1185 iov.iov_len = ZT_SIG_REG_BYTES;1186 iov.iov_base = zt_expected;1187 ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_ZT, &iov);1188 if (ret != 0)1189 ksft_print_msg("Failed to write ZT: %s (%d)\n",1190 strerror(errno), errno);1191}1192 1193/* Actually run a test */1194static void run_test(struct test_definition *test, struct test_config *config)1195{1196 pid_t child;1197 char name[1024];1198 bool pass;1199 1200 if (sve_supported() && sme_supported())1201 snprintf(name, sizeof(name), "%s, SVE %d->%d, SME %d/%x->%d/%x",1202 test->name,1203 config->sve_vl_in, config->sve_vl_expected,1204 config->sme_vl_in, config->svcr_in,1205 config->sme_vl_expected, config->svcr_expected);1206 else if (sve_supported())1207 snprintf(name, sizeof(name), "%s, SVE %d->%d", test->name,1208 config->sve_vl_in, config->sve_vl_expected);1209 else if (sme_supported())1210 snprintf(name, sizeof(name), "%s, SME %d/%x->%d/%x",1211 test->name,1212 config->sme_vl_in, config->svcr_in,1213 config->sme_vl_expected, config->svcr_expected);1214 else1215 snprintf(name, sizeof(name), "%s", test->name);1216 1217 if (test->supported && !test->supported(config)) {1218 ksft_test_result_skip("%s\n", name);1219 return;1220 }1221 1222 set_initial_values(config);1223 1224 if (test->set_expected_values)1225 test->set_expected_values(config);1226 1227 child = fork();1228 if (child < 0)1229 ksft_exit_fail_msg("fork() failed: %s (%d)\n",1230 strerror(errno), errno);1231 /* run_child() never returns */1232 if (child == 0)1233 run_child(config);1234 1235 pass = run_parent(child, test, config);1236 if (!check_memory_values(config))1237 pass = false;1238 1239 ksft_test_result(pass, "%s\n", name);1240}1241 1242static void run_tests(struct test_definition defs[], int count,1243 struct test_config *config)1244{1245 int i;1246 1247 for (i = 0; i < count; i++)1248 run_test(&defs[i], config);1249}1250 1251static struct test_definition base_test_defs[] = {1252 {1253 .name = "No writes",1254 .supported = sve_sme_same,1255 },1256 {1257 .name = "FPSIMD write",1258 .supported = sve_sme_same,1259 .set_expected_values = fpsimd_write_expected,1260 .modify_values = fpsimd_write,1261 },1262};1263 1264static struct test_definition sve_test_defs[] = {1265 {1266 .name = "SVE write",1267 .supported = sve_write_supported,1268 .set_expected_values = sve_write_expected,1269 .modify_values = sve_write,1270 },1271};1272 1273static struct test_definition za_test_defs[] = {1274 {1275 .name = "ZA write",1276 .supported = za_write_supported,1277 .set_expected_values = za_write_expected,1278 .modify_values = za_write,1279 },1280};1281 1282static struct test_definition zt_test_defs[] = {1283 {1284 .name = "ZT write",1285 .supported = zt_write_supported,1286 .set_expected_values = zt_write_expected,1287 .modify_values = zt_write,1288 },1289};1290 1291static int sve_vls[MAX_NUM_VLS], sme_vls[MAX_NUM_VLS];1292static int sve_vl_count, sme_vl_count;1293 1294static void probe_vls(const char *name, int vls[], int *vl_count, int set_vl)1295{1296 unsigned int vq;1297 int vl;1298 1299 *vl_count = 0;1300 1301 for (vq = ARCH_VQ_MAX; vq > 0; vq /= 2) {1302 vl = prctl(set_vl, vq * 16);1303 if (vl == -1)1304 ksft_exit_fail_msg("SET_VL failed: %s (%d)\n",1305 strerror(errno), errno);1306 1307 vl &= PR_SVE_VL_LEN_MASK;1308 1309 if (*vl_count && (vl == vls[*vl_count - 1]))1310 break;1311 1312 vq = sve_vq_from_vl(vl);1313 1314 vls[*vl_count] = vl;1315 *vl_count += 1;1316 }1317 1318 if (*vl_count > 2) {1319 /* Just use the minimum and maximum */1320 vls[1] = vls[*vl_count - 1];1321 ksft_print_msg("%d %s VLs, using %d and %d\n",1322 *vl_count, name, vls[0], vls[1]);1323 *vl_count = 2;1324 } else {1325 ksft_print_msg("%d %s VLs\n", *vl_count, name);1326 }1327}1328 1329static struct {1330 int svcr_in, svcr_expected;1331} svcr_combinations[] = {1332 { .svcr_in = 0, .svcr_expected = 0, },1333 { .svcr_in = 0, .svcr_expected = SVCR_SM, },1334 { .svcr_in = 0, .svcr_expected = SVCR_ZA, },1335 /* Can't enable both SM and ZA with a single ptrace write */1336 1337 { .svcr_in = SVCR_SM, .svcr_expected = 0, },1338 { .svcr_in = SVCR_SM, .svcr_expected = SVCR_SM, },1339 { .svcr_in = SVCR_SM, .svcr_expected = SVCR_ZA, },1340 { .svcr_in = SVCR_SM, .svcr_expected = SVCR_SM | SVCR_ZA, },1341 1342 { .svcr_in = SVCR_ZA, .svcr_expected = 0, },1343 { .svcr_in = SVCR_ZA, .svcr_expected = SVCR_SM, },1344 { .svcr_in = SVCR_ZA, .svcr_expected = SVCR_ZA, },1345 { .svcr_in = SVCR_ZA, .svcr_expected = SVCR_SM | SVCR_ZA, },1346 1347 { .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = 0, },1348 { .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = SVCR_SM, },1349 { .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = SVCR_ZA, },1350 { .svcr_in = SVCR_SM | SVCR_ZA, .svcr_expected = SVCR_SM | SVCR_ZA, },1351};1352 1353static void run_sve_tests(void)1354{1355 struct test_config test_config;1356 int i, j;1357 1358 if (!sve_supported())1359 return;1360 1361 test_config.sme_vl_in = sme_vls[0];1362 test_config.sme_vl_expected = sme_vls[0];1363 test_config.svcr_in = 0;1364 test_config.svcr_expected = 0;1365 1366 for (i = 0; i < sve_vl_count; i++) {1367 test_config.sve_vl_in = sve_vls[i];1368 1369 for (j = 0; j < sve_vl_count; j++) {1370 test_config.sve_vl_expected = sve_vls[j];1371 1372 run_tests(base_test_defs,1373 ARRAY_SIZE(base_test_defs),1374 &test_config);1375 if (sve_supported())1376 run_tests(sve_test_defs,1377 ARRAY_SIZE(sve_test_defs),1378 &test_config);1379 }1380 }1381 1382}1383 1384static void run_sme_tests(void)1385{1386 struct test_config test_config;1387 int i, j, k;1388 1389 if (!sme_supported())1390 return;1391 1392 test_config.sve_vl_in = sve_vls[0];1393 test_config.sve_vl_expected = sve_vls[0];1394 1395 /*1396 * Every SME VL/SVCR combination1397 */1398 for (i = 0; i < sme_vl_count; i++) {1399 test_config.sme_vl_in = sme_vls[i];1400 1401 for (j = 0; j < sme_vl_count; j++) {1402 test_config.sme_vl_expected = sme_vls[j];1403 1404 for (k = 0; k < ARRAY_SIZE(svcr_combinations); k++) {1405 test_config.svcr_in = svcr_combinations[k].svcr_in;1406 test_config.svcr_expected = svcr_combinations[k].svcr_expected;1407 1408 run_tests(base_test_defs,1409 ARRAY_SIZE(base_test_defs),1410 &test_config);1411 run_tests(sve_test_defs,1412 ARRAY_SIZE(sve_test_defs),1413 &test_config);1414 run_tests(za_test_defs,1415 ARRAY_SIZE(za_test_defs),1416 &test_config);1417 1418 if (sme2_supported())1419 run_tests(zt_test_defs,1420 ARRAY_SIZE(zt_test_defs),1421 &test_config);1422 }1423 }1424 }1425}1426 1427int main(void)1428{1429 struct test_config test_config;1430 struct sigaction sa;1431 int tests, ret, tmp;1432 1433 srandom(getpid());1434 1435 ksft_print_header();1436 1437 if (sve_supported()) {1438 probe_vls("SVE", sve_vls, &sve_vl_count, PR_SVE_SET_VL);1439 1440 tests = ARRAY_SIZE(base_test_defs) +1441 ARRAY_SIZE(sve_test_defs);1442 tests *= sve_vl_count * sve_vl_count;1443 } else {1444 /* Only run the FPSIMD tests */1445 sve_vl_count = 1;1446 tests = ARRAY_SIZE(base_test_defs);1447 }1448 1449 if (sme_supported()) {1450 probe_vls("SME", sme_vls, &sme_vl_count, PR_SME_SET_VL);1451 1452 tmp = ARRAY_SIZE(base_test_defs) + ARRAY_SIZE(sve_test_defs)1453 + ARRAY_SIZE(za_test_defs);1454 1455 if (sme2_supported())1456 tmp += ARRAY_SIZE(zt_test_defs);1457 1458 tmp *= sme_vl_count * sme_vl_count;1459 tmp *= ARRAY_SIZE(svcr_combinations);1460 tests += tmp;1461 } else {1462 sme_vl_count = 1;1463 }1464 1465 if (sme2_supported())1466 ksft_print_msg("SME2 supported\n");1467 1468 if (fa64_supported())1469 ksft_print_msg("FA64 supported\n");1470 1471 ksft_set_plan(tests);1472 1473 /* Get signal handers ready before we start any children */1474 memset(&sa, 0, sizeof(sa));1475 sa.sa_sigaction = handle_alarm;1476 sa.sa_flags = SA_RESTART | SA_SIGINFO;1477 sigemptyset(&sa.sa_mask);1478 ret = sigaction(SIGALRM, &sa, NULL);1479 if (ret < 0)1480 ksft_print_msg("Failed to install SIGALRM handler: %s (%d)\n",1481 strerror(errno), errno);1482 1483 /*1484 * Run the test set if there is no SVE or SME, with those we1485 * have to pick a VL for each run.1486 */1487 if (!sve_supported()) {1488 test_config.sve_vl_in = 0;1489 test_config.sve_vl_expected = 0;1490 test_config.sme_vl_in = 0;1491 test_config.sme_vl_expected = 0;1492 test_config.svcr_in = 0;1493 test_config.svcr_expected = 0;1494 1495 run_tests(base_test_defs, ARRAY_SIZE(base_test_defs),1496 &test_config);1497 }1498 1499 run_sve_tests();1500 run_sme_tests();1501 1502 ksft_finished();1503}1504