blob: ec9aea652e79d0665adcb36fe5e9cd49d9625a51 [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>
Sebastian Siewiorf6054e22008-05-01 12:16:38 +100031#include <linux/kallsyms.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
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
Greg Ungererdb81fb82005-09-02 10:42:52 +100042static char const * const vec_names[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 "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
64void __init trap_init(void)
65{
Linus Torvalds1da177e2005-04-16 15:20:36 -070066}
67
68void die_if_kernel(char *str, struct pt_regs *fp, int nr)
69{
70 if (!(fp->sr & PS_S))
71 return;
72
73 console_verbose();
74 printk(KERN_EMERG "%s: %08x\n",str,nr);
75 printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
76 fp->pc, fp->sr, fp, fp->a2);
77 printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
78 fp->d0, fp->d1, fp->d2, fp->d3);
79 printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
80 fp->d4, fp->d5, fp->a0, fp->a1);
81
82 printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
83 current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
Greg Ungerera4c8b912007-07-19 01:49:14 -070084 show_stack(NULL, (unsigned long *)(fp + 1));
Pavel Emelianovbcdcd8e2007-07-17 04:03:42 -070085 add_taint(TAINT_DIE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 do_exit(SIGSEGV);
87}
88
89asmlinkage 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
Greg Ungererbb286322006-06-26 10:33:10 +100095#if defined(DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 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);
Greg Ungererbb286322006-06-26 10:33:10 +1000100#if defined(DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
102#endif
103 force_sig(SIGSEGV, current);
104}
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106int kstack_depth_to_print = 48;
107
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000108static void __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;
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000111 unsigned long *last_stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 int i;
113
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000114 if (!stack)
115 stack = (unsigned long *)task->thread.ksp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Greg Ungererdb81fb82005-09-02 10:42:52 +1000117 addr = (unsigned long) stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 endstack = (unsigned long *) PAGE_ALIGN(addr);
119
120 printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
121 for (i = 0; i < kstack_depth_to_print; i++) {
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000122 if (stack + 1 + i > endstack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 break;
124 if (i % 8 == 0)
Greg Ungerer329237c2006-12-04 17:27:09 +1000125 printk("\n" KERN_EMERG " ");
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000126 printk(" %08lx", *(stack + i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 }
Greg Ungerer329237c2006-12-04 17:27:09 +1000128 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000130#ifdef CONFIG_FRAME_POINTER
131 printk(KERN_EMERG "Call Trace:\n");
132
133 last_stack = stack - 1;
134 while (stack <= endstack && stack > last_stack) {
135
136 addr = *(stack + 1);
137 printk(KERN_EMERG " [%08lx] ", addr);
138 print_symbol(KERN_CONT "%s\n", addr);
139
140 last_stack = stack;
141 stack = (unsigned long *)*stack;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 }
Greg Ungerer329237c2006-12-04 17:27:09 +1000143 printk("\n");
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000144#else
145 printk(KERN_EMERG "CONFIG_FRAME_POINTER disabled, no symbolic call trace\n");
146#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147}
148
149void bad_super_trap(struct frame *fp)
150{
151 console_verbose();
Ahmed S. Darwishbf0059b2007-02-10 01:43:46 -0800152 if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
154 vec_names[(fp->ptregs.vector) >> 2],
155 fp->ptregs.format);
156 else
157 printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
158 (fp->ptregs.vector) >> 2,
159 fp->ptregs.format);
160 printk (KERN_WARNING "Current process id is %d\n", current->pid);
161 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
162}
163
164asmlinkage void trap_c(struct frame *fp)
165{
166 int sig;
167 siginfo_t info;
168
169 if (fp->ptregs.sr & PS_S) {
170 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
171 /* traced a trapping instruction */
172 current->ptrace |= PT_DTRACE;
173 } else
174 bad_super_trap(fp);
175 return;
176 }
177
178 /* send the appropriate signal to the user program */
179 switch ((fp->ptregs.vector) >> 2) {
180 case VEC_ADDRERR:
181 info.si_code = BUS_ADRALN;
182 sig = SIGBUS;
183 break;
184 case VEC_ILLEGAL:
185 case VEC_LINE10:
186 case VEC_LINE11:
187 info.si_code = ILL_ILLOPC;
188 sig = SIGILL;
189 break;
190 case VEC_PRIV:
191 info.si_code = ILL_PRVOPC;
192 sig = SIGILL;
193 break;
194 case VEC_COPROC:
195 info.si_code = ILL_COPROC;
196 sig = SIGILL;
197 break;
198 case VEC_TRAP1: /* gdbserver breakpoint */
199 fp->ptregs.pc -= 2;
200 info.si_code = TRAP_TRACE;
201 sig = SIGTRAP;
202 break;
203 case VEC_TRAP2:
204 case VEC_TRAP3:
205 case VEC_TRAP4:
206 case VEC_TRAP5:
207 case VEC_TRAP6:
208 case VEC_TRAP7:
209 case VEC_TRAP8:
210 case VEC_TRAP9:
211 case VEC_TRAP10:
212 case VEC_TRAP11:
213 case VEC_TRAP12:
214 case VEC_TRAP13:
215 case VEC_TRAP14:
216 info.si_code = ILL_ILLTRP;
217 sig = SIGILL;
218 break;
219 case VEC_FPBRUC:
220 case VEC_FPOE:
221 case VEC_FPNAN:
222 info.si_code = FPE_FLTINV;
223 sig = SIGFPE;
224 break;
225 case VEC_FPIR:
226 info.si_code = FPE_FLTRES;
227 sig = SIGFPE;
228 break;
229 case VEC_FPDIVZ:
230 info.si_code = FPE_FLTDIV;
231 sig = SIGFPE;
232 break;
233 case VEC_FPUNDER:
234 info.si_code = FPE_FLTUND;
235 sig = SIGFPE;
236 break;
237 case VEC_FPOVER:
238 info.si_code = FPE_FLTOVF;
239 sig = SIGFPE;
240 break;
241 case VEC_ZERODIV:
242 info.si_code = FPE_INTDIV;
243 sig = SIGFPE;
244 break;
245 case VEC_CHK:
246 case VEC_TRAP:
247 info.si_code = FPE_INTOVF;
248 sig = SIGFPE;
249 break;
250 case VEC_TRACE: /* ptrace single step */
251 info.si_code = TRAP_TRACE;
252 sig = SIGTRAP;
253 break;
254 case VEC_TRAP15: /* breakpoint */
255 info.si_code = TRAP_BRKPT;
256 sig = SIGTRAP;
257 break;
258 default:
259 info.si_code = ILL_ILLOPC;
260 sig = SIGILL;
261 break;
262 }
263 info.si_signo = sig;
264 info.si_errno = 0;
265 switch (fp->ptregs.format) {
266 default:
267 info.si_addr = (void *) fp->ptregs.pc;
268 break;
269 case 2:
270 info.si_addr = (void *) fp->un.fmt2.iaddr;
271 break;
272 case 7:
273 info.si_addr = (void *) fp->un.fmt7.effaddr;
274 break;
275 case 9:
276 info.si_addr = (void *) fp->un.fmt9.iaddr;
277 break;
278 case 10:
279 info.si_addr = (void *) fp->un.fmta.daddr;
280 break;
281 case 11:
282 info.si_addr = (void *) fp->un.fmtb.daddr;
283 break;
284 }
285 force_sig_info (sig, &info, current);
286}
287
288asmlinkage void set_esp0(unsigned long ssp)
289{
290 current->thread.esp0 = ssp;
291}
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293/*
294 * The architecture-independent backtrace generator
295 */
296void dump_stack(void)
297{
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000298 /*
299 * We need frame pointers for this little trick, which works as follows:
300 *
301 * +------------+ 0x00
302 * | Next SP | -> 0x0c
303 * +------------+ 0x04
304 * | Caller |
305 * +------------+ 0x08
306 * | Local vars | -> our stack var
307 * +------------+ 0x0c
308 * | Next SP | -> 0x18, that is what we pass to show_stack()
309 * +------------+ 0x10
310 * | Caller |
311 * +------------+ 0x14
312 * | Local vars |
313 * +------------+ 0x18
314 * | ... |
315 * +------------+
316 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000318 unsigned long *stack;
319
320 stack = (unsigned long *)&stack;
321 stack++;
322 __show_stack(current, stack);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
Greg Ungererdb81fb82005-09-02 10:42:52 +1000324EXPORT_SYMBOL(dump_stack);
325
Sebastian Siewiorf6054e22008-05-01 12:16:38 +1000326void show_stack(struct task_struct *task, unsigned long *stack)
327{
328 if (!stack && !task)
329 dump_stack();
330 else
331 __show_stack(task, stack);
332}
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334#ifdef CONFIG_M68KFPU_EMU
335asmlinkage void fpemu_signal(int signal, int code, void *addr)
336{
337 siginfo_t info;
338
339 info.si_signo = signal;
340 info.si_errno = 0;
341 info.si_code = code;
342 info.si_addr = addr;
343 force_sig_info(signal, &info, current);
344}
345#endif