[PATCH v6 3/3] aarch64: tests for SME
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Tue Oct 7 16:28:36 GMT 2025
On 06/10/25 08:53, Yury Khrustalev wrote:
> This commit adds tests for the following use cases relevant to handing of
> the SME state:
>
> - fork() and vfork()
> - clone() and clone3()
> - signal handler
>
> While most cases are trivial, the case of clone3() is more complicated since
> the clone3() symbol is not public in Glibc.
>
> To avoid having to check all possible ways clone3() may be called via other
> public functions (e.g. vfork() or pthread_create()), we put together a test
> that links directly with clone3.o. All the existing functions that have calls
> to clone3() may not actually use it, in which case the outcome of such tests
> would be unexpected. Having a direct call to the clone3() symbol in the test
> allows to check precisely what we need to test: that the __arm_za_disable()
> function is indeed called and has the desired effect.
>
> Since we use unusual approach when linking test for the clone3() use case,
> to keep things simple, we actually call __arm_za_disable() provided by the
> libgcc library (since GCC 14) instead of using the internal implementation
> from Glibc itself, but that is OK for the purposes of this test since both
> functions do the same thing while the one from libgcc doesn't have extra
> link-time dependencies undesirable for linking this test.
> ---
> sysdeps/aarch64/Makefile | 10 +++
> sysdeps/aarch64/tst-sme-clone.c | 53 +++++++++++++++
> sysdeps/aarch64/tst-sme-clone3.c | 104 +++++++++++++++++++++++++++++
> sysdeps/aarch64/tst-sme-fork.c | 43 ++++++++++++
> sysdeps/aarch64/tst-sme-helper.h | 7 +-
> sysdeps/aarch64/tst-sme-jmp.c | 7 +-
> sysdeps/aarch64/tst-sme-signal.c | 98 +++++++++++++++++++++++++++
> sysdeps/aarch64/tst-sme-skeleton.c | 101 ++++++++++++++++++++++++++++
> sysdeps/aarch64/tst-sme-vfork.c | 43 ++++++++++++
> sysdeps/aarch64/tst-sme-za-state.c | 71 +-------------------
> 10 files changed, 461 insertions(+), 76 deletions(-)
> create mode 100644 sysdeps/aarch64/tst-sme-clone.c
> create mode 100644 sysdeps/aarch64/tst-sme-clone3.c
> create mode 100644 sysdeps/aarch64/tst-sme-fork.c
> create mode 100644 sysdeps/aarch64/tst-sme-signal.c
> create mode 100644 sysdeps/aarch64/tst-sme-skeleton.c
> create mode 100644 sysdeps/aarch64/tst-sme-vfork.c
>
> diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
> index bb97d31355..e720f4b2f2 100644
> --- a/sysdeps/aarch64/Makefile
> +++ b/sysdeps/aarch64/Makefile
> @@ -79,8 +79,18 @@ sysdep_routines += \
>
> tests += \
> tst-sme-jmp \
> + tst-sme-signal \
> tst-sme-za-state \
> # tests
> +tests-internal += \
> + tst-sme-clone \
> + tst-sme-clone3 \
> + tst-sme-fork \
> + tst-sme-vfork \
> + # tests-internal
> +
> +$(objpfx)tst-sme-clone3: $(objpfx)clone3.o
> +
> endif
>
> ifeq ($(subdir),malloc)
Ok.
> diff --git a/sysdeps/aarch64/tst-sme-clone.c b/sysdeps/aarch64/tst-sme-clone.c
> new file mode 100644
> index 0000000000..7106ec7926
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-sme-clone.c
> @@ -0,0 +1,53 @@
> +/* Test that ZA state of SME is cleared in both parent and child
> + when clone() syscall is used.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include "tst-sme-skeleton.c"
> +
> +#include <support/xsched.h>
> +
> +static int
> +fun (void * const arg)
> +{
> + printf ("in child: %s\n", (const char *)arg);
> + /* Check that ZA state of SME was disabled in child. */
> + check_sme_za_state ("after clone in child", /* Clear. */ true);
> + return 0;
> +}
> +
> +static char __attribute__((aligned(16)))
> +stack[1024 * 1024];
> +
> +static void
> +run (struct blk *ptr)
> +{
> + char *syscall_name = (char *)"clone";
> + printf ("in parent: before %s\n", syscall_name);
> +
> + /* Enabled ZA state so that effect of disabling be observable. */
> + enable_sme_za_state (ptr);
> + check_sme_za_state ("before clone", /* Clear. */ false);
> +
> + pid_t pid = xclone (fun, syscall_name, stack, sizeof (stack),
> + CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD);
> +
> + /* Check that ZA state of SME was disabled in parent. */
> + check_sme_za_state ("after clone in parent", /* Clear. */ true);
> +
> + TEST_VERIFY (xwaitpid (pid, NULL, 0) == pid);
> +}
Ok.
> diff --git a/sysdeps/aarch64/tst-sme-clone3.c b/sysdeps/aarch64/tst-sme-clone3.c
> new file mode 100644
> index 0000000000..598cec77bd
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-sme-clone3.c
> @@ -0,0 +1,104 @@
> +/* Test that ZA state of SME is cleared in both parent and child
> + when clone3() syscall is used.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include "tst-sme-skeleton.c"
> +
> +#include <clone3.h>
> +
> +#include <errno.h>
> +#include <sys/wait.h>
> +#include <support/xsched.h>
> +
> +/* Since clone3 is not a public symbol, we link this test explicitly
> + with clone3.o and have to provide this declaration. */
> +int __clone3 (struct clone_args *cl_args, size_t size,
> + int (*func)(void *arg), void *arg);
> +
> +static int
> +fun (void * const arg)
> +{
> + printf ("in child: %s\n", (const char *)arg);
> + /* Check that ZA state of SME was disabled in child. */
> + check_sme_za_state ("after clone3 in child", /* Clear. */ true);
> + return 0;
> +}
> +
> +static char __attribute__((aligned(16)))
> +stack[1024 * 1024];
> +
> +static void
> +run (struct blk *ptr)
> +{
> + char *syscall_name = (char *)"clone3";
> + struct clone_args args = {
> + .flags = CLONE_VM | CLONE_VFORK,
> + .exit_signal = SIGCHLD,
> + .stack = (uintptr_t) stack,
> + .stack_size = sizeof (stack),
> + };
> + printf ("in parent: before %s\n", syscall_name);
> +
> + /* Enabled ZA state so that effect of disabling be observable. */
> + enable_sme_za_state (ptr);
> + check_sme_za_state ("before clone", /* Clear. */ false);
> +
> + pid_t pid = __clone3 (&args, sizeof (args), fun, syscall_name);
Unfortunately this does not work on all scenarios. With gcc 15.2.1 with
glibc configured with --enable-stack-protector=all I see:
$ make test t=misc/tst-sme-clone3
[...]
syscall error 22 (Invalid argument)
make[2]: Leaving directory '/home/azanella/Projects/glibc/glibc-git/misc'
FAIL: misc/tst-sme-clone3
original exit status 22
svl: 32
in parent: before clone3
[before clone]
svcr = 0000000000000002
tpidr2 = 0000ffffcd36e728
$ strace -f -e clone3 misc/tst-sme-clone3 --direct
svl: 32
in parent: before clone3
[before clone]
svcr = 0000000000000002
tpidr2 = 0000ffffd543a698
clone3(0xffffd543a640, 0) = -1 EINVAL (Invalid argument)
It is because clone3 will call the __libc_arm_za_disable () at
sysdeps/aarch64/tst-sme-clone3.c:100 and it might clobber extra registers:
(gdb) si
__libc_arm_za_disable () at ../sysdeps/aarch64/tst-sme-clone3.c:100
100 {
(gdb) disas
Dump of assembler code for function __libc_arm_za_disable:
=> 0x0000aaaaaaaa27c8 <+0>: sub sp, sp, #0x20
0x0000aaaaaaaa27cc <+4>: adrp x0, 0xaaaaaaabf000
0x0000aaaaaaaa27d0 <+8>: ldr x0, [x0, #3984]
0x0000aaaaaaaa27d4 <+12>: stp x29, x30, [sp, #16]
0x0000aaaaaaaa27d8 <+16>: add x29, sp, #0x10
0x0000aaaaaaaa27dc <+20>: ldr x1, [x0]
0x0000aaaaaaaa27e0 <+24>: str x1, [sp, #8]
0x0000aaaaaaaa27e4 <+28>: mov x1, #0x0 // #0
0x0000aaaaaaaa27e8 <+32>: adrp x0, 0xaaaaaaabf000
0x0000aaaaaaaa27ec <+36>: ldr x0, [x0, #3984]
0x0000aaaaaaaa27f0 <+40>: ldr x2, [sp, #8]
0x0000aaaaaaaa27f4 <+44>: ldr x1, [x0]
0x0000aaaaaaaa27f8 <+48>: subs x2, x2, x1
0x0000aaaaaaaa27fc <+52>: mov x1, #0x0 // #0
0x0000aaaaaaaa2800 <+56>: b.ne 0xaaaaaaaa2810 <__libc_arm_za_disable+72> // b.any
0x0000aaaaaaaa2804 <+60>: ldp x29, x30, [sp, #16]
0x0000aaaaaaaa2808 <+64>: add sp, sp, #0x20
0x0000aaaaaaaa280c <+68>: b 0xaaaaaaaa1f00 <__arm_za_disable@plt>
0x0000aaaaaaaa2810 <+72>: bl 0xaaaaaaaa1dd0 <__stack_chk_fail@plt>
I think it would be better to pull the implementation from glibc itself,
which is the one that we should actually test:
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index e720f4b2f2c..ad29a8d78c5 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -89,7 +89,8 @@ tests-internal += \
tst-sme-vfork \
# tests-internal
-$(objpfx)tst-sme-clone3: $(objpfx)clone3.o
+$(objpfx)tst-sme-clone3: $(objpfx)clone3.o \
+ $(objpfx)__arm_za_disable.o
endif
diff --git a/sysdeps/aarch64/tst-sme-clone3.c b/sysdeps/aarch64/tst-sme-clone3.c
index 598cec77bd1..3ac063cb4f5 100644
--- a/sysdeps/aarch64/tst-sme-clone3.c
+++ b/sysdeps/aarch64/tst-sme-clone3.c
@@ -42,9 +42,15 @@ fun (void * const arg)
static char __attribute__((aligned(16)))
stack[1024 * 1024];
+/* Required by __arm_za_disable.S and provided by statup code as hidden
+ symbol. */
+uint64_t _dl_hwcap2;
+
static void
run (struct blk *ptr)
{
+ _dl_hwcap2 = getauxval (AT_HWCAP2);
+
char *syscall_name = (char *)"clone3";
struct clone_args args = {
.flags = CLONE_VM | CLONE_VFORK,
@@ -89,16 +95,3 @@ void __syscall_error(int code)
fprintf (stderr, "syscall error %d (%s)\n", err, strerror (err));
exit (err);
}
-
-/* Provided by libgcc since GCC 14. */
-extern void __arm_za_disable (void);
-
-/* We don't want to pull all the dependencies of Glibc's implementation
- of __arm_za_disable, so we use symbol from libgcc because it is
- available for this test executable. */
-void __libc_arm_za_disable (void)
-{
-#if defined __GNUC__ && __GNUC__ >= 14
- __arm_za_disable ();
-#endif
-}
> +
> + /* Check that ZA state of SME was disabled in parent. */
> + check_sme_za_state ("after clone in parent", /* Clear. */ true);
> +
> + printf ("%s child pid: %d\n", syscall_name, pid);
> + if (pid == -1)
> + {
> + if (errno == ENOSYS)
> + {
> + puts ("clone3 syscall is not supported");
> + exit (EXIT_UNSUPPORTED);
> + }
> + perror ("clone3");
> + TEST_VERIFY_EXIT (0);
> + }
I think we can assume that HWCAP_SME (Linux 5.19) implies in clone3 (Linux 5.3)
support.
> + if (waitid (P_PID, pid, NULL, WEXITED))
Maybe xwaitpid?
> + {
> + perror ("waitid");
> + TEST_VERIFY_EXIT (0);
> + }
> + printf ("in parent: after %s\n", syscall_name);
> +}
> +
> +/* Workaround to simplify linking with clone3.o. */
> +void __syscall_error(int code)
> +{
> + int err = -code;
> + fprintf (stderr, "syscall error %d (%s)\n", err, strerror (err));
> + exit (err);
This makes all the clone3 error handling superflous.
> +}
> +
> +/* Provided by libgcc since GCC 14. */
> +extern void __arm_za_disable (void);
> +
> +/* We don't want to pull all the dependencies of Glibc's implementation
> + of __arm_za_disable, so we use symbol from libgcc because it is
> + available for this test executable. */
> +void __libc_arm_za_disable (void)
> +{
> +#if defined __GNUC__ && __GNUC__ >= 14
> + __arm_za_disable ();
> +#endif
> +}
> diff --git a/sysdeps/aarch64/tst-sme-fork.c b/sysdeps/aarch64/tst-sme-fork.c
> new file mode 100644
> index 0000000000..b003b08884
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-sme-fork.c
> @@ -0,0 +1,43 @@
> +/* Test that ZA state of SME is cleared in both parent and child
> + when fork() function is used.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include "tst-sme-skeleton.c"
> +
> +static void
> +run (struct blk *blk)
> +{
> + /* Enabled ZA state so that effect of disabling be observable. */
> + enable_sme_za_state (blk);
> + check_sme_za_state ("before fork", /* Clear. */ false);
> + fflush (stdout);
> +
> + pid_t pid = xfork ();
> +
> + if (pid == 0)
> + {
> + /* Check that ZA state of SME was disabled in child. */
> + check_sme_za_state ("after fork in child", /* Clear. */ true);
> + exit (0);
> + }
> +
> + /* Check that ZA state of SME was disabled in parent. */
> + check_sme_za_state ("after fork in parent", /* Clear. */ true);
> +
> + TEST_VERIFY (xwaitpid (pid, NULL, 0) == pid);
> +}
> diff --git a/sysdeps/aarch64/tst-sme-helper.h b/sysdeps/aarch64/tst-sme-helper.h
> index f049416c2b..ab9c503e45 100644
> --- a/sysdeps/aarch64/tst-sme-helper.h
> +++ b/sysdeps/aarch64/tst-sme-helper.h
> @@ -16,9 +16,6 @@
> License along with the GNU C Library; if not, see
> <https://www.gnu.org/licenses/>. */
>
> -/* Streaming SVE vector register size. */
> -static unsigned long svl;
> -
> struct blk {
> void *za_save_buffer;
> uint16_t num_za_save_slices;
> @@ -68,10 +65,10 @@ start_za (void)
>
> /* Load data into ZA byte by byte from p. */
> static void __attribute__ ((noinline))
> -load_za (const void *p)
> +load_za (const void *buf, unsigned long svl)
> {
> register unsigned long x15 asm ("x15") = 0;
> - register unsigned long x16 asm ("x16") = (unsigned long)p;
> + register unsigned long x16 asm ("x16") = (unsigned long)buf;
> register unsigned long x17 asm ("x17") = svl;
>
> asm volatile (
Ok.
> diff --git a/sysdeps/aarch64/tst-sme-jmp.c b/sysdeps/aarch64/tst-sme-jmp.c
> index 103897ad36..b2d21c6e1a 100644
> --- a/sysdeps/aarch64/tst-sme-jmp.c
> +++ b/sysdeps/aarch64/tst-sme-jmp.c
> @@ -29,6 +29,9 @@
>
> #include "tst-sme-helper.h"
>
> +/* Streaming SVE vector register size. */
> +static unsigned long svl;
> +
> static uint8_t *za_orig;
> static uint8_t *za_dump;
> static uint8_t *za_save;
> @@ -82,7 +85,7 @@ longjmp_test (void)
> FAIL_EXIT1 ("svcr != 0: %lu", svcr);
> set_tpidr2 (&blk);
> start_za ();
> - load_za (za_orig);
> + load_za (za_orig, svl);
>
> print_data ("za save space", za_save);
> p = get_tpidr2 ();
> @@ -131,7 +134,7 @@ setcontext_test (void)
> FAIL_EXIT1 ("svcr != 0: %lu", svcr);
> set_tpidr2 (&blk);
> start_za ();
> - load_za (za_orig);
> + load_za (za_orig, svl);
>
> print_data ("za save space", za_save);
> p = get_tpidr2 ();
Ok.
> diff --git a/sysdeps/aarch64/tst-sme-signal.c b/sysdeps/aarch64/tst-sme-signal.c
> new file mode 100644
> index 0000000000..af73f8a89c
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-sme-signal.c
> @@ -0,0 +1,98 @@
> +/* Test handling of SME state in a signal handler.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include "tst-sme-skeleton.c"
> +
> +#include <support/xsignal.h>
> +
> +static struct _aarch64_ctx *
> +extension (void *p)
> +{
> + return p;
> +}
> +
> +#ifndef TPIDR2_MAGIC
> +#define TPIDR2_MAGIC 0x54504902
> +#endif
> +
> +#ifndef ZA_MAGIC
> +#define ZA_MAGIC 0x54366345
> +#endif
> +
> +#ifndef ZT_MAGIC
> +#define ZT_MAGIC 0x5a544e01
> +#endif
> +
> +#ifndef EXTRA_MAGIC
> +#define EXTRA_MAGIC 0x45585401
> +#endif
> +
> +static void
> +handler (int signo, siginfo_t *si, void *ctx)
> +{
> + TEST_VERIFY (signo == SIGUSR1);
> + printf ("in the handler: %d and %p\n", signo, si);
The printf here is not async-signal-safe, but I think it should not matter
for this test.
> + check_sme_za_state ("during signal", true /* State is clear. */);
> + ucontext_t *uc = ctx;
> + void *p = uc->uc_mcontext.__reserved;
> + unsigned int found = 0;
> + uint32_t m;
> + while ((m = extension (p)->magic))
> + {
> + if (m == TPIDR2_MAGIC)
> + {
> + printf ("found TPIDR2_MAGIC\n");
> + found += 1;
> + }
> + if (m == ZA_MAGIC)
> + {
> + printf ("found ZA_MAGIC\n");
> + found += 1;
> + }
> + if (m == ZT_MAGIC)
> + {
> + printf ("found ZT_MAGIC\n");
> + found += 1;
> + }
> + if (m == EXTRA_MAGIC)
> + {
> + printf ("found EXTRA_MAGIC\n");
> + struct { struct _aarch64_ctx h; uint64_t data; } *e = p;
> + p = (char *)e->data;
> + continue;
> + }
> + p = (char *)p + extension (p)->size;
> + }
> + TEST_COMPARE (found, 3);
> +}
> +
> +static void
> +run (struct blk *blk)
> +{
> + struct sigaction sigact;
> + sigemptyset (&sigact.sa_mask);
> + sigact.sa_flags = 0;
> + sigact.sa_flags |= SA_SIGINFO;
> + sigact.sa_sigaction = handler;
> + xsigaction (SIGUSR1, &sigact, NULL);
> +
> + enable_sme_za_state (blk);
> + check_sme_za_state ("before signal", false /* State is not clear. */);
> + xraise (SIGUSR1);
Afaik SIGUSR1 is not a synchronous signal, meaning that the next
check_sme_za_state state is not guarantee to execute *after* the signal handler
is being acted uppon.
The best strategy would do something like:
diff --git a/sysdeps/aarch64/tst-sme-signal.c b/sysdeps/aarch64/tst-sme-signal.c
index af73f8a89c6..a325e38afce 100644
--- a/sysdeps/aarch64/tst-sme-signal.c
+++ b/sysdeps/aarch64/tst-sme-signal.c
@@ -42,6 +42,8 @@ extension (void *p)
#define EXTRA_MAGIC 0x45585401
#endif
+static int pipefd[2];
+
static void
handler (int signo, siginfo_t *si, void *ctx)
{
@@ -79,11 +81,15 @@ handler (int signo, siginfo_t *si, void *ctx)
p = (char *)p + extension (p)->size;
}
TEST_COMPARE (found, 3);
+
+ xwrite (pipefd[1], &(char){}, 1);
}
static void
run (struct blk *blk)
{
+ xpipe (pipefd);
+
struct sigaction sigact;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
@@ -94,5 +100,8 @@ run (struct blk *blk)
enable_sme_za_state (blk);
check_sme_za_state ("before signal", false /* State is not clear. */);
xraise (SIGUSR1);
+
+ xread (pipefd[0], &(char){}, 1);
+
check_sme_za_state ("after signal", false /* State is not clear. */);
}
> + check_sme_za_state ("after signal", false /* State is not clear. */);
> +}
> diff --git a/sysdeps/aarch64/tst-sme-skeleton.c b/sysdeps/aarch64/tst-sme-skeleton.c
> new file mode 100644
> index 0000000000..ba84dda1cb
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-sme-skeleton.c
> @@ -0,0 +1,101 @@
> +/* Template for SME tests.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <stdio.h>
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <sys/auxv.h>
> +
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <support/xstdlib.h>
> +#include <support/xunistd.h>
> +#include <support/test-driver.h>
> +
> +#include "tst-sme-helper.h"
> +
> +/* Streaming SVE vector register size. */
> +static unsigned long svl;
> +
> +static uint8_t *state;
> +
> +static void
> +enable_sme_za_state (struct blk *blk)
> +{
> + start_za ();
> + set_tpidr2 (blk);
> + load_za (blk, svl);
> +}
> +
> +/* Check if SME state is disabled (when CLEAR is true) or
> + enabled (when CLEAR is false). */
> +static void
> +check_sme_za_state (const char msg[], bool clear)
> +{
> + unsigned long svcr = get_svcr ();
> + void *tpidr2 = get_tpidr2 ();
> + printf ("[%s]\n", msg);
> + printf ("svcr = %016lx\n", svcr);
> + printf ("tpidr2 = %016lx\n", (unsigned long)tpidr2);
> + if (clear)
> + {
> + TEST_VERIFY (svcr == 0);
> + TEST_VERIFY (tpidr2 == NULL);
> + }
> + else
> + {
> + TEST_VERIFY (svcr != 0);
> + TEST_VERIFY (tpidr2 != NULL);
> + }
> +}
> +
> +/* Should be defined in actual test that includes this
> + skeleton file. */
> +static void
> +run (struct blk *ptr);
> +
> +static int
> +do_test (void)
> +{
> + unsigned long hwcap2 = getauxval (AT_HWCAP2);
> + if ((hwcap2 & HWCAP2_SME) == 0)
> + return EXIT_UNSUPPORTED;
> +
> + /* Get current streaming SVE vector length in bytes. */
> + svl = get_svl ();
> + printf ("svl: %lu\n", svl);
> +
> + TEST_VERIFY_EXIT (!(svl < 16 || svl % 16 != 0 || svl >= (1 << 16)));
> +
> + /* Initialise buffer for ZA state of SME. */
> + state = xmalloc (svl * svl);
> + memset (state, 1, svl * svl);
> + struct blk blk = {
> + .za_save_buffer = state,
> + .num_za_save_slices = svl,
> + .__reserved = {0},
> + };
> +
> + run (&blk);
> +
> + free (state);
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
Ok.
> diff --git a/sysdeps/aarch64/tst-sme-vfork.c b/sysdeps/aarch64/tst-sme-vfork.c
> new file mode 100644
> index 0000000000..fecbea08be
> --- /dev/null
> +++ b/sysdeps/aarch64/tst-sme-vfork.c
> @@ -0,0 +1,43 @@
> +/* Test that ZA state of SME is cleared in both parent and child
> + when vfork() function is used.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include "tst-sme-skeleton.c"
> +
> +static void
> +run (struct blk *blk)
> +{
> + /* Enabled ZA state so that effect of disabling be observable. */
> + enable_sme_za_state (blk);
> + check_sme_za_state ("before vfork", /* Clear. */ false);
> + fflush (stdout);
> +
> + pid_t pid = vfork ();
> +
> + if (pid == 0)
> + {
> + /* Check that ZA state of SME was disabled in child. */
> + check_sme_za_state ("after vfork in child", /* Clear. */ true);
> + exit (0);
Use _exit. It is undefined calling any other function other than
execve/_exit after vfork; but I think it should not matter on this
test.
> + }
> +
> + /* Check that ZA state of SME was disabled in parent. */
> + check_sme_za_state ("after vfork in parent", /* Clear. */ true);
> +
> + TEST_VERIFY (xwaitpid (pid, NULL, 0) == pid);
> +}
> diff --git a/sysdeps/aarch64/tst-sme-za-state.c b/sysdeps/aarch64/tst-sme-za-state.c
> index 63f6eebeb4..00118ef506 100644
> --- a/sysdeps/aarch64/tst-sme-za-state.c
> +++ b/sysdeps/aarch64/tst-sme-za-state.c
> @@ -16,47 +16,9 @@
> License along with the GNU C Library; if not, see
> <https://www.gnu.org/licenses/>. */
>
> -#include <stdio.h>
> -#include <setjmp.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <sys/auxv.h>
> -
> -#include <support/check.h>
> -#include <support/support.h>
> -#include <support/test-driver.h>
> -
> -#include "tst-sme-helper.h"
> -
> -static uint8_t *state;
> -
> -static void
> -enable_sme_za_state (struct blk *ptr)
> -{
> - set_tpidr2 (ptr);
> - start_za ();
> - load_za (state);
> -}
> +#include "tst-sme-skeleton.c"
>
> -static void
> -check_sme_za_state (const char msg[], bool clear)
> -{
> - unsigned long svcr = get_svcr ();
> - void *tpidr2 = get_tpidr2 ();
> - printf ("[%s]\n", msg);
> - printf ("svcr = %016lx\n", svcr);
> - printf ("tpidr2 = %016lx\n", (unsigned long)tpidr2);
> - if (clear)
> - {
> - TEST_VERIFY (svcr == 0);
> - TEST_VERIFY (tpidr2 == NULL);
> - }
> - else
> - {
> - TEST_VERIFY (svcr != 0);
> - TEST_VERIFY (tpidr2 != NULL);
> - }
> -}
> +#include <setjmp.h>
>
> static void
> run (struct blk *ptr)
> @@ -88,32 +50,3 @@ run (struct blk *ptr)
> TEST_COMPARE (ret, 42);
> check_sme_za_state ("after longjmp", /* Clear. */ true);
> }
> -
> -static int
> -do_test (void)
> -{
> - unsigned long hwcap2 = getauxval (AT_HWCAP2);
> - if ((hwcap2 & HWCAP2_SME) == 0)
> - return EXIT_UNSUPPORTED;
> -
> - /* Get current streaming SVE vector register size. */
> - svl = get_svl ();
> - printf ("svl: %lu\n", svl);
> - TEST_VERIFY_EXIT (!(svl < 16 || svl % 16 != 0 || svl >= (1 << 16)));
> -
> - /* Initialise buffer for ZA state of SME. */
> - state = xmalloc (svl * svl);
> - memset (state, 1, svl * svl);
> - struct blk blk = {
> - .za_save_buffer = state,
> - .num_za_save_slices = svl,
> - .__reserved = {0},
> - };
> -
> - run (&blk);
> -
> - free (state);
> - return 0;
> -}
> -
> -#include <support/test-driver.c>
Ok.
More information about the Libc-alpha
mailing list