~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/arm64/fp/fp-ptrace.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2023 ARM Limited.
  4  * Original author: Mark Brown <broonie@kernel.org>
  5  */
  6 
  7 #define _GNU_SOURCE
  8 
  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_SVE
 36 #define NT_ARM_SVE 0x405
 37 #endif
 38 
 39 #ifndef NT_ARM_SSVE
 40 #define NT_ARM_SSVE 0x40b
 41 #endif
 42 
 43 #ifndef NT_ARM_ZA
 44 #define NT_ARM_ZA 0x40c
 45 #endif
 46 
 47 #ifndef NT_ARM_ZT
 48 #define NT_ARM_ZT 0x40d
 49 #endif
 50 
 51 #define ARCH_VQ_MAX 256
 52 
 53 /* VL 128..2048 in powers of 2 */
 54 #define MAX_NUM_VLS 5
 55 
 56 #define NUM_FPR 32
 57 __uint128_t v_in[NUM_FPR];
 58 __uint128_t v_expected[NUM_FPR];
 59 __uint128_t v_out[NUM_FPR];
 60 
 61 char z_in[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];
 62 char z_expected[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];
 63 char z_out[__SVE_ZREGS_SIZE(ARCH_VQ_MAX)];
 64 
 65 char p_in[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];
 66 char p_expected[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];
 67 char p_out[__SVE_PREGS_SIZE(ARCH_VQ_MAX)];
 68 
 69 char ffr_in[__SVE_PREG_SIZE(ARCH_VQ_MAX)];
 70 char ffr_expected[__SVE_PREG_SIZE(ARCH_VQ_MAX)];
 71 char ffr_out[__SVE_PREG_SIZE(ARCH_VQ_MAX)];
 72 
 73 char za_in[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];
 74 char za_expected[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];
 75 char za_out[ZA_SIG_REGS_SIZE(ARCH_VQ_MAX)];
 76 
 77 char zt_in[ZT_SIG_REG_BYTES];
 78 char zt_expected[ZT_SIG_REG_BYTES];
 79 char zt_out[ZT_SIG_REG_BYTES];
 80 
 81 uint64_t sve_vl_out;
 82 uint64_t sme_vl_out;
 83 uint64_t svcr_in, svcr_expected, svcr_out;
 84 
 85 void load_and_save(int sve, int sme, int sme2, int fa64);
 86 
 87 static bool got_alarm;
 88 
 89 static void handle_alarm(int sig, siginfo_t *info, void *context)
 90 {
 91         got_alarm = true;
 92 }
 93 
 94 #ifdef CONFIG_CPU_BIG_ENDIAN
 95 static __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 #else
103 static __uint128_t arm64_cpu_to_le128(__uint128_t x)
104 {
105         return x;
106 }
107 #endif
108 
109 #define arm64_le128_to_cpu(x) arm64_cpu_to_le128(x)
110 
111 static bool sve_supported(void)
112 {
113         return getauxval(AT_HWCAP) & HWCAP_SVE;
114 }
115 
116 static bool sme_supported(void)
117 {
118         return getauxval(AT_HWCAP2) & HWCAP2_SME;
119 }
120 
121 static bool sme2_supported(void)
122 {
123         return getauxval(AT_HWCAP2) & HWCAP2_SME2;
124 }
125 
126 static bool fa64_supported(void)
127 {
128         return getauxval(AT_HWCAP2) & HWCAP2_SME_FA64;
129 }
130 
131 static 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 
158 struct 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 
167 struct 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 
175 static 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         else
182                 vl = config->sve_vl_in;
183 
184         return vl;
185 }
186 
187 static 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         else
194                 vl = config->sve_vl_expected;
195 
196         return vl;
197 }
198 
199 static 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 
233 static 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 
248 static 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 are
254          * 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 
317 static 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 
354 static 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 
426 out:
427         free(iov.iov_base);
428         return pass;
429 }
430 
431 static 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 
502 out:
503         free(iov.iov_base);
504         return pass;
505 }
506 
507 static 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 
563 out:
564         free(iov.iov_base);
565         return pass;
566 }
567 
568 static 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 
590 static 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 
626 static 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 
753 cleanup:
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 
774 out:
775         return pass;
776 }
777 
778 static 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 
788 static 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 are
795          * valid for FFR, set all bits then clear a random number of
796          * 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 
807 static 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 
822 static 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                 else
850                         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         else
858                 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         else
862                 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                 else
870                         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                 else
874                         memset(zt_expected, 0, ZT_SIG_REG_BYTES);
875                 memset(zt_out, 0, sizeof(zt_out));
876         }
877 }
878 
879 static 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 
930 static 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 
944 static 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 
971 static 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 
987 static 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 
1004 static 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         else
1015                 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 
1027 static 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         else
1060                 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 
1070 static 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 
1090 static 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 
1117 static 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         else
1128                 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 
1152 static 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 
1166 static 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 
1180 static 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 */
1194 static 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         else
1215                 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 
1242 static 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 
1251 static 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 
1264 static 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 
1273 static 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 
1282 static 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 
1291 static int sve_vls[MAX_NUM_VLS], sme_vls[MAX_NUM_VLS];
1292 static int sve_vl_count, sme_vl_count;
1293 
1294 static 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 
1329 static 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 
1353 static 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 
1384 static 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 combination
1397          */
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 
1427 int 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 we
1485          * 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php