Merge branch 'parisc-4.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux
Pull more parisc updates from Helge Deller: - fix boot failure of 64-bit kernel. It got broken by the unwind optimization commit in merge window. - fix 64-bit userspace support (static 64-bit applications only, e.g. we don't yet have 64-bit userspace support in glibc). - consolidate unwind initialization code. - add machine model description to stack trace. * 'parisc-4.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux: parisc: Add hardware description to stack traces parisc: Fix boot failure of 64-bit kernel parisc: Consolidate unwind initialization calls parisc: Update comments in syscall.S regarding wide userland parisc: Fix ptraced 64-bit applications to call 64-bit syscalls parisc: Restore possibility to execute 64-bit applications
This commit is contained in:
commit
45b74a65b9
@ -235,6 +235,7 @@ typedef unsigned long elf_greg_t;
|
||||
#define SET_PERSONALITY(ex) \
|
||||
({ \
|
||||
set_personality((current->personality & ~PER_MASK) | PER_LINUX); \
|
||||
clear_thread_flag(TIF_32BIT); \
|
||||
current->thread.map_base = DEFAULT_MAP_BASE; \
|
||||
current->thread.task_size = DEFAULT_TASK_SIZE; \
|
||||
})
|
||||
@ -243,9 +244,11 @@ typedef unsigned long elf_greg_t;
|
||||
|
||||
#define COMPAT_SET_PERSONALITY(ex) \
|
||||
({ \
|
||||
set_thread_flag(TIF_32BIT); \
|
||||
current->thread.map_base = DEFAULT_MAP_BASE32; \
|
||||
current->thread.task_size = DEFAULT_TASK_SIZE32; \
|
||||
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) { \
|
||||
set_thread_flag(TIF_32BIT); \
|
||||
current->thread.map_base = DEFAULT_MAP_BASE32; \
|
||||
current->thread.task_size = DEFAULT_TASK_SIZE32; \
|
||||
} else clear_thread_flag(TIF_32BIT); \
|
||||
})
|
||||
|
||||
/*
|
||||
|
@ -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\
|
||||
|
@ -256,11 +256,7 @@ on downward growing arches, it looks like this:
|
||||
* it in here from the current->personality
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT))
|
||||
#else
|
||||
#define USER_WIDE_MODE 0
|
||||
#endif
|
||||
#define USER_WIDE_MODE (!is_32bit_task())
|
||||
|
||||
#define start_thread(regs, new_pc, new_sp) do { \
|
||||
elf_addr_t *sp = (elf_addr_t *)new_sp; \
|
||||
|
@ -2,7 +2,9 @@
|
||||
#ifndef __ASM_TRAPS_H
|
||||
#define __ASM_TRAPS_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define PARISC_ITLB_TRAP 6 /* defined by architecture. Do not change. */
|
||||
|
||||
#if !defined(__ASSEMBLY__)
|
||||
struct pt_regs;
|
||||
|
||||
/* traps.c */
|
||||
|
@ -73,8 +73,10 @@ unwind_table_remove(struct unwind_table *table);
|
||||
|
||||
void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
|
||||
struct pt_regs *regs);
|
||||
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t);
|
||||
void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs);
|
||||
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info,
|
||||
struct task_struct *t);
|
||||
void unwind_frame_init_task(struct unwind_frame_info *info,
|
||||
struct task_struct *task, struct pt_regs *regs);
|
||||
int unwind_once(struct unwind_frame_info *info);
|
||||
int unwind_to_user(struct unwind_frame_info *info);
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <asm/signal.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/ldcw.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
#include <linux/linkage.h>
|
||||
@ -692,7 +693,7 @@ ENTRY(fault_vector_20)
|
||||
def 3
|
||||
extint 4
|
||||
def 5
|
||||
itlb_20 6
|
||||
itlb_20 PARISC_ITLB_TRAP
|
||||
def 7
|
||||
def 8
|
||||
def 9
|
||||
@ -735,7 +736,7 @@ ENTRY(fault_vector_11)
|
||||
def 3
|
||||
extint 4
|
||||
def 5
|
||||
itlb_11 6
|
||||
itlb_11 PARISC_ITLB_TRAP
|
||||
def 7
|
||||
def 8
|
||||
def 9
|
||||
@ -776,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
|
||||
@ -791,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)
|
||||
|
||||
|
||||
/*
|
||||
@ -815,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
|
||||
@ -825,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
|
||||
@ -886,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:
|
||||
@ -1049,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) */
|
||||
@ -1068,21 +1067,12 @@ ENTRY_CFI(intr_save) /* for os_hpmc */
|
||||
save_specials %r29
|
||||
|
||||
/* If this trap is a itlb miss, skip saving/adjusting isr/ior */
|
||||
|
||||
/*
|
||||
* FIXME: 1) Use a #define for the hardwired "6" below (and in
|
||||
* traps.c.
|
||||
* 2) Once we start executing code above 4 Gb, we need
|
||||
* to adjust iasq/iaoq here in the same way we
|
||||
* adjust isr/ior below.
|
||||
*/
|
||||
|
||||
cmpib,COND(=),n 6,%r26,skip_save_ior
|
||||
cmpib,COND(=),n PARISC_ITLB_TRAP,%r26,skip_save_ior
|
||||
|
||||
|
||||
mfctl %cr20, %r16 /* isr */
|
||||
mfctl %isr, %r16
|
||||
nop /* serialize mfctl on PA 2.0 to avoid 4 cycle penalty */
|
||||
mfctl %cr21, %r17 /* ior */
|
||||
mfctl %ior, %r17
|
||||
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
@ -1094,22 +1084,34 @@ ENTRY_CFI(intr_save) /* for os_hpmc */
|
||||
extrd,u,*<> %r8,PSW_W_BIT,1,%r0
|
||||
depdi 0,1,2,%r17
|
||||
|
||||
/*
|
||||
* FIXME: This code has hardwired assumptions about the split
|
||||
* between space bits and offset bits. This will change
|
||||
* when we allow alternate page sizes.
|
||||
*/
|
||||
|
||||
/* adjust isr/ior. */
|
||||
extrd,u %r16,63,SPACEID_SHIFT,%r1 /* get high bits from isr for ior */
|
||||
depd %r1,31,SPACEID_SHIFT,%r17 /* deposit them into ior */
|
||||
depdi 0,63,SPACEID_SHIFT,%r16 /* clear them from isr */
|
||||
/* adjust isr/ior: get high bits from isr and deposit in ior */
|
||||
space_adjust %r16,%r17,%r1
|
||||
#endif
|
||||
STREG %r16, PT_ISR(%r29)
|
||||
STREG %r17, PT_IOR(%r29)
|
||||
|
||||
#if 0 && defined(CONFIG_64BIT)
|
||||
/* Revisit when we have 64-bit code above 4Gb */
|
||||
b,n intr_save2
|
||||
|
||||
skip_save_ior:
|
||||
/* We have a itlb miss, and when executing code above 4 Gb on ILP64, we
|
||||
* need to adjust iasq/iaoq here in the same way we adjusted isr/ior
|
||||
* above.
|
||||
*/
|
||||
extrd,u,* %r8,PSW_W_BIT,1,%r1
|
||||
cmpib,COND(=),n 1,%r1,intr_save2
|
||||
LDREG PT_IASQ0(%r29), %r16
|
||||
LDREG PT_IAOQ0(%r29), %r17
|
||||
/* adjust iasq/iaoq */
|
||||
space_adjust %r16,%r17,%r1
|
||||
STREG %r16, PT_IASQ0(%r29)
|
||||
STREG %r17, PT_IAOQ0(%r29)
|
||||
#else
|
||||
skip_save_ior:
|
||||
#endif
|
||||
|
||||
intr_save2:
|
||||
virt_map
|
||||
save_general %r29
|
||||
|
||||
@ -1747,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:
|
||||
@ -1759,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
|
||||
@ -1791,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.
|
||||
@ -1990,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
|
||||
@ -2027,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:
|
||||
@ -2078,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,
|
||||
|
@ -288,6 +288,8 @@ void __init collect_boot_cpu_data(void)
|
||||
printk(KERN_INFO "model %s\n",
|
||||
boot_cpu_data.pdc.sys_model_name);
|
||||
|
||||
dump_stack_set_arch_desc("%s", boot_cpu_data.pdc.sys_model_name);
|
||||
|
||||
boot_cpu_data.hversion = boot_cpu_data.pdc.model.hversion;
|
||||
boot_cpu_data.sversion = boot_cpu_data.pdc.model.sversion;
|
||||
|
||||
|
@ -16,20 +16,7 @@ static void dump_trace(struct task_struct *task, struct stack_trace *trace)
|
||||
{
|
||||
struct unwind_frame_info info;
|
||||
|
||||
/* initialize unwind info */
|
||||
if (task == current) {
|
||||
unsigned long sp;
|
||||
struct pt_regs r;
|
||||
HERE:
|
||||
asm volatile ("copy %%r30, %0" : "=r"(sp));
|
||||
memset(&r, 0, sizeof(struct pt_regs));
|
||||
r.iaoq[0] = (unsigned long)&&HERE;
|
||||
r.gr[2] = (unsigned long)__builtin_return_address(0);
|
||||
r.gr[30] = sp;
|
||||
unwind_frame_init(&info, task, &r);
|
||||
} else {
|
||||
unwind_frame_init_from_blocked_task(&info, task);
|
||||
}
|
||||
unwind_frame_init_task(&info, task, NULL);
|
||||
|
||||
/* unwind stack and save entries in stack_trace struct */
|
||||
trace->nr_entries = 0;
|
||||
|
@ -156,11 +156,6 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
|
||||
int do_color_align, last_mmap;
|
||||
struct vm_unmapped_area_info info;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/* This should only ever run for 32-bit processes. */
|
||||
BUG_ON(!test_thread_flag(TIF_32BIT));
|
||||
#endif
|
||||
|
||||
/* requested length too big for entire address space */
|
||||
if (len > TASK_SIZE)
|
||||
return -ENOMEM;
|
||||
|
@ -108,12 +108,8 @@ linux_gateway_entry:
|
||||
mtsp %r0,%sr6 /* get kernel space into sr6 */
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/* for now we can *always* set the W bit on entry to the syscall
|
||||
* since we don't support wide userland processes. We could
|
||||
* also save the current SM other than in r0 and restore it on
|
||||
* exit from the syscall, and also use that value to know
|
||||
* whether to do narrow or wide syscalls. -PB
|
||||
*/
|
||||
/* Store W bit on entry to the syscall in case it's a wide userland
|
||||
* process. */
|
||||
ssm PSW_SM_W, %r1
|
||||
extrd,u %r1,PSW_W_BIT,1,%r1
|
||||
/* sp must be aligned on 4, so deposit the W bit setting into
|
||||
@ -227,8 +223,7 @@ linux_gateway_entry:
|
||||
or,= %r2,%r2,%r2
|
||||
ldo R%sys_call_table64(%r1), %r19
|
||||
#else
|
||||
ldil L%sys_call_table, %r1
|
||||
ldo R%sys_call_table(%r1), %r19
|
||||
load32 sys_call_table, %r19
|
||||
#endif
|
||||
comiclr,>> __NR_Linux_syscalls, %r20, %r0
|
||||
b,n .Lsyscall_nosys
|
||||
@ -331,8 +326,6 @@ tracesys_next:
|
||||
* task->thread.regs.gr[20] above.
|
||||
*/
|
||||
copy %ret0,%r20
|
||||
ldil L%sys_call_table,%r1
|
||||
ldo R%sys_call_table(%r1), %r19
|
||||
|
||||
ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
|
||||
LDREG TI_TASK(%r1), %r1
|
||||
@ -354,6 +347,23 @@ tracesys_next:
|
||||
comiclr,>> __NR_Linux_syscalls, %r20, %r0
|
||||
b,n .Ltracesys_nosys
|
||||
|
||||
/* Note! We cannot use the syscall table that is mapped
|
||||
nearby since the gateway page is mapped execute-only. */
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
LDREG TASK_PT_GR30(%r1), %r19 /* get users sp back */
|
||||
extrd,u %r19,63,1,%r2 /* W hidden in bottom bit */
|
||||
|
||||
ldil L%sys_call_table, %r1
|
||||
or,= %r2,%r2,%r2
|
||||
addil L%(sys_call_table64-sys_call_table), %r1
|
||||
ldo R%sys_call_table(%r1), %r19
|
||||
or,= %r2,%r2,%r2
|
||||
ldo R%sys_call_table64(%r1), %r19
|
||||
#else
|
||||
load32 sys_call_table, %r19
|
||||
#endif
|
||||
|
||||
LDREGX %r20(%r19), %r19
|
||||
|
||||
/* If this is a sys_rt_sigreturn call, and the signal was received
|
||||
@ -464,16 +474,13 @@ tracesys_sigexit:
|
||||
lws_start:
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/* FIXME: If we are a 64-bit kernel just
|
||||
* turn this on unconditionally.
|
||||
*/
|
||||
ssm PSW_SM_W, %r1
|
||||
extrd,u %r1,PSW_W_BIT,1,%r1
|
||||
/* sp must be aligned on 4, so deposit the W bit setting into
|
||||
* the bottom of sp temporarily */
|
||||
or,ev %r1,%r30,%r30
|
||||
|
||||
/* Clip LWS number to a 32-bit value always */
|
||||
/* Clip LWS number to a 32-bit value for 32-bit processes */
|
||||
depdi 0, 31, 32, %r20
|
||||
#endif
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
#include "../math-emu/math-emu.h" /* for handle_fpe() */
|
||||
|
||||
static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
|
||||
static void parisc_show_stack(struct task_struct *task,
|
||||
struct pt_regs *regs);
|
||||
|
||||
static int printbinary(char *buf, unsigned long x, int nbits)
|
||||
@ -152,7 +152,7 @@ void show_regs(struct pt_regs *regs)
|
||||
printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
|
||||
printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
|
||||
|
||||
parisc_show_stack(current, NULL, regs);
|
||||
parisc_show_stack(current, regs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,44 +185,19 @@ static void do_show_stack(struct unwind_frame_info *info)
|
||||
printk(KERN_CRIT "\n");
|
||||
}
|
||||
|
||||
static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
|
||||
static void parisc_show_stack(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct unwind_frame_info info;
|
||||
struct task_struct *t;
|
||||
|
||||
t = task ? task : current;
|
||||
if (regs) {
|
||||
unwind_frame_init(&info, t, regs);
|
||||
goto show_stack;
|
||||
}
|
||||
unwind_frame_init_task(&info, task, regs);
|
||||
|
||||
if (t == current) {
|
||||
unsigned long sp;
|
||||
|
||||
HERE:
|
||||
asm volatile ("copy %%r30, %0" : "=r"(sp));
|
||||
{
|
||||
struct pt_regs r;
|
||||
|
||||
memset(&r, 0, sizeof(struct pt_regs));
|
||||
r.iaoq[0] = (unsigned long)&&HERE;
|
||||
r.gr[2] = (unsigned long)__builtin_return_address(0);
|
||||
r.gr[30] = sp;
|
||||
|
||||
unwind_frame_init(&info, current, &r);
|
||||
}
|
||||
} else {
|
||||
unwind_frame_init_from_blocked_task(&info, t);
|
||||
}
|
||||
|
||||
show_stack:
|
||||
do_show_stack(&info);
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *t, unsigned long *sp)
|
||||
{
|
||||
return parisc_show_stack(t, sp, NULL);
|
||||
parisc_show_stack(t, NULL);
|
||||
}
|
||||
|
||||
int is_valid_bugaddr(unsigned long iaoq)
|
||||
@ -557,7 +532,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
|
||||
cpu_lpmc(5, regs);
|
||||
return;
|
||||
|
||||
case 6:
|
||||
case PARISC_ITLB_TRAP:
|
||||
/* Instruction TLB miss fault/Instruction page fault */
|
||||
fault_address = regs->iaoq[0];
|
||||
fault_space = regs->iasq[0];
|
||||
|
@ -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;
|
||||
@ -403,9 +405,31 @@ void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct
|
||||
kfree(r2);
|
||||
}
|
||||
|
||||
void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
|
||||
#define get_parisc_stackpointer() ({ \
|
||||
unsigned long sp; \
|
||||
__asm__("copy %%r30, %0" : "=r"(sp)); \
|
||||
(sp); \
|
||||
})
|
||||
|
||||
void unwind_frame_init_task(struct unwind_frame_info *info,
|
||||
struct task_struct *task, struct pt_regs *regs)
|
||||
{
|
||||
unwind_frame_init(info, current, regs);
|
||||
task = task ? task : current;
|
||||
|
||||
if (task == current) {
|
||||
struct pt_regs r;
|
||||
|
||||
if (!regs) {
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.iaoq[0] = _THIS_IP_;
|
||||
r.gr[2] = _RET_IP_;
|
||||
r.gr[30] = get_parisc_stackpointer();
|
||||
regs = &r;
|
||||
}
|
||||
unwind_frame_init(info, task, &r);
|
||||
} else {
|
||||
unwind_frame_init_from_blocked_task(info, task);
|
||||
}
|
||||
}
|
||||
|
||||
int unwind_once(struct unwind_frame_info *next_frame)
|
||||
@ -442,19 +466,12 @@ int unwind_to_user(struct unwind_frame_info *info)
|
||||
unsigned long return_address(unsigned int level)
|
||||
{
|
||||
struct unwind_frame_info info;
|
||||
struct pt_regs r;
|
||||
unsigned long sp;
|
||||
|
||||
/* initialize unwind info */
|
||||
asm volatile ("copy %%r30, %0" : "=r"(sp));
|
||||
memset(&r, 0, sizeof(struct pt_regs));
|
||||
r.iaoq[0] = _THIS_IP_;
|
||||
r.gr[2] = _RET_IP_;
|
||||
r.gr[30] = sp;
|
||||
unwind_frame_init(&info, current, &r);
|
||||
unwind_frame_init_task(&info, current, NULL);
|
||||
|
||||
/* unwind stack */
|
||||
++level;
|
||||
level += 2;
|
||||
do {
|
||||
if (unwind_once(&info) < 0 || info.ip == 0)
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user