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