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