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