diff options
author | Anton Blanchard <anton@samba.org> | 2014-02-04 00:09:15 -0500 |
---|---|---|
committer | Anton Blanchard <anton@samba.org> | 2014-04-22 20:05:21 -0400 |
commit | c71b7eff426fa7d8fd33e0964a7f79a3b41faff9 (patch) | |
tree | 19035b32883d0b554d3b318a80f11f1acc29a485 | |
parent | 814e4cd98f777c7fa3b42e0468030cd341fb8b6b (diff) |
powerpc: Add ABIv2 support to ppc_function_entry
Skip over the well known global entry point code for ABIv2.
Signed-off-by: Anton Blanchard <anton@samba.org>
-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 97e02f985df8..37991e154ef8 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); | |||
42 | } while (0) | 42 | } while (0) |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | #define OP_RT_RA_MASK 0xffff0000UL | ||
46 | #define LIS_R2 0x3c020000UL | ||
47 | #define ADDIS_R2_R12 0x3c4c0000UL | ||
48 | #define ADDI_R2_R2 0x38420000UL | ||
49 | |||
45 | static inline unsigned long ppc_function_entry(void *func) | 50 | static inline unsigned long ppc_function_entry(void *func) |
46 | { | 51 | { |
47 | #ifdef CONFIG_PPC64 | 52 | #if defined(CONFIG_PPC64) |
53 | #if defined(_CALL_ELF) && _CALL_ELF == 2 | ||
54 | u32 *insn = func; | ||
55 | |||
56 | /* | ||
57 | * A PPC64 ABIv2 function may have a local and a global entry | ||
58 | * point. We need to use the local entry point when patching | ||
59 | * functions, so identify and step over the global entry point | ||
60 | * sequence. | ||
61 | * | ||
62 | * The global entry point sequence is always of the form: | ||
63 | * | ||
64 | * addis r2,r12,XXXX | ||
65 | * addi r2,r2,XXXX | ||
66 | * | ||
67 | * A linker optimisation may convert the addis to lis: | ||
68 | * | ||
69 | * lis r2,XXXX | ||
70 | * addi r2,r2,XXXX | ||
71 | */ | ||
72 | if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || | ||
73 | ((*insn & OP_RT_RA_MASK) == LIS_R2)) && | ||
74 | ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2)) | ||
75 | return (unsigned long)(insn + 2); | ||
76 | else | ||
77 | return (unsigned long)func; | ||
78 | #else | ||
48 | /* | 79 | /* |
49 | * On PPC64 the function pointer actually points to the function's | 80 | * On PPC64 ABIv1 the function pointer actually points to the |
50 | * descriptor. The first entry in the descriptor is the address | 81 | * function's descriptor. The first entry in the descriptor is the |
51 | * of the function text. | 82 | * address of the function text. |
52 | */ | 83 | */ |
53 | return ((func_descr_t *)func)->entry; | 84 | return ((func_descr_t *)func)->entry; |
85 | #endif | ||
54 | #else | 86 | #else |
55 | return (unsigned long)func; | 87 | return (unsigned long)func; |
56 | #endif | 88 | #endif |