diff options
Diffstat (limited to 'arch/m68knommu/kernel/traps.c')
-rw-r--r-- | arch/m68knommu/kernel/traps.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c new file mode 100644 index 000000000000..ad7dc6347f19 --- /dev/null +++ b/arch/m68knommu/kernel/traps.c | |||
@@ -0,0 +1,320 @@ | |||
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/config.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/signal.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/mm.h> | ||
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 | |||
41 | static char *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 | if (mach_trap_init) | ||
66 | mach_trap_init(); | ||
67 | } | ||
68 | |||
69 | void die_if_kernel(char *str, struct pt_regs *fp, int nr) | ||
70 | { | ||
71 | if (!(fp->sr & PS_S)) | ||
72 | return; | ||
73 | |||
74 | console_verbose(); | ||
75 | printk(KERN_EMERG "%s: %08x\n",str,nr); | ||
76 | printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", | ||
77 | fp->pc, fp->sr, fp, fp->a2); | ||
78 | printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
79 | fp->d0, fp->d1, fp->d2, fp->d3); | ||
80 | printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
81 | fp->d4, fp->d5, fp->a0, fp->a1); | ||
82 | |||
83 | printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", | ||
84 | current->comm, current->pid, PAGE_SIZE+(unsigned long)current); | ||
85 | show_stack(NULL, (unsigned long *)fp); | ||
86 | do_exit(SIGSEGV); | ||
87 | } | ||
88 | |||
89 | asmlinkage void buserr_c(struct frame *fp) | ||
90 | { | ||
91 | /* Only set esp0 if coming from user mode */ | ||
92 | if (user_mode(&fp->ptregs)) | ||
93 | current->thread.esp0 = (unsigned long) fp; | ||
94 | |||
95 | #if DEBUG | ||
96 | printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format); | ||
97 | #endif | ||
98 | |||
99 | die_if_kernel("bad frame format",&fp->ptregs,0); | ||
100 | #if DEBUG | ||
101 | printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); | ||
102 | #endif | ||
103 | force_sig(SIGSEGV, current); | ||
104 | } | ||
105 | |||
106 | |||
107 | int kstack_depth_to_print = 48; | ||
108 | |||
109 | void show_stack(struct task_struct *task, unsigned long *esp) | ||
110 | { | ||
111 | unsigned long *stack, *endstack, addr; | ||
112 | extern char _start, _etext; | ||
113 | int i; | ||
114 | |||
115 | if (esp == NULL) | ||
116 | esp = (unsigned long *) &esp; | ||
117 | |||
118 | stack = esp; | ||
119 | addr = (unsigned long) esp; | ||
120 | endstack = (unsigned long *) PAGE_ALIGN(addr); | ||
121 | |||
122 | printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); | ||
123 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
124 | if (stack + 1 > endstack) | ||
125 | break; | ||
126 | if (i % 8 == 0) | ||
127 | printk(KERN_EMERG "\n "); | ||
128 | printk(KERN_EMERG " %08lx", *stack++); | ||
129 | } | ||
130 | |||
131 | printk(KERN_EMERG "\nCall Trace:"); | ||
132 | i = 0; | ||
133 | while (stack + 1 <= endstack) { | ||
134 | addr = *stack++; | ||
135 | /* | ||
136 | * If the address is either in the text segment of the | ||
137 | * kernel, or in the region which contains vmalloc'ed | ||
138 | * memory, it *may* be the address of a calling | ||
139 | * routine; if so, print it so that someone tracing | ||
140 | * down the cause of the crash will be able to figure | ||
141 | * out the call path that was taken. | ||
142 | */ | ||
143 | if (((addr >= (unsigned long) &_start) && | ||
144 | (addr <= (unsigned long) &_etext))) { | ||
145 | if (i % 4 == 0) | ||
146 | printk(KERN_EMERG "\n "); | ||
147 | printk(KERN_EMERG " [<%08lx>]", addr); | ||
148 | i++; | ||
149 | } | ||
150 | } | ||
151 | printk(KERN_EMERG "\n"); | ||
152 | } | ||
153 | |||
154 | void bad_super_trap(struct frame *fp) | ||
155 | { | ||
156 | console_verbose(); | ||
157 | if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) | ||
158 | printk (KERN_WARNING "*** %s *** FORMAT=%X\n", | ||
159 | vec_names[(fp->ptregs.vector) >> 2], | ||
160 | fp->ptregs.format); | ||
161 | else | ||
162 | printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n", | ||
163 | (fp->ptregs.vector) >> 2, | ||
164 | fp->ptregs.format); | ||
165 | printk (KERN_WARNING "Current process id is %d\n", current->pid); | ||
166 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
167 | } | ||
168 | |||
169 | asmlinkage void trap_c(struct frame *fp) | ||
170 | { | ||
171 | int sig; | ||
172 | siginfo_t info; | ||
173 | |||
174 | if (fp->ptregs.sr & PS_S) { | ||
175 | if ((fp->ptregs.vector >> 2) == VEC_TRACE) { | ||
176 | /* traced a trapping instruction */ | ||
177 | current->ptrace |= PT_DTRACE; | ||
178 | } else | ||
179 | bad_super_trap(fp); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | /* send the appropriate signal to the user program */ | ||
184 | switch ((fp->ptregs.vector) >> 2) { | ||
185 | case VEC_ADDRERR: | ||
186 | info.si_code = BUS_ADRALN; | ||
187 | sig = SIGBUS; | ||
188 | break; | ||
189 | case VEC_ILLEGAL: | ||
190 | case VEC_LINE10: | ||
191 | case VEC_LINE11: | ||
192 | info.si_code = ILL_ILLOPC; | ||
193 | sig = SIGILL; | ||
194 | break; | ||
195 | case VEC_PRIV: | ||
196 | info.si_code = ILL_PRVOPC; | ||
197 | sig = SIGILL; | ||
198 | break; | ||
199 | case VEC_COPROC: | ||
200 | info.si_code = ILL_COPROC; | ||
201 | sig = SIGILL; | ||
202 | break; | ||
203 | case VEC_TRAP1: /* gdbserver breakpoint */ | ||
204 | fp->ptregs.pc -= 2; | ||
205 | info.si_code = TRAP_TRACE; | ||
206 | sig = SIGTRAP; | ||
207 | break; | ||
208 | case VEC_TRAP2: | ||
209 | case VEC_TRAP3: | ||
210 | case VEC_TRAP4: | ||
211 | case VEC_TRAP5: | ||
212 | case VEC_TRAP6: | ||
213 | case VEC_TRAP7: | ||
214 | case VEC_TRAP8: | ||
215 | case VEC_TRAP9: | ||
216 | case VEC_TRAP10: | ||
217 | case VEC_TRAP11: | ||
218 | case VEC_TRAP12: | ||
219 | case VEC_TRAP13: | ||
220 | case VEC_TRAP14: | ||
221 | info.si_code = ILL_ILLTRP; | ||
222 | sig = SIGILL; | ||
223 | break; | ||
224 | case VEC_FPBRUC: | ||
225 | case VEC_FPOE: | ||
226 | case VEC_FPNAN: | ||
227 | info.si_code = FPE_FLTINV; | ||
228 | sig = SIGFPE; | ||
229 | break; | ||
230 | case VEC_FPIR: | ||
231 | info.si_code = FPE_FLTRES; | ||
232 | sig = SIGFPE; | ||
233 | break; | ||
234 | case VEC_FPDIVZ: | ||
235 | info.si_code = FPE_FLTDIV; | ||
236 | sig = SIGFPE; | ||
237 | break; | ||
238 | case VEC_FPUNDER: | ||
239 | info.si_code = FPE_FLTUND; | ||
240 | sig = SIGFPE; | ||
241 | break; | ||
242 | case VEC_FPOVER: | ||
243 | info.si_code = FPE_FLTOVF; | ||
244 | sig = SIGFPE; | ||
245 | break; | ||
246 | case VEC_ZERODIV: | ||
247 | info.si_code = FPE_INTDIV; | ||
248 | sig = SIGFPE; | ||
249 | break; | ||
250 | case VEC_CHK: | ||
251 | case VEC_TRAP: | ||
252 | info.si_code = FPE_INTOVF; | ||
253 | sig = SIGFPE; | ||
254 | break; | ||
255 | case VEC_TRACE: /* ptrace single step */ | ||
256 | info.si_code = TRAP_TRACE; | ||
257 | sig = SIGTRAP; | ||
258 | break; | ||
259 | case VEC_TRAP15: /* breakpoint */ | ||
260 | info.si_code = TRAP_BRKPT; | ||
261 | sig = SIGTRAP; | ||
262 | break; | ||
263 | default: | ||
264 | info.si_code = ILL_ILLOPC; | ||
265 | sig = SIGILL; | ||
266 | break; | ||
267 | } | ||
268 | info.si_signo = sig; | ||
269 | info.si_errno = 0; | ||
270 | switch (fp->ptregs.format) { | ||
271 | default: | ||
272 | info.si_addr = (void *) fp->ptregs.pc; | ||
273 | break; | ||
274 | case 2: | ||
275 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
276 | break; | ||
277 | case 7: | ||
278 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
279 | break; | ||
280 | case 9: | ||
281 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
282 | break; | ||
283 | case 10: | ||
284 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
285 | break; | ||
286 | case 11: | ||
287 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
288 | break; | ||
289 | } | ||
290 | force_sig_info (sig, &info, current); | ||
291 | } | ||
292 | |||
293 | asmlinkage void set_esp0(unsigned long ssp) | ||
294 | { | ||
295 | current->thread.esp0 = ssp; | ||
296 | } | ||
297 | |||
298 | |||
299 | /* | ||
300 | * The architecture-independent backtrace generator | ||
301 | */ | ||
302 | void dump_stack(void) | ||
303 | { | ||
304 | unsigned long stack; | ||
305 | |||
306 | show_stack(current, &stack); | ||
307 | } | ||
308 | |||
309 | #ifdef CONFIG_M68KFPU_EMU | ||
310 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | ||
311 | { | ||
312 | siginfo_t info; | ||
313 | |||
314 | info.si_signo = signal; | ||
315 | info.si_errno = 0; | ||
316 | info.si_code = code; | ||
317 | info.si_addr = addr; | ||
318 | force_sig_info(signal, &info, current); | ||
319 | } | ||
320 | #endif | ||