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