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