xref: /openbmc/u-boot/arch/powerpc/cpu/mpc8xx/traps.c (revision ad5b5801)
1 /*
2  * linux/arch/powerpc/kernel/traps.c
3  *
4  * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
5  *
6  * Modified by Cort Dougan (cort@cs.nmt.edu)
7  * and Paul Mackerras (paulus@cs.anu.edu.au)
8  *
9  * (C) Copyright 2000
10  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
11  *
12  * SPDX-License-Identifier:	GPL-2.0+
13  */
14 
15 /*
16  * This file handles the architecture-dependent parts of hardware exceptions
17  */
18 
19 #include <common.h>
20 #include <command.h>
21 #include <kgdb.h>
22 #include <asm/processor.h>
23 
24 #if defined(CONFIG_CMD_BEDBUG)
25 extern void do_bedbug_breakpoint(struct pt_regs *);
26 #endif
27 
28 /* Returns 0 if exception not found and fixup otherwise.  */
29 extern unsigned long search_exception_table(unsigned long);
30 
31 /* THIS NEEDS CHANGING to use the board info structure.
32 */
33 #define END_OF_MEM	0x02000000
34 
35 /*
36  * Trap & Exception support
37  */
38 
39 static void print_backtrace(unsigned long *sp)
40 {
41 	int cnt = 0;
42 	unsigned long i;
43 
44 	printf("Call backtrace: ");
45 	while (sp) {
46 		if ((uint)sp > END_OF_MEM)
47 			break;
48 
49 		i = sp[1];
50 		if (cnt++ % 7 == 0)
51 			printf("\n");
52 		printf("%08lX ", i);
53 		if (cnt > 32) break;
54 		sp = (unsigned long *)*sp;
55 	}
56 	printf("\n");
57 }
58 
59 void show_regs(struct pt_regs *regs)
60 {
61 	int i;
62 
63 	printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
64 	       regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
65 	printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
66 	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
67 	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
68 	       regs->msr&MSR_IR ? 1 : 0,
69 	       regs->msr&MSR_DR ? 1 : 0);
70 
71 	printf("\n");
72 	for (i = 0;  i < 32;  i++) {
73 		if ((i % 8) == 0)
74 		{
75 			printf("GPR%02d: ", i);
76 		}
77 
78 		printf("%08lX ", regs->gpr[i]);
79 		if ((i % 8) == 7)
80 		{
81 			printf("\n");
82 		}
83 	}
84 }
85 
86 
87 static void _exception(int signr, struct pt_regs *regs)
88 {
89 	show_regs(regs);
90 	print_backtrace((unsigned long *)regs->gpr[1]);
91 	panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
92 }
93 
94 void MachineCheckException(struct pt_regs *regs)
95 {
96 	unsigned long fixup;
97 
98 	/* Probing PCI using config cycles cause this exception
99 	 * when a device is not present.  Catch it and return to
100 	 * the PCI exception handler.
101 	 */
102 	if ((fixup = search_exception_table(regs->nip)) != 0) {
103 		regs->nip = fixup;
104 		return;
105 	}
106 
107 #if defined(CONFIG_CMD_KGDB)
108 	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
109 		return;
110 #endif
111 
112 	printf("Machine check in kernel mode.\n");
113 	printf("Caused by (from msr): ");
114 	printf("regs %p ",regs);
115 	switch( regs->msr & 0x000F0000) {
116 	case (0x80000000>>12):
117 		printf("Machine check signal - probably due to mm fault\n"
118 			"with mmu off\n");
119 		break;
120 	case (0x80000000>>13):
121 		printf("Transfer error ack signal\n");
122 		break;
123 	case (0x80000000>>14):
124 		printf("Data parity signal\n");
125 		break;
126 	case (0x80000000>>15):
127 		printf("Address parity signal\n");
128 		break;
129 	default:
130 		printf("Unknown values in msr\n");
131 	}
132 	show_regs(regs);
133 	print_backtrace((unsigned long *)regs->gpr[1]);
134 	panic("machine check");
135 }
136 
137 void AlignmentException(struct pt_regs *regs)
138 {
139 #if defined(CONFIG_CMD_KGDB)
140 	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
141 		return;
142 #endif
143 	show_regs(regs);
144 	print_backtrace((unsigned long *)regs->gpr[1]);
145 	panic("Alignment Exception");
146 }
147 
148 void ProgramCheckException(struct pt_regs *regs)
149 {
150 #if defined(CONFIG_CMD_KGDB)
151 	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
152 		return;
153 #endif
154 	show_regs(regs);
155 	print_backtrace((unsigned long *)regs->gpr[1]);
156 	panic("Program Check Exception");
157 }
158 
159 void SoftEmuException(struct pt_regs *regs)
160 {
161 #if defined(CONFIG_CMD_KGDB)
162 	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
163 		return;
164 #endif
165 	show_regs(regs);
166 	print_backtrace((unsigned long *)regs->gpr[1]);
167 	panic("Software Emulation Exception");
168 }
169 
170 
171 void UnknownException(struct pt_regs *regs)
172 {
173 #if defined(CONFIG_CMD_KGDB)
174 	if (debugger_exception_handler && (*debugger_exception_handler)(regs))
175 		return;
176 #endif
177 	printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
178 	       regs->nip, regs->msr, regs->trap);
179 	_exception(0, regs);
180 }
181 
182 void DebugException(struct pt_regs *regs)
183 {
184   printf("Debugger trap at @ %lx\n", regs->nip );
185   show_regs(regs);
186 #if defined(CONFIG_CMD_BEDBUG)
187   do_bedbug_breakpoint( regs );
188 #endif
189 }
190 
191 /* Probe an address by reading.  If not present, return -1, otherwise
192  * return 0.
193  */
194 int addr_probe(uint *addr)
195 {
196 #if 0
197 	int	retval;
198 
199 	__asm__ __volatile__(			\
200 		"1:	lwz %0,0(%1)\n"		\
201 		"	eieio\n"		\
202 		"	li %0,0\n"		\
203 		"2:\n"				\
204 		".section .fixup,\"ax\"\n"	\
205 		"3:	li %0,-1\n"		\
206 		"	b 2b\n"			\
207 		".section __ex_table,\"a\"\n"	\
208 		"	.align 2\n"		\
209 		"	.long 1b,3b\n"		\
210 		".text"				\
211 		: "=r" (retval) : "r"(addr));
212 
213 	return (retval);
214 #endif
215 	return 0;
216 }
217