Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8801ccb9 authored by Helge Deller's avatar Helge Deller
Browse files

parisc: Fix boot failure of 64-bit kernel



Commit c8921d72 ("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: default avatarHelge Deller <deller@gmx.de>
Fixes: c8921d72 ("parisc: Fix and improve kernel stack unwinding")
parent 9e0d5c45
Loading
Loading
Loading
Loading
+0 −9
Original line number Original line Diff line number Diff line
@@ -22,15 +22,6 @@
name:		ASM_NL\
name:		ASM_NL\
	.export name
	.export name


#ifdef CONFIG_64BIT
#define ENDPROC(name) \
	END(name)
#else
#define ENDPROC(name) \
	.type name, @function !\
	END(name)
#endif

#define ENTRY_CFI(name, ...) \
#define ENTRY_CFI(name, ...) \
	ENTRY(name)	ASM_NL\
	ENTRY(name)	ASM_NL\
	.proc		ASM_NL\
	.proc		ASM_NL\
+11 −16
Original line number Original line Diff line number Diff line
@@ -777,7 +777,7 @@ END(fault_vector_11)
	 * copy_thread moved args into task save area.
	 * copy_thread moved args into task save area.
	 */
	 */


ENTRY_CFI(ret_from_kernel_thread)
ENTRY(ret_from_kernel_thread)
	/* Call schedule_tail first though */
	/* Call schedule_tail first though */
	BL	schedule_tail, %r2
	BL	schedule_tail, %r2
	nop
	nop
@@ -792,7 +792,7 @@ ENTRY_CFI(ret_from_kernel_thread)
	copy	%r31, %r2
	copy	%r31, %r2
	b	finish_child_return
	b	finish_child_return
	nop
	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
	LDREG	TASK_THREAD_INFO(%r25), %r25
	bv	%r0(%r2)
	bv	%r0(%r2)
	mtctl   %r25,%cr30
	mtctl   %r25,%cr30
ENDPROC_CFI(_switch_to)


ENTRY_CFI(_switch_to_ret)
ENTRY(_switch_to_ret)
	mtctl	%r0, %cr0		/* Needed for single stepping */
	mtctl	%r0, %cr0		/* Needed for single stepping */
	callee_rest
	callee_rest
	callee_rest_float
	callee_rest_float
@@ -826,7 +825,7 @@ ENTRY_CFI(_switch_to_ret)
	LDREG	-RP_OFFSET(%r30), %r2
	LDREG	-RP_OFFSET(%r30), %r2
	bv	%r0(%r2)
	bv	%r0(%r2)
	copy	%r26, %r28
	copy	%r26, %r28
ENDPROC_CFI(_switch_to_ret)
ENDPROC_CFI(_switch_to)


	/*
	/*
	 * Common rfi return path for interruptions, kernel execve, and
	 * 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_SR5(%r16)
	STREG   %r19,PT_SR6(%r16)
	STREG   %r19,PT_SR6(%r16)
	STREG   %r19,PT_SR7(%r16)
	STREG   %r19,PT_SR7(%r16)
ENDPROC_CFI(syscall_exit_rfi)


ENTRY_CFI(intr_return)
ENTRY(intr_return)
	/* check for reschedule */
	/* check for reschedule */
	mfctl   %cr30,%r1
	mfctl   %cr30,%r1
	LDREG   TI_FLAGS(%r1),%r19	/* sched.h: TIF_NEED_RESCHED */
	LDREG   TI_FLAGS(%r1),%r19	/* sched.h: TIF_NEED_RESCHED */
	bb,<,n	%r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
	bb,<,n	%r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
ENDPROC_CFI(intr_return)


	.import do_notify_resume,code
	.import do_notify_resume,code
intr_check_sig:
intr_check_sig:
@@ -1050,6 +1047,7 @@ intr_extint:


	b	do_cpu_irq_mask
	b	do_cpu_irq_mask
	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
	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) */
	/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
