| // 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 */ |