Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[sfrench/cifs-2.6.git] / 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         if (mach_trap_init)
66                 mach_trap_init();
67 }
68
69 void 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);
86         add_taint(TAINT_DIE);
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 defined(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 defined(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
110 void show_stack(struct task_struct *task, unsigned long *stack)
111 {
112         unsigned long *endstack, addr;
113         extern char _start, _etext;
114         int i;
115
116         if (!stack) {
117                 if (task)
118                         stack = (unsigned long *)task->thread.ksp;
119                 else
120                         stack = (unsigned long *)&stack;
121         }
122
123         addr = (unsigned long) stack;
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("\n" KERN_EMERG "       ");
132                 printk(" %08lx", *stack++);
133         }
134         printk("\n");
135
136         printk(KERN_EMERG "Call Trace:");
137         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)
151                                 printk("\n" KERN_EMERG "       ");
152                         printk(" [<%08lx>]", addr);
153                         i++;
154                 }
155         }
156         printk("\n");
157 }
158
159 void bad_super_trap(struct frame *fp)
160 {
161         console_verbose();
162         if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
163                 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
174 asmlinkage 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
298 asmlinkage void set_esp0(unsigned long ssp)
299 {
300         current->thread.esp0 = ssp;
301 }
302
303
304 /*
305  * The architecture-independent backtrace generator
306  */
307 void dump_stack(void)
308 {
309         unsigned long stack;
310
311         show_stack(current, &stack);
312 }
313
314 EXPORT_SYMBOL(dump_stack);
315
316 #ifdef CONFIG_M68KFPU_EMU
317 asmlinkage 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