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
41static 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
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);
86	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
95#if defined(DEBUG)
96	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);
100#if defined(DEBUG)
101	printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
102#endif
103	force_sig(SIGSEGV, current);
104}
105
106
107int kstack_depth_to_print = 48;
108
109void show_stack(struct task_struct *task, unsigned long *stack)
110{
111	unsigned long *endstack, addr;
112	extern char _start, _etext;
113	int i;
114
115	if (!stack) {
116		if (task)
117			stack = (unsigned long *)task->thread.ksp;
118		else
119			stack = (unsigned long *)&stack;
120	}
121
122	addr = (unsigned long) stack;
123	endstack = (unsigned long *) PAGE_ALIGN(addr);
124
125	printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
126	for (i = 0; i < kstack_depth_to_print; i++) {
127		if (stack + 1 > endstack)
128			break;
129		if (i % 8 == 0)
130			printk("\n" KERN_EMERG "       ");
131		printk(" %08lx", *stack++);
132	}
133	printk("\n");
134
135	printk(KERN_EMERG "Call Trace:");
136	i = 0;
137	while (stack + 1 <= endstack) {
138		addr = *stack++;
139		/*
140		 * If the address is either in the text segment of the
141		 * kernel, or in the region which contains vmalloc'ed
142		 * memory, it *may* be the address of a calling
143		 * routine; if so, print it so that someone tracing
144		 * down the cause of the crash will be able to figure
145		 * out the call path that was taken.
146		 */
147		if (((addr >= (unsigned long) &_start) &&
148		     (addr <= (unsigned long) &_etext))) {
149			if (i % 4 == 0)
150				printk("\n" KERN_EMERG "       ");
151			printk(" [<%08lx>]", addr);
152			i++;
153		}
154	}
155	printk("\n");
156}
157
158void bad_super_trap(struct frame *fp)
159{
160	console_verbose();
161	if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
162		printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
163			vec_names[(fp->ptregs.vector) >> 2],
164			fp->ptregs.format);
165	else
166		printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
167			(fp->ptregs.vector) >> 2,
168			fp->ptregs.format);
169	printk (KERN_WARNING "Current process id is %d\n", current->pid);
170	die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
171}
172
173asmlinkage void trap_c(struct frame *fp)
174{
175	int sig;
176	siginfo_t info;
177
178	if (fp->ptregs.sr & PS_S) {
179		if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
180			/* traced a trapping instruction */
181			current->ptrace |= PT_DTRACE;
182		} else
183			bad_super_trap(fp);
184		return;
185	}
186
187	/* send the appropriate signal to the user program */
188	switch ((fp->ptregs.vector) >> 2) {
189	    case VEC_ADDRERR:
190		info.si_code = BUS_ADRALN;
191		sig = SIGBUS;
192		break;
193	    case VEC_ILLEGAL:
194	    case VEC_LINE10:
195	    case VEC_LINE11:
196		info.si_code = ILL_ILLOPC;
197		sig = SIGILL;
198		break;
199	    case VEC_PRIV:
200		info.si_code = ILL_PRVOPC;
201		sig = SIGILL;
202		break;
203	    case VEC_COPROC:
204		info.si_code = ILL_COPROC;
205		sig = SIGILL;
206		break;
207	    case VEC_TRAP1: /* gdbserver breakpoint */
208		fp->ptregs.pc -= 2;
209		info.si_code = TRAP_TRACE;
210		sig = SIGTRAP;
211		break;
212	    case VEC_TRAP2:
213	    case VEC_TRAP3:
214	    case VEC_TRAP4:
215	    case VEC_TRAP5:
216	    case VEC_TRAP6:
217	    case VEC_TRAP7:
218	    case VEC_TRAP8:
219	    case VEC_TRAP9:
220	    case VEC_TRAP10:
221	    case VEC_TRAP11:
222	    case VEC_TRAP12:
223	    case VEC_TRAP13:
224	    case VEC_TRAP14:
225		info.si_code = ILL_ILLTRP;
226		sig = SIGILL;
227		break;
228	    case VEC_FPBRUC:
229	    case VEC_FPOE:
230	    case VEC_FPNAN:
231		info.si_code = FPE_FLTINV;
232		sig = SIGFPE;
233		break;
234	    case VEC_FPIR:
235		info.si_code = FPE_FLTRES;
236		sig = SIGFPE;
237		break;
238	    case VEC_FPDIVZ:
239		info.si_code = FPE_FLTDIV;
240		sig = SIGFPE;
241		break;
242	    case VEC_FPUNDER:
243		info.si_code = FPE_FLTUND;
244		sig = SIGFPE;
245		break;
246	    case VEC_FPOVER:
247		info.si_code = FPE_FLTOVF;
248		sig = SIGFPE;
249		break;
250	    case VEC_ZERODIV:
251		info.si_code = FPE_INTDIV;
252		sig = SIGFPE;
253		break;
254	    case VEC_CHK:
255	    case VEC_TRAP:
256		info.si_code = FPE_INTOVF;
257		sig = SIGFPE;
258		break;
259	    case VEC_TRACE:		/* ptrace single step */
260		info.si_code = TRAP_TRACE;
261		sig = SIGTRAP;
262		break;
263	    case VEC_TRAP15:		/* breakpoint */
264		info.si_code = TRAP_BRKPT;
265		sig = SIGTRAP;
266		break;
267	    default:
268		info.si_code = ILL_ILLOPC;
269		sig = SIGILL;
270		break;
271	}
272	info.si_signo = sig;
273	info.si_errno = 0;
274	switch (fp->ptregs.format) {
275	    default:
276		info.si_addr = (void *) fp->ptregs.pc;
277		break;
278	    case 2:
279		info.si_addr = (void *) fp->un.fmt2.iaddr;
280		break;
281	    case 7:
282		info.si_addr = (void *) fp->un.fmt7.effaddr;
283		break;
284	    case 9:
285		info.si_addr = (void *) fp->un.fmt9.iaddr;
286		break;
287	    case 10:
288		info.si_addr = (void *) fp->un.fmta.daddr;
289		break;
290	    case 11:
291		info.si_addr = (void *) fp->un.fmtb.daddr;
292		break;
293	}
294	force_sig_info (sig, &info, current);
295}
296
297asmlinkage void set_esp0(unsigned long ssp)
298{
299	current->thread.esp0 = ssp;
300}
301
302
303/*
304 * The architecture-independent backtrace generator
305 */
306void dump_stack(void)
307{
308	unsigned long stack;
309
310	show_stack(current, &stack);
311}
312
313EXPORT_SYMBOL(dump_stack);
314
315#ifdef CONFIG_M68KFPU_EMU
316asmlinkage void fpemu_signal(int signal, int code, void *addr)
317{
318	siginfo_t info;
319
320	info.si_signo = signal;
321	info.si_errno = 0;
322	info.si_code = code;
323	info.si_addr = addr;
324	force_sig_info(signal, &info, current);
325}
326#endif
327