aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/include/elf-abi.h
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/include/elf-abi.h')
-rw-r--r--roms/skiboot/include/elf-abi.h54
1 files changed, 54 insertions, 0 deletions
diff --git a/roms/skiboot/include/elf-abi.h b/roms/skiboot/include/elf-abi.h
new file mode 100644
index 000000000..29c757642
--- /dev/null
+++ b/roms/skiboot/include/elf-abi.h
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2017 IBM Corp. */
+
+#ifndef __ELF_ABI_H
+#define __ELF_ABI_H
+
+#ifndef __ASSEMBLY__
+
+#if defined (_CALL_ELF) && _CALL_ELF == 2
+#define ELF_ABI_v2
+#else
+#define ELF_ABI_v1
+#endif
+
+/* From linux/arch/powerpc/include/asm/code-patching.h */
+#define OP_RT_RA_MASK 0xffff0000UL
+#define LIS_R2 0x3c020000UL
+#define ADDIS_R2_R12 0x3c4c0000UL
+#define ADDI_R2_R2 0x38420000UL
+
+static inline uint64_t function_entry_address(void *func)
+{
+#ifdef ELF_ABI_v2
+ u32 *insn = func;
+ /*
+ * A PPC64 ABIv2 function may have a local and a global entry
+ * point. We use the local entry point for branch tables called
+ * from asm, only a single TOC is used, so identify and step over
+ * the global entry point sequence.
+ *
+ * The global entry point sequence is always of the form:
+ *
+ * addis r2,r12,XXXX
+ * addi r2,r2,XXXX
+ *
+ * A linker optimisation may convert the addis to lis:
+ *
+ * lis r2,XXXX
+ * addi r2,r2,XXXX
+ */
+ if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
+ ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
+ ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2))
+ return (uint64_t)(insn + 2);
+ else
+ return (uint64_t)func;
+#else
+ return *(uint64_t *)func;
+#endif
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __COMPILER_H */