https://github.com/MacDue created https://github.com/llvm/llvm-project/pull/165451
None >From 30bc4cabc424fb6c451c4dd2c7ddd9c5ed373949 Mon Sep 17 00:00:00 2001 From: Benjamin Maxwell <[email protected]> Date: Tue, 28 Oct 2025 17:23:23 +0000 Subject: [PATCH] [libunwind] Disable ZA before resuming from unwinding (Linux) --- libunwind/src/Registers.hpp | 53 +++++++++++++++++++++-------- libunwind/src/UnwindRegistersSave.S | 47 +++++++++++++++++++++++++ libunwind/src/libunwind.cpp | 1 - 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 5a5b57835379a..e4530d58f9a04 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -20,6 +20,11 @@ #include "libunwind_ext.h" #include "shadow_stack_unwind.h" +#if __has_include(<sys/auxv.h>) +#include <sys/auxv.h> +#define HAVE_SYS_AUXV_H +#endif + namespace libunwind { // For emulating 128-bit registers @@ -1828,6 +1833,7 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) { /// process. class _LIBUNWIND_HIDDEN Registers_arm64; extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +extern "C" bool __libunwind_Registers_arm64_za_disable(); #if defined(_LIBUNWIND_USE_GCS) extern "C" void *__libunwind_shstk_get_jump_target() { @@ -1837,7 +1843,7 @@ extern "C" void *__libunwind_shstk_get_jump_target() { class _LIBUNWIND_HIDDEN Registers_arm64 { public: - Registers_arm64(); + Registers_arm64() = default; Registers_arm64(const void *registers); Registers_arm64(const Registers_arm64 &); Registers_arm64 &operator=(const Registers_arm64 &); @@ -1855,7 +1861,10 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); static const char *getRegisterName(int num); - void jumpto() { __libunwind_Registers_arm64_jumpto(this); } + void jumpto() { + zaDisable(); + __libunwind_Registers_arm64_jumpto(this); + } static constexpr int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } @@ -1908,25 +1917,43 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { private: uint64_t lazyGetVG() const; + void zaDisable() const { + if (!_misc_registers.__has_sme) + return; + if (!__libunwind_Registers_arm64_za_disable()) + _LIBUNWIND_ABORT("SME ZA disable failed"); + } + + static bool checkHasSME() { +#if defined(HAVE_SYS_AUXV_H) + constexpr int hwcap2_sme = (1 << 23); + unsigned long hwcap2 = getauxval(AT_HWCAP2); + return (hwcap2 & hwcap2_sme) != 0; +#endif + // TODO: Support other platforms. + return false; + } + struct GPRs { - uint64_t __x[29]; // x0-x28 - uint64_t __fp; // Frame pointer x29 - uint64_t __lr; // Link register x30 - uint64_t __sp; // Stack pointer x31 - uint64_t __pc; // Program counter - uint64_t __ra_sign_state; // RA sign state register + uint64_t __x[29] = {}; // x0-x28 + uint64_t __fp = 0; // Frame pointer x29 + uint64_t __lr = 0; // Link register x30 + uint64_t __sp = 0; // Stack pointer x31 + uint64_t __pc = 0; // Program counter + uint64_t __ra_sign_state = 0; // RA sign state register }; struct Misc { - mutable uint64_t __vg = 0; // Vector Granule + mutable uint32_t __vg = 0; // Vector Granule + bool __has_sme = checkHasSME(); }; - GPRs _registers; + GPRs _registers = {}; // Currently only the lower double in 128-bit vectore registers // is perserved during unwinding. We could define new register // numbers (> 96) which mean whole vector registers, then this // struct would need to change to contain whole vector registers. - double _vectorHalfRegisters[32]; + double _vectorHalfRegisters[32] = {}; // Miscellaneous/virtual registers. These are stored below the GPRs and FPRs // as they do not correspond to physical registers, so do not need to be @@ -1971,10 +1998,6 @@ Registers_arm64::operator=(const Registers_arm64 &other) { return *this; } -inline Registers_arm64::Registers_arm64() { - memset(static_cast<void *>(this), 0, sizeof(*this)); -} - inline bool Registers_arm64::validRegister(int regNum) const { if (regNum == UNW_REG_IP) return true; diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 619a59751151e..1a19c5fffa3af 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -827,6 +827,53 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) ret #endif +// +// extern "C" bool __libunwind_Registers_arm64_za_disable() +// +// On return: +// success (true/false) is returned in x0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_za_disable) + // If TPIDR2_EL0 is null, the subroutine does nothing. + .inst 0xd53bd0b0 // mrs x16, TPIDR2_EL0 + cbz x16, 1f + + // If any of the reserved bytes in the first 16 bytes of the TPIDR2 block are + // nonzero, return false (libunwind will then abort). + ldrh w14, [x16, #10] + cbnz w14, 2f + ldr w14, [x16, #12] + cbnz w14, 2f + + // If za_save_buffer is NULL, the subroutine does nothing. + ldr x14, [x16] + cbz x14, 1f + + // If num_za_save_slices is zero, the subroutine does nothing. + ldrh w14, [x16, #8] + cbz x14, 1f + + mov x15, xzr + ldr x16, [x16] +0: + .inst 0xe1206200 // str za[w15,0], [x16] + .inst 0x04305830 // addsvl x16, x16, #1 + add x15, x15, #1 + cmp x14, x15 + b.ne 0b + + // * Set TPIDR2_EL0 to null. + .inst 0xd51bd0bf // msr TPIDR2_EL0, xzr + // * Set PSTATE.ZA to 0. + .inst 0xd503447f // smstop za +1: + mov x0, #1 + ret +2: + mov x0, #0 + ret + #elif defined(__arm__) && !defined(__APPLE__) #if !defined(__ARM_ARCH_ISA_ARM) diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index 951d87db868bc..c2384becbd310 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -514,4 +514,3 @@ bool logDWARF() { } #endif // NDEBUG - _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
