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