diff options
Diffstat (limited to 'arch/m68k/kernel/traps_no.c')
-rw-r--r-- | arch/m68k/kernel/traps_no.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/arch/m68k/kernel/traps_no.c b/arch/m68k/kernel/traps_no.c new file mode 100644 index 00000000000..a768008dfd0 --- /dev/null +++ b/arch/m68k/kernel/traps_no.c | |||
@@ -0,0 +1,365 @@ | |||
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 | */ | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/signal.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/user.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/linkage.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/ptrace.h> | ||
30 | #include <linux/kallsyms.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 | |||
41 | static char const * const vec_names[] = { | ||
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 | { | ||
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); | ||
83 | show_stack(NULL, (unsigned long *)(fp + 1)); | ||
84 | add_taint(TAINT_DIE); | ||
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 | |||
94 | #if defined(DEBUG) | ||
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); | ||
99 | #if defined(DEBUG) | ||
100 | printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); | ||
101 | #endif | ||
102 | force_sig(SIGSEGV, current); | ||
103 | } | ||
104 | |||
105 | static void print_this_address(unsigned long addr, int i) | ||
106 | { | ||
107 | #ifdef CONFIG_KALLSYMS | ||
108 | printk(KERN_EMERG " [%08lx] ", addr); | ||
109 | print_symbol(KERN_CONT "%s\n", addr); | ||
110 | #else | ||
111 | if (i % 5) | ||
112 | printk(KERN_CONT " [%08lx] ", addr); | ||
113 | else | ||
114 | printk(KERN_EMERG " [%08lx] ", addr); | ||
115 | i++; | ||
116 | #endif | ||
117 | } | ||
118 | |||
119 | int kstack_depth_to_print = 48; | ||
120 | |||
121 | static void __show_stack(struct task_struct *task, unsigned long *stack) | ||
122 | { | ||
123 | unsigned long *endstack, addr; | ||
124 | #ifdef CONFIG_FRAME_POINTER | ||
125 | unsigned long *last_stack; | ||
126 | #endif | ||
127 | int i; | ||
128 | |||
129 | if (!stack) | ||
130 | stack = (unsigned long *)task->thread.ksp; | ||
131 | |||
132 | addr = (unsigned long) stack; | ||
133 | endstack = (unsigned long *) PAGE_ALIGN(addr); | ||
134 | |||
135 | printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); | ||
136 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
137 | if (stack + 1 + i > endstack) | ||
138 | break; | ||
139 | if (i % 8 == 0) | ||
140 | printk(KERN_EMERG " "); | ||
141 | printk(KERN_CONT " %08lx", *(stack + i)); | ||
142 | } | ||
143 | printk("\n"); | ||
144 | i = 0; | ||
145 | |||
146 | #ifdef CONFIG_FRAME_POINTER | ||
147 | printk(KERN_EMERG "Call Trace:\n"); | ||
148 | |||
149 | last_stack = stack - 1; | ||
150 | while (stack <= endstack && stack > last_stack) { | ||
151 | |||
152 | addr = *(stack + 1); | ||
153 | print_this_address(addr, i); | ||
154 | i++; | ||
155 | |||
156 | last_stack = stack; | ||
157 | stack = (unsigned long *)*stack; | ||
158 | } | ||
159 | printk("\n"); | ||
160 | #else | ||
161 | printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n"); | ||
162 | while (stack <= endstack) { | ||
163 | addr = *stack++; | ||
164 | /* | ||
165 | * If the address is either in the text segment of the kernel, | ||
166 | * or in a region which is occupied by a module then it *may* | ||
167 | * be the address of a calling routine; if so, print it so that | ||
168 | * someone tracing down the cause of the crash will be able to | ||
169 | * figure out the call path that was taken. | ||
170 | */ | ||
171 | if (__kernel_text_address(addr)) { | ||
172 | print_this_address(addr, i); | ||
173 | i++; | ||
174 | } | ||
175 | } | ||
176 | printk(KERN_CONT "\n"); | ||
177 | #endif | ||
178 | } | ||
179 | |||
180 | void bad_super_trap(struct frame *fp) | ||
181 | { | ||
182 | int vector = (fp->ptregs.vector >> 2) & 0xff; | ||
183 | |||
184 | console_verbose(); | ||
185 | if (vector < ARRAY_SIZE(vec_names)) | ||
186 | printk (KERN_WARNING "*** %s *** FORMAT=%X\n", | ||
187 | vec_names[vector], | ||
188 | fp->ptregs.format); | ||
189 | else | ||
190 | printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n", | ||
191 | vector, | ||
192 | fp->ptregs.format); | ||
193 | printk (KERN_WARNING "Current process id is %d\n", current->pid); | ||
194 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
195 | } | ||
196 | |||
197 | asmlinkage void trap_c(struct frame *fp) | ||
198 | { | ||
199 | int sig; | ||
200 | int vector = (fp->ptregs.vector >> 2) & 0xff; | ||
201 | siginfo_t info; | ||
202 | |||
203 | if (fp->ptregs.sr & PS_S) { | ||
204 | if (vector == VEC_TRACE) { | ||
205 | /* traced a trapping instruction */ | ||
206 | } else | ||
207 | bad_super_trap(fp); | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | /* send the appropriate signal to the user program */ | ||
212 | switch (vector) { | ||
213 | case VEC_ADDRERR: | ||
214 | info.si_code = BUS_ADRALN; | ||
215 | sig = SIGBUS; | ||
216 | break; | ||
217 | case VEC_ILLEGAL: | ||
218 | case VEC_LINE10: | ||
219 | case VEC_LINE11: | ||
220 | info.si_code = ILL_ILLOPC; | ||
221 | sig = SIGILL; | ||
222 | break; | ||
223 | case VEC_PRIV: | ||
224 | info.si_code = ILL_PRVOPC; | ||
225 | sig = SIGILL; | ||
226 | break; | ||
227 | case VEC_COPROC: | ||
228 | info.si_code = ILL_COPROC; | ||
229 | sig = SIGILL; | ||
230 | break; | ||
231 | case VEC_TRAP1: /* gdbserver breakpoint */ | ||
232 | fp->ptregs.pc -= 2; | ||
233 | info.si_code = TRAP_TRACE; | ||
234 | sig = SIGTRAP; | ||
235 | break; | ||
236 | case VEC_TRAP2: | ||
237 | case VEC_TRAP3: | ||
238 | case VEC_TRAP4: | ||
239 | case VEC_TRAP5: | ||
240 | case VEC_TRAP6: | ||
241 | case VEC_TRAP7: | ||
242 | case VEC_TRAP8: | ||
243 | case VEC_TRAP9: | ||
244 | case VEC_TRAP10: | ||
245 | case VEC_TRAP11: | ||
246 | case VEC_TRAP12: | ||
247 | case VEC_TRAP13: | ||
248 | case VEC_TRAP14: | ||
249 | info.si_code = ILL_ILLTRP; | ||
250 | sig = SIGILL; | ||
251 | break; | ||
252 | case VEC_FPBRUC: | ||
253 | case VEC_FPOE: | ||
254 | case VEC_FPNAN: | ||
255 | info.si_code = FPE_FLTINV; | ||
256 | sig = SIGFPE; | ||
257 | break; | ||
258 | case VEC_FPIR: | ||
259 | info.si_code = FPE_FLTRES; | ||
260 | sig = SIGFPE; | ||
261 | break; | ||
262 | case VEC_FPDIVZ: | ||
263 | info.si_code = FPE_FLTDIV; | ||
264 | sig = SIGFPE; | ||
265 | break; | ||
266 | case VEC_FPUNDER: | ||
267 | info.si_code = FPE_FLTUND; | ||
268 | sig = SIGFPE; | ||
269 | break; | ||
270 | case VEC_FPOVER: | ||
271 | info.si_code = FPE_FLTOVF; | ||
272 | sig = SIGFPE; | ||
273 | break; | ||
274 | case VEC_ZERODIV: | ||
275 | info.si_code = FPE_INTDIV; | ||
276 | sig = SIGFPE; | ||
277 | break; | ||
278 | case VEC_CHK: | ||
279 | case VEC_TRAP: | ||
280 | info.si_code = FPE_INTOVF; | ||
281 | sig = SIGFPE; | ||
282 | break; | ||
283 | case VEC_TRACE: /* ptrace single step */ | ||
284 | info.si_code = TRAP_TRACE; | ||
285 | sig = SIGTRAP; | ||
286 | break; | ||
287 | case VEC_TRAP15: /* breakpoint */ | ||
288 | info.si_code = TRAP_BRKPT; | ||
289 | sig = SIGTRAP; | ||
290 | break; | ||
291 | default: | ||
292 | info.si_code = ILL_ILLOPC; | ||
293 | sig = SIGILL; | ||
294 | break; | ||
295 | } | ||
296 | info.si_signo = sig; | ||
297 | info.si_errno = 0; | ||
298 | switch (fp->ptregs.format) { | ||
299 | default: | ||
300 | info.si_addr = (void *) fp->ptregs.pc; | ||
301 | break; | ||
302 | case 2: | ||
303 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
304 | break; | ||
305 | case 7: | ||
306 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
307 | break; | ||
308 | case 9: | ||
309 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
310 | break; | ||
311 | case 10: | ||
312 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
313 | break; | ||
314 | case 11: | ||
315 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
316 | break; | ||
317 | } | ||
318 | force_sig_info (sig, &info, current); | ||
319 | } | ||
320 | |||
321 | asmlinkage void set_esp0(unsigned long ssp) | ||
322 | { | ||
323 | current->thread.esp0 = ssp; | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * The architecture-independent backtrace generator | ||
328 | */ | ||
329 | void dump_stack(void) | ||
330 | { | ||
331 | /* | ||
332 | * We need frame pointers for this little trick, which works as follows: | ||
333 | * | ||
334 | * +------------+ 0x00 | ||
335 | * | Next SP | -> 0x0c | ||
336 | * +------------+ 0x04 | ||
337 | * | Caller | | ||
338 | * +------------+ 0x08 | ||
339 | * | Local vars | -> our stack var | ||
340 | * +------------+ 0x0c | ||
341 | * | Next SP | -> 0x18, that is what we pass to show_stack() | ||
342 | * +------------+ 0x10 | ||
343 | * | Caller | | ||
344 | * +------------+ 0x14 | ||
345 | * | Local vars | | ||
346 | * +------------+ 0x18 | ||
347 | * | ... | | ||
348 | * +------------+ | ||
349 | */ | ||
350 | |||
351 | unsigned long *stack; | ||
352 | |||
353 | stack = (unsigned long *)&stack; | ||
354 | stack++; | ||
355 | __show_stack(current, stack); | ||
356 | } | ||
357 | EXPORT_SYMBOL(dump_stack); | ||
358 | |||
359 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
360 | { | ||
361 | if (!stack && !task) | ||
362 | dump_stack(); | ||
363 | else | ||
364 | __show_stack(task, stack); | ||
365 | } | ||