From e67659deac47fb2d4d27a7d4869bef8b9e363e08 Mon Sep 17 00:00:00 2001 From: Jiamin Ma Date: Tue, 19 Feb 2019 18:19:27 +0800 Subject: [PATCH] debug: fail to show active cpu stacks [1/1] PD#SWPL-4718 Problem: Will have "PC=0, LR=0" issue when try to show active cpu stacks via sysrq Solution: Save the addr of current interrupted task's context to the interrupt stack first, so that we can easily obtain pt_regs later Verify: Locally on Ampere Change-Id: I1cc5095e0ec356bed90f76cdf9af1b2617ce7834 Signed-off-by: Jiamin Ma --- arch/arm/kernel/entry-armv.S | 4 ++++ arch/arm/kernel/unwind.c | 38 ++++++++++++++++++++++----------- drivers/amlogic/memory_ext/vmap_stack.c | 19 +++++++++++------ include/linux/amlogic/vmap_stack.h | 4 ++++ 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bd77d9c..51c5758 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -47,7 +47,11 @@ #endif #ifdef CONFIG_MULTI_IRQ_HANDLER ldr r1, =handle_arch_irq +#ifdef CONFIG_AMLOGIC_VMAP + mov r0, r8 +#else mov r0, sp +#endif badr lr, 9997f ldr pc, [r1] #else diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index f7b320f..a005a27 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -46,6 +46,7 @@ #include #ifdef CONFIG_AMLOGIC_VMAP #include +#include #endif #include @@ -524,25 +525,36 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk) #ifdef CONFIG_AMLOGIC_VMAP if (urc < 0) { int keep = 0; + int cpu; + unsigned long addr; + struct pt_regs *pt_regs; + cpu = raw_smp_processor_id(); /* continue search for irq stack */ - if (on_irq_stack(frame.sp, raw_smp_processor_id())) { - unsigned long *prev_fp; - - prev_fp = (unsigned long *)(frame.fp - 12); - if (frame.fp >= TASK_SIZE) { - keep = 1; - frame.fp = prev_fp[0]; - frame.sp = prev_fp[1]; - frame.lr = prev_fp[2]; - frame.pc = prev_fp[3]; - } + if (on_irq_stack(frame.sp, cpu)) { + unsigned long sp_irq; + + keep = 1; + sp_irq = (unsigned long)irq_stack[cpu]; + addr = *((unsigned long *)(sp_irq + + THREAD_INFO_OFFSET - 8 - + sizeof(addr))); + pt_regs = (struct pt_regs *)addr; + frame.fp = pt_regs->ARM_fp; + frame.sp = pt_regs->ARM_sp; + frame.lr = pt_regs->ARM_lr; + frame.pc = pt_regs->ARM_pc; } if (!keep) break; } - where = frame.lr; - dump_backtrace_entry_fp(where, frame.fp, frame.sp); + where = frame.pc; + /* + * The last "where" may be an invalid one, + * rechecking it + */ + if (kernel_text_address(where)) + dump_backtrace_entry_fp(where, frame.fp, frame.sp); #else if (urc < 0) break; diff --git a/drivers/amlogic/memory_ext/vmap_stack.c b/drivers/amlogic/memory_ext/vmap_stack.c index 94beb26..664ab24 100644 --- a/drivers/amlogic/memory_ext/vmap_stack.c +++ b/drivers/amlogic/memory_ext/vmap_stack.c @@ -56,7 +56,7 @@ DEFINE_PER_CPU(unsigned long [THREAD_SIZE/sizeof(long)], vmap_stack) #else static unsigned long irq_stack1[(THREAD_SIZE/sizeof(long))] __aligned(THREAD_SIZE); -static void *irq_stack[NR_CPUS] = { +void *irq_stack[NR_CPUS] = { irq_stack1, /* only assign 1st irq stack ,other need alloc */ }; static unsigned long vmap_stack1[(THREAD_SIZE/sizeof(long))] @@ -142,23 +142,29 @@ int on_irq_stack(unsigned long sp, int cpu) return 0; } -unsigned long notrace irq_stack_entry(unsigned long sp_irq) +unsigned long notrace irq_stack_entry(unsigned long sp) { int cpu = raw_smp_processor_id(); - if (!on_irq_stack(sp_irq, cpu)) { - unsigned long sp = (unsigned long)irq_stack[cpu]; + if (!on_irq_stack(sp, cpu)) { + unsigned long sp_irq = (unsigned long)irq_stack[cpu]; void *src, *dst; /* * copy some data to irq stack */ src = current_thread_info(); - dst = (void *)(sp + THREAD_INFO_OFFSET); + dst = (void *)(sp_irq + THREAD_INFO_OFFSET); memcpy(dst, src, offsetof(struct thread_info, cpu_context)); sp_irq = (unsigned long)dst - 8; + /* + * save start addr of the interrupted task's context + */ + sp_irq = sp_irq - sizeof(sp); + *((unsigned long *)sp_irq) = sp; + return sp_irq; } - return sp_irq; + return sp; } unsigned long notrace pmd_check(unsigned long addr, unsigned long far) @@ -403,6 +409,7 @@ static noinline void show_fault_stack(unsigned long addr, struct pt_regs *regs) #elif defined(CONFIG_ARM) frame.fp = regs->ARM_fp; frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; frame.pc = (unsigned long)regs->uregs[15]; #endif diff --git a/include/linux/amlogic/vmap_stack.h b/include/linux/amlogic/vmap_stack.h index a5e001a..a8aa35f 100644 --- a/include/linux/amlogic/vmap_stack.h +++ b/include/linux/amlogic/vmap_stack.h @@ -55,6 +55,10 @@ struct aml_vmap { spinlock_t page_lock; }; +#ifndef CONFIG_ARM64 +extern void *irq_stack[NR_CPUS]; +#endif + extern int handle_vmap_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs); -- 2.7.4