From: Philippe Bergheaud <felix@linux.vnet.ibm.com>
Subject: [14/33] powerpc: Fix kernel thread creation on ABIv2
Git-commit: 7cedd6014bfe353d4b552ed8d54d63f6e06e26ba
Patch-mainline: v3.16-rc1
References: bnc#863764 fate#315275, LTC#103998
X-Patchwork-Id: 333411

Summary: Novell863764 - SLES 12 - Enable POWER LE kernel build with ELFv2
Description: Enable POWER LE kernel build with ELFv2

Upstream-Description:

    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>

Signed-off-by: Philippe Bergheaud <felix@linux.vnet.ibm.com>
Acked-by: Torsten Duwe <duwe@suse.de>
---
 arch/powerpc/kernel/entry_64.S |  4 +++-
 arch/powerpc/kernel/process.c  | 17 +++++------------
 2 files changed, 8 insertions(+), 13 deletions(-)

--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -383,9 +383,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
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -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>
 
@@ -1109,7 +1110,9 @@ int copy_thread(unsigned long clone_flag
 		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;
@@ -1188,17 +1191,7 @@ int copy_thread(unsigned long clone_flag
 	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;
 }
 
