1*d0df954bSJoseph Chen // SPDX-License-Identifier: GPL-2.0 2*d0df954bSJoseph Chen /* 3*d0df954bSJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4*d0df954bSJoseph Chen */ 5*d0df954bSJoseph Chen 6*d0df954bSJoseph Chen #include <common.h> 7*d0df954bSJoseph Chen #include <stacktrace.h> 8*d0df954bSJoseph Chen 9*d0df954bSJoseph Chen DECLARE_GLOBAL_DATA_PTR; 10*d0df954bSJoseph Chen 11*d0df954bSJoseph Chen struct stackframe { 12*d0df954bSJoseph Chen uint64_t fp; 13*d0df954bSJoseph Chen uint64_t sp; 14*d0df954bSJoseph Chen uint64_t pc; 15*d0df954bSJoseph Chen }; 16*d0df954bSJoseph Chen 17*d0df954bSJoseph Chen static __always_inline uint64_t read_fp(void) 18*d0df954bSJoseph Chen { 19*d0df954bSJoseph Chen uint64_t val; 20*d0df954bSJoseph Chen 21*d0df954bSJoseph Chen asm volatile ("mov %0, x29" : "=r" (val)); 22*d0df954bSJoseph Chen return val; 23*d0df954bSJoseph Chen } 24*d0df954bSJoseph Chen 25*d0df954bSJoseph Chen static __always_inline uint64_t read_lr(void) 26*d0df954bSJoseph Chen { 27*d0df954bSJoseph Chen uint64_t val; 28*d0df954bSJoseph Chen 29*d0df954bSJoseph Chen asm volatile ("mov %0, x30" : "=r" (val)); 30*d0df954bSJoseph Chen return val; 31*d0df954bSJoseph Chen } 32*d0df954bSJoseph Chen 33*d0df954bSJoseph Chen static __always_inline uint64_t read_pc(void) 34*d0df954bSJoseph Chen { 35*d0df954bSJoseph Chen uint64_t val; 36*d0df954bSJoseph Chen 37*d0df954bSJoseph Chen asm volatile ("adr %0, ." : "=r" (val)); 38*d0df954bSJoseph Chen return val; 39*d0df954bSJoseph Chen } 40*d0df954bSJoseph Chen 41*d0df954bSJoseph Chen /* It's not allowed to access sp_el2 in EL2, so always return a valid sp */ 42*d0df954bSJoseph Chen static __always_inline uint64_t read_sp(void) 43*d0df954bSJoseph Chen { 44*d0df954bSJoseph Chen return gd->start_addr_sp - (CONFIG_SYS_STACK_SIZE / 2); 45*d0df954bSJoseph Chen } 46*d0df954bSJoseph Chen 47*d0df954bSJoseph Chen static bool walk_stackframe(struct stackframe *frame) 48*d0df954bSJoseph Chen { 49*d0df954bSJoseph Chen ulong fp = frame->fp; 50*d0df954bSJoseph Chen 51*d0df954bSJoseph Chen if (fp > gd->start_addr_sp || 52*d0df954bSJoseph Chen fp < gd->start_addr_sp - CONFIG_SYS_STACK_SIZE) 53*d0df954bSJoseph Chen return false; 54*d0df954bSJoseph Chen 55*d0df954bSJoseph Chen frame->sp = fp + 0x10; 56*d0df954bSJoseph Chen frame->fp = *(ulong *)(fp); 57*d0df954bSJoseph Chen frame->pc = *(ulong *)(fp + 8); 58*d0df954bSJoseph Chen 59*d0df954bSJoseph Chen return true; 60*d0df954bSJoseph Chen } 61*d0df954bSJoseph Chen 62*d0df954bSJoseph Chen void dump_core_stack(struct pt_regs *regs) 63*d0df954bSJoseph Chen { 64*d0df954bSJoseph Chen struct stackframe frame; 65*d0df954bSJoseph Chen ulong pc, lr; 66*d0df954bSJoseph Chen 67*d0df954bSJoseph Chen frame.fp = regs->regs[29]; 68*d0df954bSJoseph Chen frame.sp = regs->sp; 69*d0df954bSJoseph Chen frame.pc = regs->elr; 70*d0df954bSJoseph Chen 71*d0df954bSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 72*d0df954bSJoseph Chen pc = (ulong)frame.pc - gd->reloc_off; 73*d0df954bSJoseph Chen lr = (ulong)regs->regs[30] - gd->reloc_off; 74*d0df954bSJoseph Chen } else { 75*d0df954bSJoseph Chen pc = (ulong)frame.pc; 76*d0df954bSJoseph Chen lr = (ulong)regs->regs[30]; 77*d0df954bSJoseph Chen } 78*d0df954bSJoseph Chen 79*d0df954bSJoseph Chen printf("\nCall trace:\n"); 80*d0df954bSJoseph Chen printf(" PC: [< %08lx >]\n", pc); 81*d0df954bSJoseph Chen printf(" LR: [< %08lx >]\n", lr); 82*d0df954bSJoseph Chen 83*d0df954bSJoseph Chen printf("\nStack:\n"); 84*d0df954bSJoseph Chen do { 85*d0df954bSJoseph Chen if (gd->flags & GD_FLG_RELOC) 86*d0df954bSJoseph Chen pc = (ulong)frame.pc - gd->reloc_off; 87*d0df954bSJoseph Chen else 88*d0df954bSJoseph Chen pc = (ulong)frame.pc; 89*d0df954bSJoseph Chen 90*d0df954bSJoseph Chen printf(" [< %08lx >]\n", pc); 91*d0df954bSJoseph Chen } while (walk_stackframe(&frame)); 92*d0df954bSJoseph Chen 93*d0df954bSJoseph Chen printf("\nNOTE: Please use ./scripts/stacktrace.sh to parse trace info\n"); 94*d0df954bSJoseph Chen } 95*d0df954bSJoseph Chen 96*d0df954bSJoseph Chen void dump_stack(void) 97*d0df954bSJoseph Chen { 98*d0df954bSJoseph Chen struct pt_regs regs; 99*d0df954bSJoseph Chen 100*d0df954bSJoseph Chen regs.regs[29] = read_fp(); 101*d0df954bSJoseph Chen regs.regs[30] = read_lr(); 102*d0df954bSJoseph Chen regs.sp = read_sp(); 103*d0df954bSJoseph Chen regs.elr = read_pc(); 104*d0df954bSJoseph Chen 105*d0df954bSJoseph Chen dump_core_stack(®s); 106*d0df954bSJoseph Chen } 107