xref: /rk3399_rockchip-uboot/arch/arm/lib/stacktrace_64.c (revision 87e4c6020eff05133e40ab8b7b0e37e6a2be37e4)
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(&regs);
108 }
109