arm64: Test if TPIDR2_EL0 is cleared in signal handlers.
SME requires that TPIDR2_EL0 is set to null before the signal handler
is entered, otherwise things can end up in an inconsistent SME state.
Currently SME is disabled in the kernel as BROKEN. In case anyone
decides to enable it anyway, this adds a test that checks if
TPIDR2_EL0 is null upon entry to the signal handler, and if not,
recommends applying the following patch that fixes the issue:
https://lore.kernel.org/linux-arm-kernel/20250417190113.3778111-1-mark.rutland@arm.com/
Test: bionic-unit-tests --gtest_filter='*.sme_tpidr2_clear'
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3bfa4bce430b2f3344af5082788b301b34ef3ab1)
Merged-In: I3972c2d04d32175259d99e0eac3234a424c78c59
Change-Id: I3972c2d04d32175259d99e0eac3234a424c78c59
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index f8bfcef..27f5c6c 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -16,6 +16,7 @@
#include <errno.h>
#include <signal.h>
+#include <sys/auxv.h>
#include <sys/cdefs.h>
#include <sys/syscall.h>
#include <sys/types.h>
@@ -1070,3 +1071,35 @@
GTEST_SKIP() << "our old glibc doesn't have str2sig";
#endif
}
+
+#if defined(__aarch64__)
+__attribute__((target("arch=armv9+sme"))) __arm_new("za") static void FunctionUsingZA() {
+ raise(SIGUSR1);
+}
+
+TEST(signal, sme_tpidr2_clear) {
+ // When using SME, on entering a signal handler the kernel should clear TPIDR2_EL0, but this was
+ // not always correctly done. This tests checks if the kernel correctly clears it or not.
+ if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
+ GTEST_SKIP() << "SME is not enabled on device.";
+ }
+
+ static uint64_t tpidr2 = 0;
+ struct sigaction handler = {};
+ handler.sa_sigaction = [](int, siginfo_t*, void*) {
+ uint64_t zero = 0;
+ __asm__ __volatile__(".arch_extension sme; mrs %0, TPIDR2_EL0" : "=r"(tpidr2));
+ __asm__ __volatile__(".arch_extension sme; msr TPIDR2_EL0, %0" : : "r"(zero)); // Clear TPIDR2.
+ };
+ handler.sa_flags = SA_SIGINFO;
+
+ ASSERT_EQ(0, sigaction(SIGUSR1, &handler, nullptr));
+
+ FunctionUsingZA();
+
+ ASSERT_EQ(0x0UL, tpidr2)
+ << "Broken kernel! TPIDR2_EL0 was not null in the signal handler! "
+ << "Please make sure the following patch has been applied to the kernel: "
+ << "https://lore.kernel.org/linux-arm-kernel/20250417190113.3778111-1-mark.rutland@arm.com/";
+}
+#endif