]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/m68knommu/kernel/traps.c | |
3 | * | |
4 | * Copyright (C) 1993, 1994 by Hamish Macdonald | |
5 | * | |
6 | * 68040 fixes by Michael Rausch | |
7 | * 68040 fixes by Martin Apel | |
8 | * 68060 fixes by Roman Hodek | |
9 | * 68060 fixes by Jesper Skov | |
10 | * | |
11 | * This file is subject to the terms and conditions of the GNU General Public | |
12 | * License. See the file COPYING in the main directory of this archive | |
13 | * for more details. | |
14 | */ | |
15 | ||
16 | /* | |
17 | * Sets up all exception vectors | |
18 | */ | |
1da177e4 LT |
19 | #include <linux/sched.h> |
20 | #include <linux/signal.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/mm.h> | |
db81fb84 | 23 | #include <linux/module.h> |
1da177e4 LT |
24 | #include <linux/types.h> |
25 | #include <linux/a.out.h> | |
26 | #include <linux/user.h> | |
27 | #include <linux/string.h> | |
28 | #include <linux/linkage.h> | |
29 | #include <linux/init.h> | |
30 | #include <linux/ptrace.h> | |
31 | ||
32 | #include <asm/setup.h> | |
33 | #include <asm/fpu.h> | |
34 | #include <asm/system.h> | |
35 | #include <asm/uaccess.h> | |
36 | #include <asm/traps.h> | |
37 | #include <asm/pgtable.h> | |
38 | #include <asm/machdep.h> | |
39 | #include <asm/siginfo.h> | |
40 | ||
db81fb84 | 41 | static char const * const vec_names[] = { |
1da177e4 LT |
42 | "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", |
43 | "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", | |
44 | "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", | |
45 | "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", | |
46 | "FORMAT ERROR", "UNINITIALIZED INTERRUPT", | |
47 | "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", | |
48 | "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", | |
49 | "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", | |
50 | "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", | |
51 | "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", | |
52 | "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", | |
53 | "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", | |
54 | "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", | |
55 | "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", | |
56 | "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15", | |
57 | "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", | |
58 | "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", | |
59 | "FPCP UNSUPPORTED OPERATION", | |
60 | "MMU CONFIGURATION ERROR" | |
61 | }; | |
62 | ||
63 | void __init trap_init(void) | |
64 | { | |
1da177e4 LT |
65 | } |
66 | ||
67 | void die_if_kernel(char *str, struct pt_regs *fp, int nr) | |
68 | { | |
69 | if (!(fp->sr & PS_S)) | |
70 | return; | |
71 | ||
72 | console_verbose(); | |
73 | printk(KERN_EMERG "%s: %08x\n",str,nr); | |
74 | printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", | |
75 | fp->pc, fp->sr, fp, fp->a2); | |
76 | printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | |
77 | fp->d0, fp->d1, fp->d2, fp->d3); | |
78 | printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | |
79 | fp->d4, fp->d5, fp->a0, fp->a1); | |
80 | ||
81 | printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", | |
82 | current->comm, current->pid, PAGE_SIZE+(unsigned long)current); | |
a4c8b915 | 83 | show_stack(NULL, (unsigned long *)(fp + 1)); |
bcdcd8e7 | 84 | add_taint(TAINT_DIE); |
1da177e4 LT |
85 | do_exit(SIGSEGV); |
86 | } | |
87 | ||
88 | asmlinkage void buserr_c(struct frame *fp) | |
89 | { | |
90 | /* Only set esp0 if coming from user mode */ | |
91 | if (user_mode(&fp->ptregs)) | |
92 | current->thread.esp0 = (unsigned long) fp; | |
93 | ||
bb28632c | 94 | #if defined(DEBUG) |
1da177e4 LT |
95 | printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format); |
96 | #endif | |
97 | ||
98 | die_if_kernel("bad frame format",&fp->ptregs,0); | |
bb28632c | 99 | #if defined(DEBUG) |
1da177e4 LT |
100 | printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); |
101 | #endif | |
102 | force_sig(SIGSEGV, current); | |
103 | } | |
104 | ||
105 | ||
106 | int kstack_depth_to_print = 48; | |
107 | ||
db81fb84 | 108 | void show_stack(struct task_struct *task, unsigned long *stack) |
1da177e4 | 109 | { |
db81fb84 | 110 | unsigned long *endstack, addr; |
1da177e4 LT |
111 | extern char _start, _etext; |
112 | int i; | |
113 | ||
db81fb84 GU |
114 | if (!stack) { |
115 | if (task) | |
116 | stack = (unsigned long *)task->thread.ksp; | |
117 | else | |
118 | stack = (unsigned long *)&stack; | |
119 | } | |
1da177e4 | 120 | |
db81fb84 | 121 | addr = (unsigned long) stack; |
1da177e4 LT |
122 | endstack = (unsigned long *) PAGE_ALIGN(addr); |
123 | ||
124 | printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); | |
125 | for (i = 0; i < kstack_depth_to_print; i++) { | |
126 | if (stack + 1 > endstack) | |
127 | break; | |
128 | if (i % 8 == 0) | |
329237c1 GU |
129 | printk("\n" KERN_EMERG " "); |
130 | printk(" %08lx", *stack++); | |
1da177e4 | 131 | } |
329237c1 | 132 | printk("\n"); |
1da177e4 | 133 | |
329237c1 | 134 | printk(KERN_EMERG "Call Trace:"); |
1da177e4 LT |
135 | i = 0; |
136 | while (stack + 1 <= endstack) { | |
137 | addr = *stack++; | |
138 | /* | |
139 | * If the address is either in the text segment of the | |
140 | * kernel, or in the region which contains vmalloc'ed | |
141 | * memory, it *may* be the address of a calling | |
142 | * routine; if so, print it so that someone tracing | |
143 | * down the cause of the crash will be able to figure | |
144 | * out the call path that was taken. | |
145 | */ | |
146 | if (((addr >= (unsigned long) &_start) && | |
147 | (addr <= (unsigned long) &_etext))) { | |
148 | if (i % 4 == 0) | |
329237c1 GU |
149 | printk("\n" KERN_EMERG " "); |
150 | printk(" [<%08lx>]", addr); | |
1da177e4 LT |
151 | i++; |
152 | } | |
153 | } | |
329237c1 | 154 | printk("\n"); |
1da177e4 LT |
155 | } |
156 | ||
157 | void bad_super_trap(struct frame *fp) | |
158 | { | |
159 | console_verbose(); | |
bf0059b2 | 160 | if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) |
1da177e4 LT |
161 | printk (KERN_WARNING "*** %s *** FORMAT=%X\n", |
162 | vec_names[(fp->ptregs.vector) >> 2], | |
163 | fp->ptregs.format); | |
164 | else | |
165 | printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n", | |
166 | (fp->ptregs.vector) >> 2, | |
167 | fp->ptregs.format); | |
168 | printk (KERN_WARNING "Current process id is %d\n", current->pid); | |
169 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | |
170 | } | |
171 | ||
172 | asmlinkage void trap_c(struct frame *fp) | |
173 | { | |
174 | int sig; | |
175 | siginfo_t info; | |
176 | ||
177 | if (fp->ptregs.sr & PS_S) { | |
178 | if ((fp->ptregs.vector >> 2) == VEC_TRACE) { | |
179 | /* traced a trapping instruction */ | |
180 | current->ptrace |= PT_DTRACE; | |
181 | } else | |
182 | bad_super_trap(fp); | |
183 | return; | |
184 | } | |
185 | ||
186 | /* send the appropriate signal to the user program */ | |
187 | switch ((fp->ptregs.vector) >> 2) { | |
188 | case VEC_ADDRERR: | |
189 | info.si_code = BUS_ADRALN; | |
190 | sig = SIGBUS; | |
191 | break; | |
192 | case VEC_ILLEGAL: | |
193 | case VEC_LINE10: | |
194 | case VEC_LINE11: | |
195 | info.si_code = ILL_ILLOPC; | |
196 | sig = SIGILL; | |
197 | break; | |
198 | case VEC_PRIV: | |
199 | info.si_code = ILL_PRVOPC; | |
200 | sig = SIGILL; | |
201 | break; | |
202 | case VEC_COPROC: | |
203 | info.si_code = ILL_COPROC; | |
204 | sig = SIGILL; | |
205 | break; | |
206 | case VEC_TRAP1: /* gdbserver breakpoint */ | |
207 | fp->ptregs.pc -= 2; | |
208 | info.si_code = TRAP_TRACE; | |
209 | sig = SIGTRAP; | |
210 | break; | |
211 | case VEC_TRAP2: | |
212 | case VEC_TRAP3: | |
213 | case VEC_TRAP4: | |
214 | case VEC_TRAP5: | |
215 | case VEC_TRAP6: | |
216 | case VEC_TRAP7: | |
217 | case VEC_TRAP8: | |
218 | case VEC_TRAP9: | |
219 | case VEC_TRAP10: | |
220 | case VEC_TRAP11: | |
221 | case VEC_TRAP12: | |
222 | case VEC_TRAP13: | |
223 | case VEC_TRAP14: | |
224 | info.si_code = ILL_ILLTRP; | |
225 | sig = SIGILL; | |
226 | break; | |
227 | case VEC_FPBRUC: | |
228 | case VEC_FPOE: | |
229 | case VEC_FPNAN: | |
230 | info.si_code = FPE_FLTINV; | |
231 | sig = SIGFPE; | |
232 | break; | |
233 | case VEC_FPIR: | |
234 | info.si_code = FPE_FLTRES; | |
235 | sig = SIGFPE; | |
236 | break; | |
237 | case VEC_FPDIVZ: | |
238 | info.si_code = FPE_FLTDIV; | |
239 | sig = SIGFPE; | |
240 | break; | |
241 | case VEC_FPUNDER: | |
242 | info.si_code = FPE_FLTUND; | |
243 | sig = SIGFPE; | |
244 | break; | |
245 | case VEC_FPOVER: | |
246 | info.si_code = FPE_FLTOVF; | |
247 | sig = SIGFPE; | |
248 | break; | |
249 | case VEC_ZERODIV: | |
250 | info.si_code = FPE_INTDIV; | |
251 | sig = SIGFPE; | |
252 | break; | |
253 | case VEC_CHK: | |
254 | case VEC_TRAP: | |
255 | info.si_code = FPE_INTOVF; | |
256 | sig = SIGFPE; | |
257 | break; | |
258 | case VEC_TRACE: /* ptrace single step */ | |
259 | info.si_code = TRAP_TRACE; | |
260 | sig = SIGTRAP; | |
261 | break; | |
262 | case VEC_TRAP15: /* breakpoint */ | |
263 | info.si_code = TRAP_BRKPT; | |
264 | sig = SIGTRAP; | |
265 | break; | |
266 | default: | |
267 | info.si_code = ILL_ILLOPC; | |
268 | sig = SIGILL; | |
269 | break; | |
270 | } | |
271 | info.si_signo = sig; | |
272 | info.si_errno = 0; | |
273 | switch (fp->ptregs.format) { | |
274 | default: | |
275 | info.si_addr = (void *) fp->ptregs.pc; | |
276 | break; | |
277 | case 2: | |
278 | info.si_addr = (void *) fp->un.fmt2.iaddr; | |
279 | break; | |
280 | case 7: | |
281 | info.si_addr = (void *) fp->un.fmt7.effaddr; | |
282 | break; | |
283 | case 9: | |
284 | info.si_addr = (void *) fp->un.fmt9.iaddr; | |
285 | break; | |
286 | case 10: | |
287 | info.si_addr = (void *) fp->un.fmta.daddr; | |
288 | break; | |
289 | case 11: | |
290 | info.si_addr = (void *) fp->un.fmtb.daddr; | |
291 | break; | |
292 | } | |
293 | force_sig_info (sig, &info, current); | |
294 | } | |
295 | ||
296 | asmlinkage void set_esp0(unsigned long ssp) | |
297 | { | |
298 | current->thread.esp0 = ssp; | |
299 | } | |
300 | ||
301 | ||
302 | /* | |
303 | * The architecture-independent backtrace generator | |
304 | */ | |
305 | void dump_stack(void) | |
306 | { | |
307 | unsigned long stack; | |
308 | ||
309 | show_stack(current, &stack); | |
310 | } | |
311 | ||
db81fb84 GU |
312 | EXPORT_SYMBOL(dump_stack); |
313 | ||
1da177e4 LT |
314 | #ifdef CONFIG_M68KFPU_EMU |
315 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | |
316 | { | |
317 | siginfo_t info; | |
318 | ||
319 | info.si_signo = signal; | |
320 | info.si_errno = 0; | |
321 | info.si_code = code; | |
322 | info.si_addr = addr; | |
323 | force_sig_info(signal, &info, current); | |
324 | } | |
325 | #endif |