[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