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
read_fp(void)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
read_lr(void)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
read_pc(void)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 */
read_sp(void)42 static __always_inline uint64_t read_sp(void)
43 {
44 return gd->start_addr_sp - (CONFIG_SYS_STACK_SIZE / 2);
45 }
46
walk_stackframe(struct stackframe * frame)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
dump_core_stack(struct pt_regs * regs)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
dump_stack(void)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