Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[linux-2.6] / arch / m68knommu / kernel / traps.c
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/sched.h>
20 #include <linux/signal.h>
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/module.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 const * const 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 }
66
67 void 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);
83         show_stack(NULL, (unsigned long *)(fp + 1));
84         add_taint(TAINT_DIE);
85         do_exit(SIGSEGV);
86 }
87
88 asmlinkage 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
94 #if defined(DEBUG)
95         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);
99 #if defined(DEBUG)
100         printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
101 #endif
102         force_sig(SIGSEGV, current);
103 }
104
105
106 int kstack_depth_to_print = 48;
107
108 void show_stack(struct task_struct *task, unsigned long *stack)
109 {
110         unsigned long *endstack, addr;
111         extern char _start, _etext;
112         int i;
113
114         if (!stack) {
115                 if (task)
116                         stack = (unsigned long *)task->thread.ksp;
117                 else
118                         stack = (unsigned long *)&stack;
119         }
120
121         addr = (unsigned long) stack;
122         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)
129                         printk("\n" KERN_EMERG "       ");
130                 printk(" %08lx", *stack++);
131         }
132         printk("\n");
133
134         printk(KERN_EMERG "Call Trace:");
135         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)
149                                 printk("\n" KERN_EMERG "       ");
150                         printk(" [<%08lx>]", addr);
151                         i++;
152                 }
153         }
154         printk("\n");
155 }
156
157 void bad_super_trap(struct frame *fp)
158 {
159         console_verbose();
160         if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
161                 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
172 asmlinkage 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
296 asmlinkage void set_esp0(unsigned long ssp)
297 {
298         current->thread.esp0 = ssp;
299 }
300
301
302 /*
303  * The architecture-independent backtrace generator
304  */
305 void dump_stack(void)
306 {
307         unsigned long stack;
308
309         show_stack(current, &stack);
310 }
311
312 EXPORT_SYMBOL(dump_stack);
313
314 #ifdef CONFIG_M68KFPU_EMU
315 asmlinkage 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