The unwind user eh_frame implementation works well with GCC and Clang
generated code on s390.  Enable it.

Signed-off-by: Jens Remus <[email protected]>
---
 arch/s390/Kconfig                            |  1 +
 arch/s390/include/asm/unwind_user.h          | 71 ++++++++++++++++++++
 arch/s390/include/asm/unwind_user_eh_frame.h | 24 +++++++
 3 files changed, 96 insertions(+)
 create mode 100644 arch/s390/include/asm/unwind_user.h
 create mode 100644 arch/s390/include/asm/unwind_user_eh_frame.h

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 84404e6778d5..fa229ac92d5a 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -251,6 +251,7 @@ config S390
        select HAVE_SOFTIRQ_ON_OWN_STACK
        select HAVE_STACKPROTECTOR if CC_HAS_STACKPROTECTOR_GLOBAL
        select HAVE_SYSCALL_TRACEPOINTS
+       select HAVE_UNWIND_USER_EH_FRAME
        select HAVE_VIRT_CPU_ACCOUNTING
        select HAVE_VIRT_CPU_ACCOUNTING_IDLE
        select HOTPLUG_SMT
diff --git a/arch/s390/include/asm/unwind_user.h 
b/arch/s390/include/asm/unwind_user.h
new file mode 100644
index 000000000000..41ff0b477626
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_UNWIND_USER_H
+#define _ASM_S390_UNWIND_USER_H
+
+#include <linux/sched/task_stack.h>
+#include <linux/types.h>
+#include <asm/fpu.h>
+
+#ifdef CONFIG_UNWIND_USER
+
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+       return 8;
+}
+
+static inline int unwind_user_get_ra_reg(unsigned long *val)
+{
+       struct pt_regs *regs = task_pt_regs(current);
+       *val = regs->gprs[14];
+       return 0;
+}
+#define unwind_user_get_ra_reg unwind_user_get_ra_reg
+
+static inline unsigned long __s390_dwarf_fpr_to_fpr(unsigned int regnum)
+{
+       unsigned int fpr;
+
+       /*
+        * Convert from s390 DWARF floating-point register number (16..31)
+        * to floating-point register number (0..15): left rotate the least
+        * significant three bits and then return the least significant four
+        * bits.
+        */
+       fpr  = (regnum & 3) << 1;
+       fpr |= (regnum & 4) >> 2;
+       fpr |= (regnum & 8);
+       return fpr;
+}
+
+static inline unsigned long __s390_get_dwarf_fpr(unsigned int regnum)
+{
+       struct fpu *fpu = &current->thread.ufpu;
+
+       save_user_fpu_regs();
+       return fpu->vxrs[__s390_dwarf_fpr_to_fpr(regnum)].high;
+}
+
+static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum)
+{
+       if (regnum <= 15) {
+               /* DWARF register numbers 0..15 */
+               struct pt_regs *regs = task_pt_regs(current);
+               *val = regs->gprs[regnum];
+               return 0;
+       } else if (regnum <= 31) {
+               /* DWARF register numbers 16..31 */
+               *val = __s390_get_dwarf_fpr(regnum);
+               return 0;
+       }
+
+       pr_debug("%s (%d): %s(%u): unsupported register number\n",
+                current->comm, current->pid, __func__, regnum);
+       return -EINVAL;
+}
+#define unwind_user_get_reg unwind_user_get_reg
+
+#endif /* CONFIG_UNWIND_USER */
+
+#include <asm-generic/unwind_user.h>
+
+#endif /* _ASM_S390_UNWIND_USER_H */
diff --git a/arch/s390/include/asm/unwind_user_eh_frame.h 
b/arch/s390/include/asm/unwind_user_eh_frame.h
new file mode 100644
index 000000000000..842d9f7c3d80
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user_eh_frame.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_UNWIND_USER_EH_FRAME_H
+#define _ASM_S390_UNWIND_USER_EH_FRAME_H
+
+#define EH_FRAME_REG_SP        15      /* designated stack pointer register */
+#define EH_FRAME_REG_FP        11      /* "preferred" frame pointer register */
+#define EH_FRAME_REG_RA        14      /* designaged return address register */
+
+/* Instructions must be 2-byte aligned */
+#define EH_FRAME_MAX_CODE_ALIGN 2
+
+/* CFA is defined as SP at call site + 160, so that SP = CFA - 160 */
+#define EH_FRAME_SP_VAL_OFFSET -160
+
+/* SP may be saved on the stack or in a register */
+static inline bool eh_frame_reject_sp_rule(void)
+{
+       return false;
+}
+#define eh_frame_reject_sp_rule eh_frame_reject_sp_rule
+
+#include <asm-generic/unwind_user_eh_frame.h>
+
+#endif /* _ASM_S390_UNWIND_USER_EH_FRAME_H */
-- 
2.53.0


Reply via email to