OSDN Git Service

powerpc: Fix kernel thread creation on ABIv2
authorAnton Blanchard <anton@samba.org>
Tue, 4 Feb 2014 05:08:51 +0000 (16:08 +1100)
committerAnton Blanchard <anton@samba.org>
Wed, 23 Apr 2014 00:05:23 +0000 (10:05 +1000)
Change how we setup registers for ret_from_kernel_thread. In
ABIv1, instead of passing a function descriptor in, dereference
it and pass the target in directly.

Use ppc_global_function_entry to get it right on both ABIv1 and ABIv2.

Signed-off-by: Anton Blanchard <anton@samba.org>
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/process.c

index d23d752..cf4f6e6 100644 (file)
@@ -378,9 +378,11 @@ _GLOBAL(ret_from_fork)
 _GLOBAL(ret_from_kernel_thread)
        bl      schedule_tail
        REST_NVGPRS(r1)
-       ld      r14, 0(r14)
        mtlr    r14
        mr      r3,r15
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+       mr      r12,r14
+#endif
        blrl
        li      r3,0
        b       syscall_exit
index 31d0215..2ae1b99 100644 (file)
@@ -54,6 +54,7 @@
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #endif
+#include <asm/code-patching.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 
@@ -1108,7 +1109,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                struct thread_info *ti = (void *)task_stack_page(p);
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->gpr[1] = sp + sizeof(struct pt_regs);
-               childregs->gpr[14] = usp;       /* function */
+               /* function */
+               if (usp)
+                       childregs->gpr[14] = ppc_function_entry((void *)usp);
 #ifdef CONFIG_PPC64
                clear_tsk_thread_flag(p, TIF_32BIT);
                childregs->softe = 1;
@@ -1187,17 +1190,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        if (cpu_has_feature(CPU_FTR_HAS_PPR))
                p->thread.ppr = INIT_PPR;
 #endif
-       /*
-        * The PPC64 ABI makes use of a TOC to contain function 
-        * pointers.  The function (ret_from_except) is actually a pointer
-        * to the TOC entry.  The first entry is a pointer to the actual
-        * function.
-        */
-#ifdef CONFIG_PPC64
-       kregs->nip = *((unsigned long *)f);
-#else
-       kregs->nip = (unsigned long)f;
-#endif
+       kregs->nip = ppc_function_entry(f);
        return 0;
 }