]>
Commit | Line | Data |
---|---|---|
affae2bf WD |
1 | /* |
2 | * linux/arch/ppc/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 | * See file CREDITS for list of people who contributed to this | |
13 | * project. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or | |
16 | * modify it under the terms of the GNU General Public License as | |
17 | * published by the Free Software Foundation; either version 2 of | |
18 | * the License, or (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
28 | * MA 02111-1307 USA | |
29 | */ | |
30 | ||
31 | /* | |
32 | * This file handles the architecture-dependent parts of hardware exceptions | |
33 | */ | |
34 | ||
35 | #include <common.h> | |
36 | #include <command.h> | |
37 | #include <asm/processor.h> | |
38 | ||
efa35cf1 GB |
39 | DECLARE_GLOBAL_DATA_PTR; |
40 | ||
3a1ed1e1 | 41 | #if defined(CONFIG_CMD_KGDB) |
affae2bf WD |
42 | int (*debugger_exception_handler)(struct pt_regs *) = 0; |
43 | #endif | |
44 | ||
45 | /* Returns 0 if exception not found and fixup otherwise. */ | |
46 | extern unsigned long search_exception_table(unsigned long); | |
47 | ||
48 | /* THIS NEEDS CHANGING to use the board info structure. | |
49 | */ | |
efa35cf1 | 50 | #define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize) |
affae2bf WD |
51 | |
52 | static __inline__ void set_tsr(unsigned long val) | |
53 | { | |
54 | #if defined(CONFIG_440) | |
55 | asm volatile("mtspr 0x150, %0" : : "r" (val)); | |
56 | #else | |
57 | asm volatile("mttsr %0" : : "r" (val)); | |
58 | #endif | |
59 | } | |
60 | ||
61 | static __inline__ unsigned long get_esr(void) | |
62 | { | |
63 | unsigned long val; | |
64 | ||
65 | #if defined(CONFIG_440) | |
66 | asm volatile("mfspr %0, 0x03e" : "=r" (val) :); | |
67 | #else | |
68 | asm volatile("mfesr %0" : "=r" (val) :); | |
69 | #endif | |
70 | return val; | |
71 | } | |
72 | ||
73 | #define ESR_MCI 0x80000000 | |
74 | #define ESR_PIL 0x08000000 | |
75 | #define ESR_PPR 0x04000000 | |
76 | #define ESR_PTR 0x02000000 | |
77 | #define ESR_DST 0x00800000 | |
78 | #define ESR_DIZ 0x00400000 | |
79 | #define ESR_U0F 0x00008000 | |
80 | ||
3a1ed1e1 | 81 | #if defined(CONFIG_CMD_BEDBUG) |
affae2bf WD |
82 | extern void do_bedbug_breakpoint(struct pt_regs *); |
83 | #endif | |
84 | ||
85 | /* | |
86 | * Trap & Exception support | |
87 | */ | |
88 | ||
89 | void | |
90 | print_backtrace(unsigned long *sp) | |
91 | { | |
83b4cfa3 WD |
92 | int cnt = 0; |
93 | unsigned long i; | |
94 | ||
95 | printf("Call backtrace: "); | |
96 | while (sp) { | |
97 | if ((uint)sp > END_OF_MEM) | |
98 | break; | |
99 | ||
100 | i = sp[1]; | |
101 | if (cnt++ % 7 == 0) | |
102 | printf("\n"); | |
103 | printf("%08lX ", i); | |
104 | if (cnt > 32) break; | |
105 | sp = (unsigned long *)*sp; | |
106 | } | |
107 | printf("\n"); | |
affae2bf WD |
108 | } |
109 | ||
110 | void show_regs(struct pt_regs * regs) | |
111 | { | |
112 | int i; | |
113 | ||
efa35cf1 | 114 | printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DEAR: %08lX\n", |
affae2bf WD |
115 | regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); |
116 | printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", | |
117 | regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, | |
118 | regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, | |
119 | regs->msr&MSR_IR ? 1 : 0, | |
120 | regs->msr&MSR_DR ? 1 : 0); | |
121 | ||
122 | printf("\n"); | |
123 | for (i = 0; i < 32; i++) { | |
83b4cfa3 | 124 | if ((i % 8) == 0) { |
affae2bf WD |
125 | printf("GPR%02d: ", i); |
126 | } | |
127 | ||
128 | printf("%08lX ", regs->gpr[i]); | |
83b4cfa3 | 129 | if ((i % 8) == 7) { |
affae2bf WD |
130 | printf("\n"); |
131 | } | |
132 | } | |
133 | } | |
134 | ||
135 | ||
136 | void | |
137 | _exception(int signr, struct pt_regs *regs) | |
138 | { | |
139 | show_regs(regs); | |
140 | print_backtrace((unsigned long *)regs->gpr[1]); | |
efa35cf1 | 141 | panic("Exception"); |
affae2bf WD |
142 | } |
143 | ||
144 | void | |
145 | MachineCheckException(struct pt_regs *regs) | |
146 | { | |
efa35cf1 | 147 | unsigned long fixup, val; |
a1bd6200 NG |
148 | #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) |
149 | u32 value2; | |
27a528fb SR |
150 | int corr_ecc = 0; |
151 | int uncorr_ecc = 0; | |
a1bd6200 | 152 | #endif |
83b4cfa3 | 153 | |
affae2bf WD |
154 | if ((fixup = search_exception_table(regs->nip)) != 0) { |
155 | regs->nip = fixup; | |
c9240981 GB |
156 | val = mfspr(MCSR); |
157 | /* Clear MCSR */ | |
9ca8d79d | 158 | mtspr(SPRN_MCSR, val); |
affae2bf WD |
159 | return; |
160 | } | |
161 | ||
3a1ed1e1 | 162 | #if defined(CONFIG_CMD_KGDB) |
affae2bf WD |
163 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
164 | return; | |
165 | #endif | |
166 | ||
efa35cf1 | 167 | printf("Machine Check Exception.\n"); |
affae2bf | 168 | printf("Caused by (from msr): "); |
efa35cf1 GB |
169 | printf("regs %p ", regs); |
170 | ||
171 | val = get_esr(); | |
172 | ||
c821b5f1 | 173 | #if !defined(CONFIG_440) && !defined(CONFIG_405EX) |
efa35cf1 GB |
174 | if (val& ESR_IMCP) { |
175 | printf("Instruction"); | |
176 | mtspr(ESR, val & ~ESR_IMCP); | |
83b4cfa3 | 177 | } else { |
efa35cf1 | 178 | printf("Data"); |
83b4cfa3 | 179 | } |
efa35cf1 GB |
180 | printf(" machine check.\n"); |
181 | ||
c821b5f1 | 182 | #elif defined(CONFIG_440) || defined(CONFIG_405EX) |
efa35cf1 GB |
183 | if (val& ESR_IMCP){ |
184 | printf("Instruction Synchronous Machine Check exception\n"); | |
185 | mtspr(SPRN_ESR, val & ~ESR_IMCP); | |
83b4cfa3 | 186 | } else { |
efa35cf1 GB |
187 | val = mfspr(MCSR); |
188 | if (val & MCSR_IB) | |
189 | printf("Instruction Read PLB Error\n"); | |
c821b5f1 | 190 | #if defined(CONFIG_440) |
efa35cf1 GB |
191 | if (val & MCSR_DRB) |
192 | printf("Data Read PLB Error\n"); | |
193 | if (val & MCSR_DWB) | |
194 | printf("Data Write PLB Error\n"); | |
c821b5f1 GE |
195 | #else |
196 | if (val & MCSR_DB) | |
197 | printf("Data PLB Error\n"); | |
198 | #endif | |
efa35cf1 GB |
199 | if (val & MCSR_TLBP) |
200 | printf("TLB Parity Error\n"); | |
201 | if (val & MCSR_ICP){ | |
202 | /*flush_instruction_cache(); */ | |
203 | printf("I-Cache Parity Error\n"); | |
204 | } | |
205 | if (val & MCSR_DCSP) | |
206 | printf("D-Cache Search Parity Error\n"); | |
207 | if (val & MCSR_DCFP) | |
208 | printf("D-Cache Flush Parity Error\n"); | |
209 | if (val & MCSR_IMPE) | |
210 | printf("Machine Check exception is imprecise\n"); | |
211 | ||
212 | /* Clear MCSR */ | |
213 | mtspr(SPRN_MCSR, val); | |
214 | } | |
a1bd6200 NG |
215 | #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) |
216 | mfsdram(DDR0_00, val) ; | |
217 | printf("DDR0: DDR0_00 %p\n", val); | |
218 | val = (val >> 16) & 0xff; | |
219 | if (val & 0x80) | |
220 | printf("DDR0: At least one interrupt active\n"); | |
221 | if (val & 0x40) | |
222 | printf("DDR0: DRAM initialization complete.\n"); | |
27a528fb | 223 | if (val & 0x20) { |
a1bd6200 | 224 | printf("DDR0: Multiple uncorrectable ECC events.\n"); |
27a528fb SR |
225 | uncorr_ecc = 1; |
226 | } | |
227 | if (val & 0x10) { | |
a1bd6200 | 228 | printf("DDR0: Single uncorrectable ECC event.\n"); |
27a528fb SR |
229 | uncorr_ecc = 1; |
230 | } | |
231 | if (val & 0x08) { | |
a1bd6200 | 232 | printf("DDR0: Multiple correctable ECC events.\n"); |
27a528fb SR |
233 | corr_ecc = 1; |
234 | } | |
235 | if (val & 0x04) { | |
a1bd6200 | 236 | printf("DDR0: Single correctable ECC event.\n"); |
27a528fb SR |
237 | corr_ecc = 1; |
238 | } | |
a1bd6200 NG |
239 | if (val & 0x02) |
240 | printf("Multiple accesses outside the defined" | |
241 | " physical memory space detected\n"); | |
242 | if (val & 0x01) | |
243 | printf("DDR0: Single access outside the defined" | |
244 | " physical memory space detected.\n"); | |
245 | ||
246 | mfsdram(DDR0_01, val); | |
247 | val = (val >> 8) & 0x7; | |
248 | switch (val ) { | |
249 | case 0: | |
250 | printf("DDR0: Write Out-of-Range command\n"); | |
251 | break; | |
252 | case 1: | |
253 | printf("DDR0: Read Out-of-Range command\n"); | |
254 | break; | |
255 | case 2: | |
256 | printf("DDR0: Masked write Out-of-Range command\n"); | |
257 | break; | |
258 | case 4: | |
259 | printf("DDR0: Wrap write Out-of-Range command\n"); | |
260 | break; | |
261 | case 5: | |
262 | printf("DDR0: Wrap read Out-of-Range command\n"); | |
263 | break; | |
264 | default: | |
265 | mfsdram(DDR0_01, value2); | |
266 | printf("DDR0: No DDR0 error know 0x%x %p\n", val, value2); | |
267 | } | |
268 | mfsdram(DDR0_23, val); | |
27a528fb | 269 | if (((val >> 16) & 0xff) && corr_ecc) |
a1bd6200 NG |
270 | printf("DDR0: Syndrome for correctable ECC event 0x%x\n", |
271 | (val >> 16) & 0xff); | |
272 | mfsdram(DDR0_23, val); | |
27a528fb | 273 | if (((val >> 8) & 0xff) && uncorr_ecc) |
a1bd6200 NG |
274 | printf("DDR0: Syndrome for uncorrectable ECC event 0x%x\n", |
275 | (val >> 8) & 0xff); | |
276 | mfsdram(DDR0_33, val); | |
277 | if (val) | |
278 | printf("DDR0: Address of command that caused an " | |
279 | "Out-of-Range interrupt %p\n", val); | |
280 | mfsdram(DDR0_34, val); | |
27a528fb | 281 | if (val && uncorr_ecc) |
a1bd6200 NG |
282 | printf("DDR0: Address of uncorrectable ECC event %p\n", val); |
283 | mfsdram(DDR0_35, val); | |
27a528fb | 284 | if (val && uncorr_ecc) |
a1bd6200 NG |
285 | printf("DDR0: Address of uncorrectable ECC event %p\n", val); |
286 | mfsdram(DDR0_36, val); | |
27a528fb | 287 | if (val && uncorr_ecc) |
a1bd6200 NG |
288 | printf("DDR0: Data of uncorrectable ECC event 0x%08x\n", val); |
289 | mfsdram(DDR0_37, val); | |
27a528fb | 290 | if (val && uncorr_ecc) |
a1bd6200 NG |
291 | printf("DDR0: Data of uncorrectable ECC event 0x%08x\n", val); |
292 | mfsdram(DDR0_38, val); | |
27a528fb | 293 | if (val && corr_ecc) |
a1bd6200 NG |
294 | printf("DDR0: Address of correctable ECC event %p\n", val); |
295 | mfsdram(DDR0_39, val); | |
27a528fb | 296 | if (val && corr_ecc) |
a1bd6200 NG |
297 | printf("DDR0: Address of correctable ECC event %p\n", val); |
298 | mfsdram(DDR0_40, val); | |
27a528fb | 299 | if (val && corr_ecc) |
a1bd6200 NG |
300 | printf("DDR0: Data of correctable ECC event 0x%08x\n", val); |
301 | mfsdram(DDR0_41, val); | |
27a528fb | 302 | if (val && corr_ecc) |
a1bd6200 NG |
303 | printf("DDR0: Data of correctable ECC event 0x%08x\n", val); |
304 | #endif /* CONFIG_440EPX */ | |
305 | #endif /* CONFIG_440 */ | |
affae2bf WD |
306 | show_regs(regs); |
307 | print_backtrace((unsigned long *)regs->gpr[1]); | |
308 | panic("machine check"); | |
309 | } | |
310 | ||
311 | void | |
312 | AlignmentException(struct pt_regs *regs) | |
313 | { | |
3a1ed1e1 | 314 | #if defined(CONFIG_CMD_KGDB) |
affae2bf WD |
315 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
316 | return; | |
317 | #endif | |
318 | ||
319 | show_regs(regs); | |
320 | print_backtrace((unsigned long *)regs->gpr[1]); | |
321 | panic("Alignment Exception"); | |
322 | } | |
323 | ||
324 | void | |
325 | ProgramCheckException(struct pt_regs *regs) | |
326 | { | |
8bde7f77 | 327 | long esr_val; |
affae2bf | 328 | |
3a1ed1e1 | 329 | #if defined(CONFIG_CMD_KGDB) |
affae2bf WD |
330 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
331 | return; | |
332 | #endif | |
333 | ||
334 | show_regs(regs); | |
335 | ||
8bde7f77 WD |
336 | esr_val = get_esr(); |
337 | if( esr_val & ESR_PIL ) | |
affae2bf | 338 | printf( "** Illegal Instruction **\n" ); |
8bde7f77 | 339 | else if( esr_val & ESR_PPR ) |
affae2bf | 340 | printf( "** Privileged Instruction **\n" ); |
8bde7f77 | 341 | else if( esr_val & ESR_PTR ) |
affae2bf WD |
342 | printf( "** Trap Instruction **\n" ); |
343 | ||
344 | print_backtrace((unsigned long *)regs->gpr[1]); | |
345 | panic("Program Check Exception"); | |
346 | } | |
347 | ||
348 | void | |
efa35cf1 | 349 | DecrementerPITException(struct pt_regs *regs) |
affae2bf | 350 | { |
8bde7f77 WD |
351 | /* |
352 | * Reset PIT interrupt | |
353 | */ | |
354 | set_tsr(0x08000000); | |
355 | ||
356 | /* | |
357 | * Call timer_interrupt routine in interrupts.c | |
358 | */ | |
359 | timer_interrupt(NULL); | |
affae2bf WD |
360 | } |
361 | ||
362 | ||
363 | void | |
364 | UnknownException(struct pt_regs *regs) | |
365 | { | |
3a1ed1e1 | 366 | #if defined(CONFIG_CMD_KGDB) |
affae2bf WD |
367 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
368 | return; | |
369 | #endif | |
370 | ||
371 | printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", | |
372 | regs->nip, regs->msr, regs->trap); | |
373 | _exception(0, regs); | |
374 | } | |
375 | ||
376 | void | |
377 | DebugException(struct pt_regs *regs) | |
378 | { | |
379 | printf("Debugger trap at @ %lx\n", regs->nip ); | |
380 | show_regs(regs); | |
3a1ed1e1 | 381 | #if defined(CONFIG_CMD_BEDBUG) |
affae2bf WD |
382 | do_bedbug_breakpoint( regs ); |
383 | #endif | |
384 | } | |
385 | ||
386 | /* Probe an address by reading. If not present, return -1, otherwise | |
387 | * return 0. | |
388 | */ | |
389 | int | |
390 | addr_probe(uint *addr) | |
391 | { | |
392 | #if 0 | |
393 | int retval; | |
394 | ||
395 | __asm__ __volatile__( \ | |
396 | "1: lwz %0,0(%1)\n" \ | |
83b4cfa3 WD |
397 | " eieio\n" \ |
398 | " li %0,0\n" \ | |
399 | "2:\n" \ | |
400 | ".section .fixup,\"ax\"\n" \ | |
401 | "3: li %0,-1\n" \ | |
402 | " b 2b\n" \ | |
403 | ".section __ex_table,\"a\"\n" \ | |
404 | " .align 2\n" \ | |
405 | " .long 1b,3b\n" \ | |
406 | ".text" \ | |
407 | : "=r" (retval) : "r"(addr)); | |
affae2bf WD |
408 | |
409 | return (retval); | |
410 | #endif | |
411 | return 0; | |
412 | } |