]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
powerpc: Add ABIv2 support to ppc_function_entry
authorAnton Blanchard <anton@samba.org>
Tue, 4 Feb 2014 05:09:15 +0000 (16:09 +1100)
committerAnton Blanchard <anton@samba.org>
Wed, 23 Apr 2014 00:05:21 +0000 (10:05 +1000)
Skip over the well known global entry point code for ABIv2.

Signed-off-by: Anton Blanchard <anton@samba.org>
arch/powerpc/include/asm/code-patching.h

index 97e02f985df8e47946438ecc1b0ba2f040ee7bf5..37991e154ef88faf50b7b8b447c1772877a253bf 100644 (file)
@@ -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