@@ -1751,7 +1749,7 @@ fork_like fork
fork_like vfork
fork_like vfork


	/* Set the return value for the child */
	/* Set the return value for the child */
ENTRY_CFI(child_return)
ENTRY(child_return)
	BL	schedule_tail, %r2
	BL	schedule_tail, %r2
	nop
	nop
finish_child_return:
finish_child_return:
@@ -1763,7 +1761,7 @@ finish_child_return:
	reg_restore %r1
	reg_restore %r1
	b	syscall_exit
	b	syscall_exit
	copy	%r0,%r28
	copy	%r0,%r28
ENDPROC_CFI(child_return)
END(child_return)


ENTRY_CFI(sys_rt_sigreturn_wrapper)
ENTRY_CFI(sys_rt_sigreturn_wrapper)
	LDREG	TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
	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 */
	LDREG	PT_GR28(%r1),%r28  /* reload original r28 for syscall_exit */
ENDPROC_CFI(sys_rt_sigreturn_wrapper)
ENDPROC_CFI(sys_rt_sigreturn_wrapper)


ENTRY_CFI(syscall_exit)
ENTRY(syscall_exit)
	/* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
	/* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
	 * via syscall_exit_rfi if the signal was received while the process
	 * via syscall_exit_rfi if the signal was received while the process
	 * was running.
	 * was running.
@@ -1994,15 +1992,13 @@ syscall_do_resched:
#else
#else
	nop
	nop
#endif
#endif
ENDPROC_CFI(syscall_exit)
END(syscall_exit)




#ifdef CONFIG_FUNCTION_TRACER
#ifdef CONFIG_FUNCTION_TRACER


	.import ftrace_function_trampoline,code
	.import ftrace_function_trampoline,code
	.align L1_CACHE_BYTES
	.align L1_CACHE_BYTES
	.globl mcount
	.type  mcount, @function
ENTRY_CFI(mcount, caller)
ENTRY_CFI(mcount, caller)
_mcount:
_mcount:
	.export _mcount,data
	.export _mcount,data
@@ -2031,8 +2027,6 @@ ENDPROC_CFI(mcount)


#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	.align 8
	.align 8
	.globl return_to_handler
	.type  return_to_handler, @function
ENTRY_CFI(return_to_handler, caller,frame=FRAME_SIZE)
ENTRY_CFI(return_to_handler, caller,frame=FRAME_SIZE)
	.export parisc_return_to_handler,data
	.export parisc_return_to_handler,data
parisc_return_to_handler:
parisc_return_to_handler:
@@ -2082,6 +2076,7 @@ ENDPROC_CFI(return_to_handler)
/* void call_on_stack(unsigned long param1, void *func,
/* void call_on_stack(unsigned long param1, void *func,
		      unsigned long new_stack) */
		      unsigned long new_stack) */
ENTRY_CFI(call_on_stack, FRAME=2*FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
ENTRY_CFI(call_on_stack, FRAME=2*FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
ENTRY(_call_on_stack)
	copy	%sp, %r1
	copy	%sp, %r1


	/* Regarding the HPPA calling conventions for function pointers,
	/* Regarding the HPPA calling conventions for function pointers,
+4 −2
Original line number Original line Diff line number Diff line
@@ -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
	 * We have to use void * instead of a function pointer, because
	 * function pointers aren't a pointer to the function on 64-bit.
	 * function pointers aren't a pointer to the function on 64-bit.
	 * Make them const so the compiler knows they live in .text
	 * 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 handle_interruption;
	extern void * const ret_from_kernel_thread;
	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 intr_return;
	extern void * const _switch_to_ret;
	extern void * const _switch_to_ret;
#ifdef CONFIG_IRQSTACKS
#ifdef CONFIG_IRQSTACKS
	extern void * const call_on_stack;
	extern void * const _call_on_stack;
#endif /* CONFIG_IRQSTACKS */
#endif /* CONFIG_IRQSTACKS */


	if (pc == (unsigned long) &handle_interruption) {
	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
#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_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
		info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
		info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
		return 1;
		return 1;