xref: /OK3568_Linux_fs/u-boot/arch/arm/lib/stacktrace_64.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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(&regs);
115 }
116