]>
Commit | Line | Data |
---|---|---|
0db5bca8 | 1 | /* |
a47a12be | 2 | * linux/arch/powerpc/kernel/traps.c |
0db5bca8 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) | |
8 | * | |
9 | * (C) Copyright 2000 | |
10 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
11 | * | |
1a459660 | 12 | * SPDX-License-Identifier: GPL-2.0+ |
0db5bca8 WD |
13 | */ |
14 | ||
15 | /* | |
16 | * This file handles the architecture-dependent parts of hardware exceptions | |
17 | */ | |
18 | ||
19 | #include <common.h> | |
20 | #include <command.h> | |
e39bf1e2 | 21 | #include <kgdb.h> |
0db5bca8 WD |
22 | #include <asm/processor.h> |
23 | ||
4431283c | 24 | #if defined(CONFIG_CMD_BEDBUG) |
0db5bca8 WD |
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 0x0001000 | |
34 | ||
35 | ||
36 | /* | |
37 | * Print stack backtrace | |
38 | */ | |
20051f2a | 39 | static void print_backtrace(unsigned long *sp) |
0db5bca8 WD |
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 | /* | |
60 | * Print current registers | |
61 | */ | |
20051f2a | 62 | void show_regs(struct pt_regs *regs) |
0db5bca8 WD |
63 | { |
64 | int i; | |
65 | printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n", | |
66 | regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); | |
67 | printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", | |
68 | regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, | |
69 | regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, | |
70 | regs->msr&MSR_IR ? 1 : 0, | |
71 | regs->msr&MSR_DR ? 1 : 0); | |
72 | ||
73 | printf("\n"); | |
74 | for (i = 0; i < 32; i++) { | |
75 | if ((i % 8) == 0) | |
76 | { | |
77 | printf("GPR%02d: ", i); | |
78 | } | |
79 | ||
80 | printf("%08lX ", regs->gpr[i]); | |
81 | if ((i % 8) == 7) | |
82 | { | |
83 | printf("\n"); | |
84 | } | |
85 | } | |
86 | } | |
87 | ||
88 | ||
89 | /* | |
90 | * General exception handler routine | |
91 | */ | |
20051f2a | 92 | static void _exception(int signr, struct pt_regs *regs) |
0db5bca8 WD |
93 | { |
94 | show_regs(regs); | |
95 | print_backtrace((unsigned long *)regs->gpr[1]); | |
96 | panic("Exception in kernel pc %lx signal %d",regs->nip,signr); | |
97 | } | |
98 | ||
99 | /* | |
100 | * Machine check exception handler routine | |
101 | */ | |
102 | void MachineCheckException(struct pt_regs *regs) | |
103 | { | |
104 | unsigned long fixup; | |
105 | ||
106 | /* Probing PCI using config cycles cause this exception | |
107 | * when a device is not present. Catch it and return to | |
108 | * the PCI exception handler. | |
109 | */ | |
110 | if ((fixup = search_exception_table(regs->nip)) != 0) { | |
111 | regs->nip = fixup; | |
112 | return; | |
113 | } | |
114 | ||
4431283c | 115 | #if defined(CONFIG_CMD_KGDB) |
0db5bca8 WD |
116 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
117 | return; | |
118 | #endif | |
119 | ||
120 | printf("Machine check in kernel mode.\n"); | |
121 | printf("Caused by (from msr): "); | |
122 | printf("regs %p ",regs); | |
63e73c9a WD |
123 | switch( regs->msr & 0x000F0000) { |
124 | case (0x80000000>>12): | |
0db5bca8 WD |
125 | printf("Machine check signal\n"); |
126 | break; | |
63e73c9a | 127 | case (0x80000000>>13): |
0db5bca8 WD |
128 | printf("Transfer error ack signal\n"); |
129 | break; | |
63e73c9a | 130 | case (0x80000000>>14): |
0db5bca8 WD |
131 | printf("Data parity signal\n"); |
132 | break; | |
63e73c9a | 133 | case (0x80000000>>15): |
0db5bca8 WD |
134 | printf("Address parity signal\n"); |
135 | break; | |
136 | default: | |
137 | printf("Unknown values in msr\n"); | |
138 | } | |
139 | show_regs(regs); | |
140 | print_backtrace((unsigned long *)regs->gpr[1]); | |
141 | panic("machine check"); | |
142 | } | |
143 | ||
144 | /* | |
145 | * Alignment exception handler routine | |
146 | */ | |
147 | void AlignmentException(struct pt_regs *regs) | |
148 | { | |
4431283c | 149 | #if defined(CONFIG_CMD_KGDB) |
0db5bca8 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("Alignment Exception"); | |
156 | } | |
157 | ||
158 | /* | |
159 | * Program check exception handler routine | |
160 | */ | |
161 | void ProgramCheckException(struct pt_regs *regs) | |
162 | { | |
4431283c | 163 | #if defined(CONFIG_CMD_KGDB) |
0db5bca8 WD |
164 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
165 | return; | |
166 | #endif | |
167 | show_regs(regs); | |
168 | print_backtrace((unsigned long *)regs->gpr[1]); | |
169 | panic("Program Check Exception"); | |
170 | } | |
171 | ||
172 | /* | |
173 | * Software emulation exception handler routine | |
174 | */ | |
175 | void SoftEmuException(struct pt_regs *regs) | |
176 | { | |
4431283c | 177 | #if defined(CONFIG_CMD_KGDB) |
0db5bca8 WD |
178 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
179 | return; | |
180 | #endif | |
181 | show_regs(regs); | |
182 | print_backtrace((unsigned long *)regs->gpr[1]); | |
183 | panic("Software Emulation Exception"); | |
184 | } | |
185 | ||
186 | ||
187 | /* | |
188 | * Unknown exception handler routine | |
189 | */ | |
190 | void UnknownException(struct pt_regs *regs) | |
191 | { | |
4431283c | 192 | #if defined(CONFIG_CMD_KGDB) |
0db5bca8 WD |
193 | if (debugger_exception_handler && (*debugger_exception_handler)(regs)) |
194 | return; | |
195 | #endif | |
196 | printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", | |
197 | regs->nip, regs->msr, regs->trap); | |
198 | _exception(0, regs); | |
199 | } | |
200 | ||
201 | /* | |
202 | * Debug exception handler routine | |
203 | */ | |
204 | void DebugException(struct pt_regs *regs) | |
205 | { | |
206 | printf("Debugger trap at @ %lx\n", regs->nip ); | |
53677ef1 | 207 | show_regs(regs); |
4431283c | 208 | #if defined(CONFIG_CMD_BEDBUG) |
53677ef1 | 209 | do_bedbug_breakpoint( regs ); |
0db5bca8 WD |
210 | #endif |
211 | } |