blob: fde04e1757f74ac1b4cd0fddb19ea7a6ebc59218 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/sched.h>
20#include <linux/signal.h>
21#include <linux/kernel.h>
22#include <linux/mm.h>
Greg Ungererdb81fb82005-09-02 10:42:52 +100023#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#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
Greg Ungererdb81fb82005-09-02 10:42:52 +100041static char const * const vec_names[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 "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
63void __init trap_init(void)
64{
65 if (mach_trap_init)
66 mach_trap_init();
67}
68
69void 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);
Pavel Emelianovbcdcd8e2007-07-17 04:03:42 -070086 add_taint(TAINT_DIE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 do_exit(SIGSEGV);
88}
89
90asmlinkage 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
Greg Ungererbb286322006-06-26 10:33:10 +100096#if defined(DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 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);
Greg Ungererbb286322006-06-26 10:33:10 +1000101#if defined(DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
103#endif
104 force_sig(SIGSEGV, current);
105}
106
107
108int kstack_depth_to_print = 48;
109
Greg Ungererdb81fb82005-09-02 10:42:52 +1000110void show_stack(struct task_struct *task, unsigned long *stack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
Greg Ungererdb81fb82005-09-02 10:42:52 +1000112 unsigned long *endstack, addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 extern char _start, _etext;
114 int i;
115
Greg Ungererdb81fb82005-09-02 10:42:52 +1000116 if (!stack) {
117 if (task)
118 stack = (unsigned long *)task->thread.ksp;
119 else
120 stack = (unsigned long *)&stack;
121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Greg Ungererdb81fb82005-09-02 10:42:52 +1000123 addr = (unsigned long) stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 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)
Greg Ungerer329237c2006-12-04 17:27:09 +1000131 printk("\n" KERN_EMERG " ");
132 printk(" %08lx", *stack++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 }
Greg Ungerer329237c2006-12-04 17:27:09 +1000134 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Greg Ungerer329237c2006-12-04 17:27:09 +1000136 printk(KERN_EMERG "Call Trace:");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 i = 0;
138 while (stack + 1 <= endstack) {
139 addr = *stack++;
140 /*
141 * If the address is either in the text segment of the
142 * kernel, or in the region which contains vmalloc'ed
143 * memory, it *may* be the address of a calling
144 * routine; if so, print it so that someone tracing
145 * down the cause of the crash will be able to figure
146 * out the call path that was taken.
147 */
148 if (((addr >= (unsigned long) &_start) &&
149 (addr <= (unsigned long) &_etext))) {
150 if (i % 4 == 0)
Greg Ungerer329237c2006-12-04 17:27:09 +1000151 printk("\n" KERN_EMERG " ");
152 printk(" [<%08lx>]", addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 i++;
154 }
155 }
Greg Ungerer329237c2006-12-04 17:27:09 +1000156 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157}
158
159void bad_super_trap(struct frame *fp)
160{
161 console_verbose();
Ahmed S. Darwishbf0059b2007-02-10 01:43:46 -0800162 if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
164 vec_names[(fp->ptregs.vector) >> 2],
165 fp->ptregs.format);
166 else
167 printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
168 (fp->ptregs.vector) >> 2,
169 fp->ptregs.format);
170 printk (KERN_WARNING "Current process id is %d\n", current->pid);
171 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
172}
173
174asmlinkage void trap_c(struct frame *fp)
175{
176 int sig;
177 siginfo_t info;
178
179 if (fp->ptregs.sr & PS_S) {
180 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
181 /* traced a trapping instruction */
182 current->ptrace |= PT_DTRACE;
183 } else
184 bad_super_trap(fp);
185 return;
186 }
187
188 /* send the appropriate signal to the user program */
189 switch ((fp->ptregs.vector) >> 2) {
190 case VEC_ADDRERR:
191 info.si_code = BUS_ADRALN;
192 sig = SIGBUS;
193 break;
194 case VEC_ILLEGAL:
195 case VEC_LINE10:
196 case VEC_LINE11:
197 info.si_code = ILL_ILLOPC;
198 sig = SIGILL;
199 break;
200 case VEC_PRIV:
201 info.si_code = ILL_PRVOPC;
202 sig = SIGILL;
203 break;
204 case VEC_COPROC:
205 info.si_code = ILL_COPROC;
206 sig = SIGILL;
207 break;
208 case VEC_TRAP1: /* gdbserver breakpoint */
209 fp->ptregs.pc -= 2;
210 info.si_code = TRAP_TRACE;
211 sig = SIGTRAP;
212 break;
213 case VEC_TRAP2:
214 case VEC_TRAP3:
215 case VEC_TRAP4:
216 case VEC_TRAP5:
217 case VEC_TRAP6:
218 case VEC_TRAP7:
219 case VEC_TRAP8:
220 case VEC_TRAP9:
221 case VEC_TRAP10:
222 case VEC_TRAP11:
223 case VEC_TRAP12:
224 case VEC_TRAP13:
225 case VEC_TRAP14:
226 info.si_code = ILL_ILLTRP;
227 sig = SIGILL;
228 break;
229 case VEC_FPBRUC:
230 case VEC_FPOE:
231 case VEC_FPNAN:
232 info.si_code = FPE_FLTINV;
233 sig = SIGFPE;
234 break;
235 case VEC_FPIR:
236 info.si_code = FPE_FLTRES;
237 sig = SIGFPE;
238 break;
239 case VEC_FPDIVZ:
240 info.si_code = FPE_FLTDIV;
241 sig = SIGFPE;
242 break;
243 case VEC_FPUNDER:
244 info.si_code = FPE_FLTUND;
245 sig = SIGFPE;
246 break;
247 case VEC_FPOVER:
248 info.si_code = FPE_FLTOVF;
249 sig = SIGFPE;
250 break;
251 case VEC_ZERODIV:
252 info.si_code = FPE_INTDIV;
253 sig = SIGFPE;
254 break;
255 case VEC_CHK:
256 case VEC_TRAP:
257 info.si_code = FPE_INTOVF;
258 sig = SIGFPE;
259 break;
260 case VEC_TRACE: /* ptrace single step */
261 info.si_code = TRAP_TRACE;
262 sig = SIGTRAP;
263 break;
264 case VEC_TRAP15: /* breakpoint */
265 info.si_code = TRAP_BRKPT;
266 sig = SIGTRAP;
267 break;
268 default:
269 info.si_code = ILL_ILLOPC;
270 sig = SIGILL;
271 break;
272 }
273 info.si_signo = sig;
274 info.si_errno = 0;
275 switch (fp->ptregs.format) {
276 default:
277 info.si_addr = (void *) fp->ptregs.pc;
278 break;
279 case 2:
280 info.si_addr = (void *) fp->un.fmt2.iaddr;
281 break;
282 case 7:
283 info.si_addr = (void *) fp->un.fmt7.effaddr;
284 break;
285 case 9:
286 info.si_addr = (void *) fp->un.fmt9.iaddr;
287 break;
288 case 10:
289 info.si_addr = (void *) fp->un.fmta.daddr;
290 break;
291 case 11:
292 info.si_addr = (void *) fp->un.fmtb.daddr;
293 break;
294 }
295 force_sig_info (sig, &info, current);
296}
297
298asmlinkage void set_esp0(unsigned long ssp)
299{
300 current->thread.esp0 = ssp;
301}
302
303
304/*
305 * The architecture-independent backtrace generator
306 */
307void dump_stack(void)
308{
309 unsigned long stack;
310
311 show_stack(current, &stack);
312}
313
Greg Ungererdb81fb82005-09-02 10:42:52 +1000314EXPORT_SYMBOL(dump_stack);
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316#ifdef CONFIG_M68KFPU_EMU
317asmlinkage void fpemu_signal(int signal, int code, void *addr)
318{
319 siginfo_t info;
320
321 info.si_signo = signal;
322 info.si_errno = 0;
323 info.si_code = code;
324 info.si_addr = addr;
325 force_sig_info(signal, &info, current);
326}
327#endif