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

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
...@@ -22,15 +22,6 @@ ...@@ -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\
......
...@@ -777,7 +777,7 @@ END(fault_vector_11) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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 ...@@ -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: ...@@ -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) ...@@ -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: ...@@ -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) ...@@ -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) ...@@ -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,
......
...@@ -209,6 +209,8 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int ...@@ -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 ...@@ -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 ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment