diff mbox series

parisc: Fix boot failure of 64-bit kernel

Message ID 20180821123132.GA4250@ls3530.fritz.box (mailing list archive)
State Accepted, archived
Headers show
Series parisc: Fix boot failure of 64-bit kernel | expand

Commit Message

Helge Deller Aug. 21, 2018, 12:31 p.m. UTC
Commit c8921d72e390 ("parisc: Fix and improve kernel stack unwinding")
broke booting of 64-bit kernels. On 64-bit kernels function pointers are
actually function descriptors which require dereferencing. In this patch
we instead declare functions in assembly code which are referenced from
C-code as external data pointers with the ENTRY() macro and thus can use
a simple external reference to the functions.

Signed-off-by: Helge Deller <deller@gmx.de>
Fixes: c8921d72e390 ("parisc: Fix and improve kernel stack unwinding")
diff mbox series

Patch

diff --git a/arch/parisc/include/asm/linkage.h b/arch/parisc/include/asm/linkage.h
index 49f6f3d772cc..cd6fe4febead 100644
--- a/arch/parisc/include/asm/linkage.h
+++ b/arch/parisc/include/asm/linkage.h
@@ -22,15 +22,6 @@ 
 name:		ASM_NL\
 	.export name
 
-#ifdef CONFIG_64BIT
-#define ENDPROC(name) \
-	END(name)
-#else
-#define ENDPROC(name) \
-	.type name, @function !\
-	END(name)
-#endif
-
 #define ENTRY_CFI(name, ...) \
 	ENTRY(name)	ASM_NL\
 	.proc		ASM_NL\
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index e170365941f8..242c5ab65611 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -777,7 +777,7 @@  END(fault_vector_11)
 	 * copy_thread moved args into task save area.
 	 */
 
-ENTRY_CFI(ret_from_kernel_thread)
+ENTRY(ret_from_kernel_thread)
 	/* Call schedule_tail first though */
 	BL	schedule_tail, %r2
 	nop
@@ -792,7 +792,7 @@  ENTRY_CFI(ret_from_kernel_thread)
 	copy	%r31, %r2
 	b	finish_child_return
 	nop
-ENDPROC_CFI(ret_from_kernel_thread)
+END(ret_from_kernel_thread)
 
 
 	/*
@@ -816,9 +816,8 @@  ENTRY_CFI(_switch_to)
 	LDREG	TASK_THREAD_INFO(%r25), %r25
 	bv	%r0(%r2)
 	mtctl   %r25,%cr30
-ENDPROC_CFI(_switch_to)
 
-ENTRY_CFI(_switch_to_ret)
+ENTRY(_switch_to_ret)
 	mtctl	%r0, %cr0		/* Needed for single stepping */
 	callee_rest
 	callee_rest_float
@@ -826,7 +825,7 @@  ENTRY_CFI(_switch_to_ret)
 	LDREG	-RP_OFFSET(%r30), %r2
 	bv	%r0(%r2)
 	copy	%r26, %r28
-ENDPROC_CFI(_switch_to_ret)
+ENDPROC_CFI(_switch_to)
 
 	/*
 	 * Common rfi return path for interruptions, kernel execve, and
@@ -887,14 +886,12 @@  ENTRY_CFI(syscall_exit_rfi)
 	STREG   %r19,PT_SR5(%r16)
 	STREG   %r19,PT_SR6(%r16)
 	STREG   %r19,PT_SR7(%r16)
-ENDPROC_CFI(syscall_exit_rfi)
 
-ENTRY_CFI(intr_return)
+ENTRY(intr_return)
 	/* check for reschedule */
 	mfctl   %cr30,%r1
 	LDREG   TI_FLAGS(%r1),%r19	/* sched.h: TIF_NEED_RESCHED */
 	bb,<,n	%r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
-ENDPROC_CFI(intr_return)
 
 	.import do_notify_resume,code
 intr_check_sig:
@@ -1050,6 +1047,7 @@  intr_extint:
 
 	b	do_cpu_irq_mask
 	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
+ENDPROC_CFI(syscall_exit_rfi)
 
 
 	/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
@@ -1751,7 +1749,7 @@  fork_like fork
 fork_like vfork
 
 	/* Set the return value for the child */
-ENTRY_CFI(child_return)
+ENTRY(child_return)
 	BL	schedule_tail, %r2
 	nop
 finish_child_return:
@@ -1763,7 +1761,7 @@  finish_child_return:
 	reg_restore %r1
 	b	syscall_exit
 	copy	%r0,%r28
-ENDPROC_CFI(child_return)
+END(child_return)
 
 ENTRY_CFI(sys_rt_sigreturn_wrapper)
 	LDREG	TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
@@ -1795,7 +1793,7 @@  ENTRY_CFI(sys_rt_sigreturn_wrapper)
 	LDREG	PT_GR28(%r1),%r28  /* reload original r28 for syscall_exit */
 ENDPROC_CFI(sys_rt_sigreturn_wrapper)
 
-ENTRY_CFI(syscall_exit)
+ENTRY(syscall_exit)
 	/* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
 	 * via syscall_exit_rfi if the signal was received while the process
 	 * was running.
@@ -1994,15 +1992,13 @@  syscall_do_resched:
 #else
 	nop
 #endif
-ENDPROC_CFI(syscall_exit)
+END(syscall_exit)
 
 
 #ifdef CONFIG_FUNCTION_TRACER
 
 	.import ftrace_function_trampoline,code
 	.align L1_CACHE_BYTES
-	.globl mcount
-	.type  mcount, @function
 ENTRY_CFI(mcount, caller)
 _mcount:
 	.export _mcount,data
@@ -2031,8 +2027,6 @@  ENDPROC_CFI(mcount)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	.align 8
-	.globl return_to_handler
-	.type  return_to_handler, @function
 ENTRY_CFI(return_to_handler, caller,frame=FRAME_SIZE)
 	.export parisc_return_to_handler,data
 parisc_return_to_handler:
@@ -2082,6 +2076,7 @@  ENDPROC_CFI(return_to_handler)
 /* void call_on_stack(unsigned long param1, void *func,
 		      unsigned long new_stack) */
 ENTRY_CFI(call_on_stack, FRAME=2*FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
+ENTRY(_call_on_stack)
 	copy	%sp, %r1
 
 	/* Regarding the HPPA calling conventions for function pointers,
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index 5578a325a730..f329b466e68f 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -209,6 +209,8 @@  static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
 	 * We have to use void * instead of a function pointer, because
 	 * function pointers aren't a pointer to the function on 64-bit.
 	 * Make them const so the compiler knows they live in .text
+	 * Note: We could use dereference_kernel_function_descriptor()
+	 * instead but we want to keep it simple here.
 	 */
 	extern void * const handle_interruption;
 	extern void * const ret_from_kernel_thread;
@@ -216,7 +218,7 @@  static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
 	extern void * const intr_return;
 	extern void * const _switch_to_ret;
 #ifdef CONFIG_IRQSTACKS
-	extern void * const call_on_stack;
+	extern void * const _call_on_stack;
 #endif /* CONFIG_IRQSTACKS */
 
 	if (pc == (unsigned long) &handle_interruption) {
@@ -251,7 +253,7 @@  static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
 	}
 
 #ifdef CONFIG_IRQSTACKS
-	if (pc == (unsigned long) &call_on_stack) {
+	if (pc == (unsigned long) &_call_on_stack) {
 		info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
 		info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
 		return 1;