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 67 frame.fp = regs->regs[29]; 68 frame.sp = regs->sp; 69 frame.pc = regs->elr; 70 71 if (gd->flags & GD_FLG_RELOC) { 72 pc = (ulong)frame.pc - gd->reloc_off; 73 lr = (ulong)regs->regs[30] - gd->reloc_off; 74 } else { 75 pc = (ulong)frame.pc; 76 lr = (ulong)regs->regs[30]; 77 } 78 79 printf("\nCall trace:\n"); 80 printf(" PC: [< %08lx >]\n", pc); 81 printf(" LR: [< %08lx >]\n", lr); 82 83 printf("\nStack:\n"); 84 do { 85 if (gd->flags & GD_FLG_RELOC) 86 pc = (ulong)frame.pc - gd->reloc_off; 87 else 88 pc = (ulong)frame.pc; 89 90 printf(" [< %08lx >]\n", pc); 91 } while (walk_stackframe(&frame)); 92 93 printf("\nCopy above stack info to a file(eg. dump.txt), and\n" 94 "execute command in your U-Boot project: " 95 "./scripts/stacktrace.sh dump.txt\n\n"); 96 } 97 98 void dump_stack(void) 99 { 100 struct pt_regs regs; 101 102 regs.regs[29] = read_fp(); 103 regs.regs[30] = read_lr(); 104 regs.sp = read_sp(); 105 regs.elr = read_pc(); 106 107 dump_core_stack(®s); 108 } 109