]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kselftest/arm64: Add HWCAP test for FEAT_LS64
authorYicong Yang <yangyicong@hisilicon.com>
Mon, 19 Jan 2026 02:29:28 +0000 (10:29 +0800)
committerWill Deacon <will@kernel.org>
Thu, 22 Jan 2026 13:25:33 +0000 (13:25 +0000)
Add tests for FEAT_LS64. Issue related instructions if feature
presents, no SIGILL should be received. When such instructions
operate on Device memory or non-cacheable memory, we may received
a SIGBUS during the test (w/o FEAT_LS64WB). Just ignore it since
we only tested whether the instruction itself can be issued as
expected on platforms declaring the support of such features.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Oliver Upton <oupton@kernel.org>
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com>
Signed-off-by: Will Deacon <will@kernel.org>
tools/testing/selftests/arm64/abi/hwcap.c

index c41640f18e4ecb3608b19ea54a0104a6ea0b8c7b..9d2df1f3e6bbe0819f2830dfd7091b121400985c 100644 (file)
@@ -11,6 +11,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <linux/auxvec.h>
+#include <linux/compiler.h>
 #include <sys/auxv.h>
 #include <sys/prctl.h>
 #include <asm/hwcap.h>
@@ -595,6 +597,45 @@ static void lrcpc3_sigill(void)
                      : "=r" (data0), "=r" (data1) : "r" (src) :);
 }
 
+static void ignore_signal(int sig, siginfo_t *info, void *context)
+{
+       ucontext_t *uc = context;
+
+       uc->uc_mcontext.pc += 4;
+}
+
+static void ls64_sigill(void)
+{
+       struct sigaction ign, old;
+       char src[64] __aligned(64) = { 1 };
+
+       /*
+        * LS64 requires target memory to be Device/Non-cacheable (if
+        * FEAT_LS64WB not supported) and the completer supports these
+        * instructions, otherwise we'll receive a SIGBUS. Since we are only
+        * testing the ABI here, so just ignore the SIGBUS and see if we can
+        * execute the instructions without receiving a SIGILL. Restore the
+        * handler of SIGBUS after this test.
+        */
+       ign.sa_sigaction = ignore_signal;
+       ign.sa_flags = SA_SIGINFO | SA_RESTART;
+       sigemptyset(&ign.sa_mask);
+       sigaction(SIGBUS, &ign, &old);
+
+       register void *xn asm ("x8") = src;
+       register u64 xt_1 asm ("x0");
+
+       /* LD64B x0, [x8] */
+       asm volatile(".inst 0xf83fd100" : "=r" (xt_1) : "r" (xn)
+                    : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
+
+       /* ST64B x0, [x8] */
+       asm volatile(".inst 0xf83f9100" : : "r" (xt_1), "r" (xn)
+                    : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
+
+       sigaction(SIGBUS, &old, NULL);
+}
+
 static const struct hwcap_data {
        const char *name;
        unsigned long at_hwcap;
@@ -1134,6 +1175,14 @@ static const struct hwcap_data {
                .hwcap_bit = HWCAP3_MTE_STORE_ONLY,
                .cpuinfo = "mtestoreonly",
        },
+       {
+               .name = "LS64",
+               .at_hwcap = AT_HWCAP3,
+               .hwcap_bit = HWCAP3_LS64,
+               .cpuinfo = "ls64",
+               .sigill_fn = ls64_sigill,
+               .sigill_reliable = true,
+       },
 };
 
 typedef void (*sighandler_fn)(int, siginfo_t *, void *);