blob: 437a061d8b94a74745f0e7d55cc96c14d9276e08 [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{
Linus Torvalds1da177e2005-04-16 15:20:36 -070065}
66
67void 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);
Greg Ungerera4c8b912007-07-19 01:49:14 -070083 show_stack(NULL, (unsigned long *)(fp + 1));
Pavel Emelianovbcdcd8e2007-07-17 04:03:42 -070084 add_taint(TAINT_DIE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 do_exit(SIGSEGV);
86}
87
88asmlinkage 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
Greg Ungererbb286322006-06-26 10:33:10 +100094#if defined(DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 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);
Greg Ungererbb286322006-06-26 10:33:10 +100099#if defined(DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
101#endif
102 force_sig(SIGSEGV, current);
103}
104
105
106int kstack_depth_to_print = 48;
107
Greg Ungererdb81fb82005-09-02 10:42:52 +1000108void show_stack(struct task_struct *task, unsigned long *stack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
Greg Ungererdb81fb82005-09-02 10:42:52 +1000110 unsigned long *endstack, addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 extern char _start, _etext;
112 int i;
113
Greg Ungererdb81fb82005-09-02 10:42:52 +1000114 if (!stack) {
115 if (task)
116 stack = (unsigned long *)task->thread.ksp;
117 else
118 stack = (unsigned long *)&stack;
119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Greg Ungererdb81fb82005-09-02 10:42:52 +1000121 addr = (unsigned long) stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 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)
Greg Ungerer329237c2006-12-04 17:27:09 +1000129 printk("\n" KERN_EMERG " ");
130 printk(" %08lx", *stack++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 }
Greg Ungerer329237c2006-12-04 17:27:09 +1000132 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Greg Ungerer329237c2006-12-04 17:27:09 +1000134 printk(KERN_EMERG "Call Trace:");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 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)
Greg Ungerer329237c2006-12-04 17:27:09 +1000149 printk("\n" KERN_EMERG " ");
150 printk(" [<%08lx>]", addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 i++;
152 }
153 }
Greg Ungerer329237c2006-12-04 17:27:09 +1000154 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
156
157void bad_super_trap(struct frame *fp)
158{
159 console_verbose();
Ahmed S. Darwishbf0059b2007-02-10 01:43:46 -0800160 if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 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
172asmlinkage 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
296asmlinkage void set_esp0(unsigned long ssp)
297{
298 current->thread.esp0 = ssp;
299}
300
301
302/*
303 * The architecture-independent backtrace generator
304 */
305void dump_stack(void)
306{
307 unsigned long stack;
308
309 show_stack(current, &stack);
310}
311
Greg Ungererdb81fb82005-09-02 10:42:52 +1000312EXPORT_SYMBOL(dump_stack);
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314#ifdef CONFIG_M68KFPU_EMU
315asmlinkage 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