diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-05-05 20:33:10 +1000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-05-05 20:57:12 +1000 |
commit | f6869e7fe657bd977e72954cd78c5871a6a4f71d (patch) | |
tree | 1e34a4bb36cde4b541d7344599e65b541bb4bee7 /arch/powerpc/include/asm/code-patching.h | |
parent | 5a4e58bc693f04aa650219784e5e339e0db6b902 (diff) | |
parent | cec4b7eaf09d330e94e8e94133d360e6f1855974 (diff) |
Merge remote-tracking branch 'anton/abiv2' into next
This series adds support for building the powerpc 64-bit
LE kernel using the new ABI v2. We already supported
running ABI v2 userspace programs but this adds support
for building the kernel itself using the new ABI.
Diffstat (limited to 'arch/powerpc/include/asm/code-patching.h')
-rw-r--r-- | arch/powerpc/include/asm/code-patching.h | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h index 97e02f985df..37991e154ef 100644 --- a/arch/powerpc/include/asm/code-patching.h +++ b/arch/powerpc/include/asm/code-patching.h @@ -42,15 +42,47 @@ void __patch_exception(int exc, unsigned long addr); } while (0) #endif +#define OP_RT_RA_MASK 0xffff0000UL +#define LIS_R2 0x3c020000UL +#define ADDIS_R2_R12 0x3c4c0000UL +#define ADDI_R2_R2 0x38420000UL + static inline unsigned long ppc_function_entry(void *func) { -#ifdef CONFIG_PPC64 +#if defined(CONFIG_PPC64) +#if defined(_CALL_ELF) && _CALL_ELF == 2 + u32 *insn = func; + + /* + * A PPC64 ABIv2 function may have a local and a global entry + * point. We need to use the local entry point when patching + * functions, 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 (unsigned long)(insn + 2); + else + return (unsigned long)func; +#else /* - * On PPC64 the function pointer actually points to the function's - * descriptor. The first entry in the descriptor is the address - * of the function text. + * On PPC64 ABIv1 the function pointer actually points to the + * function's descriptor. The first entry in the descriptor is the + * address of the function text. */ return ((func_descr_t *)func)->entry; +#endif #else return (unsigned long)func; #endif |