- Peter Anvin: more P4 configuration parsing
[davej-history.git] / arch / m68k / kernel / traps.c
blobd5d6753cb1e4582efb0632d69975842a19984ee4
1 /*
2 * linux/arch/m68k/kernel/traps.c
4 * Copyright (C) 1993, 1994 by Hamish Macdonald
6 * 68040 fixes by Michael Rausch
7 * 68040 fixes by Martin Apel
8 * 68040 fixes and writeback by Richard Zidlicky
9 * 68060 fixes by Roman Hodek
10 * 68060 fixes by Jesper Skov
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive
14 * for more details.
18 * Sets up all exception vectors
21 #include <linux/config.h>
22 #include <linux/sched.h>
23 #include <linux/signal.h>
24 #include <linux/kernel.h>
25 #include <linux/mm.h>
26 #include <linux/types.h>
27 #include <linux/a.out.h>
28 #include <linux/user.h>
29 #include <linux/string.h>
30 #include <linux/linkage.h>
31 #include <linux/init.h>
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/pgalloc.h>
39 #include <asm/machdep.h>
40 #include <asm/siginfo.h>
42 /* assembler routines */
43 asmlinkage void system_call(void);
44 asmlinkage void buserr(void);
45 asmlinkage void trap(void);
46 asmlinkage void inthandler(void);
47 asmlinkage void nmihandler(void);
48 #ifdef CONFIG_M68KFPU_EMU
49 asmlinkage void fpu_emu(void);
50 #endif
52 e_vector vectors[256] = {
53 0, 0, buserr, trap, trap, trap, trap, trap,
54 trap, trap, trap, trap, trap, trap, trap, trap,
55 trap, trap, trap, trap, trap, trap, trap, trap,
56 inthandler, inthandler, inthandler, inthandler,
57 inthandler, inthandler, inthandler, inthandler,
58 /* TRAP #0-15 */
59 system_call, trap, trap, trap, trap, trap, trap, trap,
60 trap, trap, trap, trap, trap, trap, trap, trap,
61 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
64 /* nmi handler for the Amiga */
65 asm(".text\n"
66 __ALIGN_STR "\n"
67 SYMBOL_NAME_STR(nmihandler) ": rte");
70 * this must be called very early as the kernel might
71 * use some instruction that are emulated on the 060
73 void __init base_trap_init(void)
75 /* setup the exception vector table */
76 __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
78 if (CPU_IS_060) {
79 /* set up ISP entry points */
80 asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
82 vectors[VEC_UNIMPII] = unimp_vec;
86 void __init trap_init (void)
88 int i;
90 for (i = 48; i < 64; i++)
91 if (!vectors[i])
92 vectors[i] = trap;
94 for (i = 64; i < 256; i++)
95 vectors[i] = inthandler;
97 #ifdef CONFIG_M68KFPU_EMU
98 if (FPU_IS_EMU)
99 vectors[VEC_LINE11] = fpu_emu;
100 #endif
102 if (CPU_IS_040 && !FPU_IS_EMU) {
103 /* set up FPSP entry points */
104 asmlinkage void dz_vec(void) asm ("dz");
105 asmlinkage void inex_vec(void) asm ("inex");
106 asmlinkage void ovfl_vec(void) asm ("ovfl");
107 asmlinkage void unfl_vec(void) asm ("unfl");
108 asmlinkage void snan_vec(void) asm ("snan");
109 asmlinkage void operr_vec(void) asm ("operr");
110 asmlinkage void bsun_vec(void) asm ("bsun");
111 asmlinkage void fline_vec(void) asm ("fline");
112 asmlinkage void unsupp_vec(void) asm ("unsupp");
114 vectors[VEC_FPDIVZ] = dz_vec;
115 vectors[VEC_FPIR] = inex_vec;
116 vectors[VEC_FPOVER] = ovfl_vec;
117 vectors[VEC_FPUNDER] = unfl_vec;
118 vectors[VEC_FPNAN] = snan_vec;
119 vectors[VEC_FPOE] = operr_vec;
120 vectors[VEC_FPBRUC] = bsun_vec;
121 vectors[VEC_LINE11] = fline_vec;
122 vectors[VEC_FPUNSUP] = unsupp_vec;
125 if (CPU_IS_060 && !FPU_IS_EMU) {
126 /* set up IFPSP entry points */
127 asmlinkage void snan_vec(void) asm ("_060_fpsp_snan");
128 asmlinkage void operr_vec(void) asm ("_060_fpsp_operr");
129 asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl");
130 asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl");
131 asmlinkage void dz_vec(void) asm ("_060_fpsp_dz");
132 asmlinkage void inex_vec(void) asm ("_060_fpsp_inex");
133 asmlinkage void fline_vec(void) asm ("_060_fpsp_fline");
134 asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp");
135 asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd");
137 vectors[VEC_FPNAN] = snan_vec;
138 vectors[VEC_FPOE] = operr_vec;
139 vectors[VEC_FPOVER] = ovfl_vec;
140 vectors[VEC_FPUNDER] = unfl_vec;
141 vectors[VEC_FPDIVZ] = dz_vec;
142 vectors[VEC_FPIR] = inex_vec;
143 vectors[VEC_LINE11] = fline_vec;
144 vectors[VEC_FPUNSUP] = unsupp_vec;
145 vectors[VEC_UNIMPEA] = effadd_vec;
148 /* if running on an amiga, make the NMI interrupt do nothing */
149 if (MACH_IS_AMIGA) {
150 vectors[VEC_INT7] = nmihandler;
155 static inline void console_verbose(void)
157 extern int console_loglevel;
158 console_loglevel = 15;
162 static char *vec_names[] = {
163 "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
164 "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
165 "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
166 "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
167 "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
168 "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
169 "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
170 "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
171 "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
172 "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
173 "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
174 "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
175 "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
176 "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
177 "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
178 "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
179 "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
180 "FPCP UNSUPPORTED OPERATION",
181 "MMU CONFIGURATION ERROR"
184 #ifndef CONFIG_SUN3
185 static char *space_names[] = {
186 "Space 0", "User Data", "User Program", "Space 3",
187 "Space 4", "Super Data", "Super Program", "CPU"
189 #else
190 static char *space_names[] = {
191 "Space 0", "User Data", "User Program", "Control",
192 "Space 4", "Super Data", "Super Program", "CPU"
194 #endif
196 void die_if_kernel(char *,struct pt_regs *,int);
197 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
198 unsigned long error_code);
199 int send_fault_sig(struct pt_regs *regs);
201 asmlinkage void trap_c(struct frame *fp);
203 #if defined (CONFIG_M68060)
204 static inline void access_error060 (struct frame *fp)
206 unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
208 #ifdef DEBUG
209 printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
210 #endif
212 if (fslw & MMU060_BPE) {
213 /* branch prediction error -> clear branch cache */
214 __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
215 "orl #0x00400000,%/d0\n\t"
216 "movec %/d0,%/cacr"
217 : : : "d0" );
218 /* return if there's no other error */
219 if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
220 return;
223 if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
224 unsigned long errorcode;
225 unsigned long addr = fp->un.fmt4.effaddr;
227 if (fslw & MMU060_MA)
228 addr = (addr + 7) & -8;
230 errorcode = 1;
231 if (fslw & MMU060_DESC_ERR) {
232 __flush_tlb040_one(addr);
233 errorcode = 0;
235 if (fslw & MMU060_W)
236 errorcode |= 2;
237 #ifdef DEBUG
238 printk("errorcode = %d\n", errorcode );
239 #endif
240 do_page_fault(&fp->ptregs, addr, errorcode);
241 } else if (fslw & (MMU060_SEE)){
242 /* Software Emulation Error.
243 * fault during mem_read/mem_write in ifpsp060/os.S
245 send_fault_sig(&fp->ptregs);
246 } else {
247 printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
248 printk( "68060 access error, fslw=%lx\n", fslw );
249 trap_c( fp );
252 #endif /* CONFIG_M68060 */
254 #if defined (CONFIG_M68040)
255 static inline unsigned long probe040(int iswrite, unsigned long addr)
257 unsigned long mmusr;
259 asm volatile (".chip 68040");
261 if (iswrite)
262 asm volatile ("ptestw (%0)" : : "a" (addr));
263 else
264 asm volatile ("ptestr (%0)" : : "a" (addr));
266 asm volatile ("movec %%mmusr,%0" : "=r" (mmusr));
268 asm volatile (".chip 68k");
270 return mmusr;
273 static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
274 unsigned long wbd)
276 int res = 0;
278 set_fs(MAKE_MM_SEG(wbs));
280 switch (wbs & WBSIZ_040) {
281 case BA_SIZE_BYTE:
282 res = put_user(wbd & 0xff, (char *)wba);
283 break;
284 case BA_SIZE_WORD:
285 res = put_user(wbd & 0xffff, (short *)wba);
286 break;
287 case BA_SIZE_LONG:
288 res = put_user(wbd, (int *)wba);
289 break;
292 #ifdef DEBUG
293 printk("do_040writeback1, res=%d\n",res);
294 #endif
296 return res;
299 /* after an exception in a writeback the stack frame coresponding
300 * to that exception is discarded, set a few bits in the old frame
301 * to simulate what it should look like
303 static inline void fix_xframe040(struct frame *fp, unsigned short wbs)
305 fp->un.fmt7.faddr = current->thread.faddr;
306 fp->un.fmt7.ssw = wbs & 0xff;
309 static inline void do_040writebacks(struct frame *fp)
311 int res = 0;
312 #if 0
313 if (fp->un.fmt7.wb1s & WBV_040)
314 printk("access_error040: cannot handle 1st writeback. oops.\n");
315 #endif
317 if ((fp->un.fmt7.wb2s & WBV_040) &&
318 !(fp->un.fmt7.wb2s & WBTT_040)) {
319 res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
320 fp->un.fmt7.wb2d);
321 if (res)
322 fix_xframe040(fp, fp->un.fmt7.wb2s);
323 else
324 fp->un.fmt7.wb2s = 0;
327 /* do the 2nd wb only if the first one was succesful (except for a kernel wb) */
328 if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
329 res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
330 fp->un.fmt7.wb3d);
331 if (res)
332 fix_xframe040(fp, fp->un.fmt7.wb3s);
333 else
334 fp->un.fmt7.wb3s = 0;
337 if (res)
338 send_fault_sig(&fp->ptregs);
342 * called from sigreturn(), must ensure userspace code didn't
343 * manipulate exception frame to circumvent protection, then complete
344 * pending writebacks
345 * we just clear TM2 to turn it into an userspace access
347 asmlinkage void berr_040cleanup(struct frame *fp)
349 mm_segment_t old_fs = get_fs();
351 fp->un.fmt7.wb2s &= ~4;
352 fp->un.fmt7.wb3s &= ~4;
354 do_040writebacks(fp);
355 set_fs(old_fs);
358 static inline void access_error040(struct frame *fp)
360 unsigned short ssw = fp->un.fmt7.ssw;
361 mm_segment_t old_fs = get_fs();
362 unsigned long mmusr;
364 #ifdef DEBUG
365 printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
366 printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
367 fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
368 printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
369 fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
370 fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
371 #endif
373 if (ssw & ATC_040) {
374 unsigned long addr = fp->un.fmt7.faddr;
375 unsigned long errorcode;
378 * The MMU status has to be determined AFTER the address
379 * has been corrected if there was a misaligned access (MA).
381 if (ssw & MA_040)
382 addr = (addr + 7) & -8;
384 set_fs(MAKE_MM_SEG(ssw));
385 /* MMU error, get the MMUSR info for this access */
386 mmusr = probe040(!(ssw & RW_040), addr);
387 #ifdef DEBUG
388 printk("mmusr = %lx\n", mmusr);
389 #endif
390 errorcode = 1;
391 if (!(mmusr & MMU_R_040)) {
392 /* clear the invalid atc entry */
393 __flush_tlb040_one(addr);
394 errorcode = 0;
396 if (!(ssw & RW_040))
397 errorcode |= 2;
398 if (do_page_fault(&fp->ptregs, addr, errorcode)) {
399 #ifdef DEBUG
400 printk("do_page_fault() !=0 \n");
401 #endif
402 if (user_mode(&fp->ptregs)){
403 /* delay writebacks after signal delivery */
404 #ifdef DEBUG
405 printk(".. was usermode - return\n");
406 #endif
407 return;
409 /* disable writeback into user space from kernel
410 * (if do_page_fault didn't fix the mapping,
411 * the writeback won't do good)
413 #ifdef DEBUG
414 printk(".. disabling wb2\n");
415 #endif
416 if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
417 fp->un.fmt7.wb2s &= ~WBV_040;
419 } else {
420 printk("68040 access error, ssw=%x\n", ssw);
421 trap_c(fp);
424 do_040writebacks(fp);
425 set_fs(old_fs);
427 #endif /* CONFIG_M68040 */
429 #if defined(CONFIG_SUN3)
430 #include <asm/sun3mmu.h>
432 extern int mmu_emu_handle_fault (unsigned long, int, int);
434 /* sun3 version of bus_error030 */
436 extern inline void bus_error030 (struct frame *fp)
438 unsigned char buserr_type = sun3_get_buserr ();
439 unsigned long addr, errorcode;
440 unsigned short ssw = fp->un.fmtb.ssw;
442 #if DEBUG
443 if (ssw & (FC | FB))
444 printk ("Instruction fault at %#010lx\n",
445 ssw & FC ?
446 fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
448 fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
449 if (ssw & DF)
450 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
451 ssw & RW ? "read" : "write",
452 fp->un.fmtb.daddr,
453 space_names[ssw & DFC], fp->ptregs.pc);
454 #endif
457 * Check if this page should be demand-mapped. This needs to go before
458 * the testing for a bad kernel-space access (demand-mapping applies
459 * to kernel accesses too).
462 if ((ssw & DF)
463 && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
464 if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
465 return;
468 /* Check for kernel-space pagefault (BAD). */
469 if (fp->ptregs.sr & PS_S) {
470 /* kernel fault must be a data fault to user space */
471 if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
472 // try checking the kernel mappings before surrender
473 if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
474 return;
475 /* instruction fault or kernel data fault! */
476 if (ssw & (FC | FB))
477 printk ("Instruction fault at %#010lx\n",
478 fp->ptregs.pc);
479 if (ssw & DF) {
480 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
481 ssw & RW ? "read" : "write",
482 fp->un.fmtb.daddr,
483 space_names[ssw & DFC], fp->ptregs.pc);
485 printk ("BAD KERNEL BUSERR\n");
487 die_if_kernel("Oops", &fp->ptregs,0);
488 force_sig(SIGKILL, current);
489 return;
491 } else {
492 /* user fault */
493 if (!(ssw & (FC | FB)) && !(ssw & DF))
494 /* not an instruction fault or data fault! BAD */
495 panic ("USER BUSERR w/o instruction or data fault");
499 /* First handle the data fault, if any. */
500 if (ssw & DF) {
501 addr = fp->un.fmtb.daddr;
503 // errorcode bit 0: 0 -> no page 1 -> protection fault
504 // errorcode bit 1: 0 -> read fault 1 -> write fault
506 // (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
507 // (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
509 if (buserr_type & SUN3_BUSERR_PROTERR)
510 errorcode = 0x01;
511 else if (buserr_type & SUN3_BUSERR_INVALID)
512 errorcode = 0x00;
513 else {
514 #ifdef DEBUG
515 printk ("*** unexpected busfault type=%#04x\n", buserr_type);
516 printk ("invalid %s access at %#lx from pc %#lx\n",
517 !(ssw & RW) ? "write" : "read", addr,
518 fp->ptregs.pc);
519 #endif
520 die_if_kernel ("Oops", &fp->ptregs, buserr_type);
521 force_sig (SIGBUS, current);
522 return;
525 //todo: wtf is RM bit? --m
526 if (!(ssw & RW) || ssw & RM)
527 errorcode |= 0x02;
529 /* Handle page fault. */
530 do_page_fault (&fp->ptregs, addr, errorcode);
532 /* Retry the data fault now. */
533 return;
536 /* Now handle the instruction fault. */
538 /* Get the fault address. */
539 if (fp->ptregs.format == 0xA)
540 addr = fp->ptregs.pc + 4;
541 else
542 addr = fp->un.fmtb.baddr;
543 if (ssw & FC)
544 addr -= 2;
546 if (buserr_type & SUN3_BUSERR_INVALID) {
547 if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
548 do_page_fault (&fp->ptregs, addr, 0);
549 } else {
550 #ifdef DEBUG
551 printk ("protection fault on insn access (segv).\n");
552 #endif
553 force_sig (SIGSEGV, current);
556 #else
557 #if defined(CPU_M68020_OR_M68030)
558 static inline void bus_error030 (struct frame *fp)
560 volatile unsigned short temp;
561 unsigned short mmusr;
562 unsigned long addr, errorcode;
563 unsigned short ssw = fp->un.fmtb.ssw;
564 int user_space_fault = 1;
565 #if DEBUG
566 unsigned long desc;
567 #endif
569 #if DEBUG
570 printk ("pid = %x ", current->pid);
571 printk ("SSW=%#06x ", ssw);
573 if (ssw & (FC | FB))
574 printk ("Instruction fault at %#010lx\n",
575 ssw & FC ?
576 fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
578 fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
579 if (ssw & DF)
580 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
581 ssw & RW ? "read" : "write",
582 fp->un.fmtb.daddr,
583 space_names[ssw & DFC], fp->ptregs.pc);
584 #endif
586 if (fp->ptregs.sr & PS_S) {
587 /* kernel fault must be a data fault to user space */
588 if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
589 /* instruction fault or kernel data fault! */
590 if (ssw & (FC | FB))
591 printk ("Instruction fault at %#010lx\n",
592 fp->ptregs.pc);
593 if (ssw & DF) {
594 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
595 ssw & RW ? "read" : "write",
596 fp->un.fmtb.daddr,
597 space_names[ssw & DFC], fp->ptregs.pc);
599 printk ("BAD KERNEL BUSERR\n");
600 die_if_kernel("Oops",&fp->ptregs,0);
601 force_sig(SIGKILL, current);
602 return;
604 } else {
605 /* user fault */
606 if (!(ssw & (FC | FB)) && !(ssw & DF))
607 /* not an instruction fault or data fault! BAD */
608 panic ("USER BUSERR w/o instruction or data fault");
609 user_space_fault = 1;
610 #if DEBUG
611 printk("User space bus-error\n");
612 #endif
615 /* ++andreas: If a data fault and an instruction fault happen
616 at the same time map in both pages. */
618 /* First handle the data fault, if any. */
619 if (ssw & DF)
621 addr = fp->un.fmtb.daddr;
623 mmusr = MMU_I;
624 if (user_space_fault) {
625 #if DEBUG
626 asm volatile ("ptestr #1,%2@,#7,%0\n\t"
627 "pmove %/psr,%1@"
628 : "=a&" (desc)
629 : "a" (&temp), "a" (addr));
630 #else
631 asm volatile ("ptestr #1,%1@,#7\n\t"
632 "pmove %/psr,%0@"
633 : : "a" (&temp), "a" (addr));
634 #endif
635 mmusr = temp;
638 #if DEBUG
639 printk ("mmusr is %#x for addr %#lx in task %p\n",
640 mmusr, addr, current);
641 printk ("descriptor address is %#lx, contents %#lx\n",
642 __va(desc), *(unsigned long *)__va(desc));
643 #endif
645 errorcode = (mmusr & MMU_I) ? 0 : 1;
646 if (!(ssw & RW) || (ssw & RM))
647 errorcode |= 2;
649 if (mmusr & (MMU_I | MMU_WP)) {
650 /* Don't try to do anything further if an exception was
651 handled. */
652 if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
653 return;
654 } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
655 printk ("invalid %s access at %#lx from pc %#lx\n",
656 !(ssw & RW) ? "write" : "read", addr,
657 fp->ptregs.pc);
658 die_if_kernel("Oops",&fp->ptregs,mmusr);
659 force_sig(SIGSEGV, current);
660 return;
661 } else {
662 #if 0
663 static volatile long tlong;
664 #endif
666 printk ("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
667 !(ssw & RW) ? "write" : "read", addr,
668 fp->ptregs.pc, ssw);
669 asm volatile ("ptestr #1,%1@,#0\n\t"
670 "pmove %/psr,%0@"
671 : /* no outputs */
672 : "a" (&temp), "a" (addr));
673 mmusr = temp;
675 printk ("level 0 mmusr is %#x\n", mmusr);
676 #if 0
677 asm volatile ("pmove %/tt0,%0@"
678 : /* no outputs */
679 : "a" (&tlong));
680 printk ("tt0 is %#lx, ", tlong);
681 asm volatile ("pmove %/tt1,%0@"
682 : /* no outputs */
683 : "a" (&tlong));
684 printk ("tt1 is %#lx\n", tlong);
685 #endif
686 #if DEBUG
687 printk("Unknown SIGSEGV - 1\n");
688 #endif
689 die_if_kernel("Oops",&fp->ptregs,mmusr);
690 force_sig(SIGSEGV, current);
691 return;
694 /* setup an ATC entry for the access about to be retried */
695 if (!(ssw & RW))
696 asm volatile ("ploadw %1,%0@" : /* no outputs */
697 : "a" (addr), "d" (ssw));
698 else
699 asm volatile ("ploadr %1,%0@" : /* no outputs */
700 : "a" (addr), "d" (ssw));
703 /* Now handle the instruction fault. */
705 if (!(ssw & (FC|FB)))
706 return;
708 /* get the fault address */
709 if (fp->ptregs.format == 10)
710 addr = fp->ptregs.pc + 4;
711 else
712 addr = fp->un.fmtb.baddr;
713 if (ssw & FC)
714 addr -= 2;
716 if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
717 /* Insn fault on same page as data fault. But we
718 should still create the ATC entry. */
719 goto create_atc_entry;
721 mmusr = MMU_I;
722 if (user_space_fault) {
723 #if DEBUG
724 asm volatile ("ptestr #1,%2@,#7,%0\n\t"
725 "pmove %/psr,%1@"
726 : "=a&" (desc)
727 : "a" (&temp), "a" (addr));
728 #else
729 asm volatile ("ptestr #1,%1@,#7\n\t"
730 "pmove %/psr,%0@"
731 : : "a" (&temp), "a" (addr));
732 #endif
733 mmusr = temp;
736 #ifdef DEBUG
737 printk ("mmusr is %#x for addr %#lx in task %p\n",
738 mmusr, addr, current);
739 printk ("descriptor address is %#lx, contents %#lx\n",
740 __va(desc), *(unsigned long *)__va(desc));
741 #endif
743 if (mmusr & MMU_I)
744 do_page_fault (&fp->ptregs, addr, 0);
745 else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
746 printk ("invalid insn access at %#lx from pc %#lx\n",
747 addr, fp->ptregs.pc);
748 #if DEBUG
749 printk("Unknown SIGSEGV - 2\n");
750 #endif
751 die_if_kernel("Oops",&fp->ptregs,mmusr);
752 force_sig(SIGSEGV, current);
753 return;
756 create_atc_entry:
757 /* setup an ATC entry for the access about to be retried */
758 asm volatile ("ploadr #2,%0@" : /* no outputs */
759 : "a" (addr));
761 #endif /* CPU_M68020_OR_M68030 */
762 #endif /* !CONFIG_SUN3 */
764 asmlinkage void buserr_c(struct frame *fp)
766 /* Only set esp0 if coming from user mode */
767 if (user_mode(&fp->ptregs))
768 current->thread.esp0 = (unsigned long) fp;
770 #if DEBUG
771 printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
772 #endif
774 switch (fp->ptregs.format) {
775 #if defined (CONFIG_M68060)
776 case 4: /* 68060 access error */
777 access_error060 (fp);
778 break;
779 #endif
780 #if defined (CONFIG_M68040)
781 case 0x7: /* 68040 access error */
782 access_error040 (fp);
783 break;
784 #endif
785 #if defined (CPU_M68020_OR_M68030)
786 case 0xa:
787 case 0xb:
788 bus_error030 (fp);
789 break;
790 #endif
791 default:
792 die_if_kernel("bad frame format",&fp->ptregs,0);
793 #if DEBUG
794 printk("Unknown SIGSEGV - 4\n");
795 #endif
796 force_sig(SIGSEGV, current);
801 int kstack_depth_to_print = 48;
803 /* MODULE_RANGE is a guess of how much space is likely to be
804 vmalloced. */
805 #define MODULE_RANGE (8*1024*1024)
807 static void dump_stack(struct frame *fp)
809 unsigned long *stack, *endstack, addr, module_start, module_end;
810 extern char _start, _etext;
811 int i;
813 addr = (unsigned long)&fp->un;
814 printk("Frame format=%X ", fp->ptregs.format);
815 switch (fp->ptregs.format) {
816 case 0x2:
817 printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
818 addr += sizeof(fp->un.fmt2);
819 break;
820 case 0x3:
821 printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
822 addr += sizeof(fp->un.fmt3);
823 break;
824 case 0x4:
825 printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
826 : "eff addr=%08lx pc=%08lx\n"),
827 fp->un.fmt4.effaddr, fp->un.fmt4.pc);
828 addr += sizeof(fp->un.fmt4);
829 break;
830 case 0x7:
831 printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
832 fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
833 printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
834 fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
835 printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
836 fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
837 printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
838 fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
839 printk("push data: %08lx %08lx %08lx %08lx\n",
840 fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
841 fp->un.fmt7.pd3);
842 addr += sizeof(fp->un.fmt7);
843 break;
844 case 0x9:
845 printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
846 addr += sizeof(fp->un.fmt9);
847 break;
848 case 0xa:
849 printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
850 fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
851 fp->un.fmta.daddr, fp->un.fmta.dobuf);
852 addr += sizeof(fp->un.fmta);
853 break;
854 case 0xb:
855 printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
856 fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
857 fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
858 printk("baddr=%08lx dibuf=%08lx ver=%x\n",
859 fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
860 addr += sizeof(fp->un.fmtb);
861 break;
862 default:
863 printk("\n");
866 stack = (unsigned long *)addr;
867 endstack = (unsigned long *)PAGE_ALIGN(addr);
869 printk("Stack from %08lx:", (unsigned long)stack);
870 for (i = 0; i < kstack_depth_to_print; i++) {
871 if (stack + 1 > endstack)
872 break;
873 if (i % 8 == 0)
874 printk("\n ");
875 printk(" %08lx", *stack++);
878 printk ("\nCall Trace:");
879 stack = (unsigned long *) addr;
880 i = 0;
881 module_start = VMALLOC_START;
882 module_end = module_start + MODULE_RANGE;
883 while (stack + 1 <= endstack) {
884 addr = *stack++;
886 * If the address is either in the text segment of the
887 * kernel, or in the region which contains vmalloc'ed
888 * memory, it *may* be the address of a calling
889 * routine; if so, print it so that someone tracing
890 * down the cause of the crash will be able to figure
891 * out the call path that was taken.
893 if (((addr >= (unsigned long) &_start) &&
894 (addr <= (unsigned long) &_etext)) ||
895 ((addr >= module_start) && (addr <= module_end))) {
896 if (i % 4 == 0)
897 printk("\n ");
898 printk(" [<%08lx>]", addr);
899 i++;
902 printk("\nCode: ");
903 for (i = 0; i < 10; i++)
904 printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
905 printk ("\n");
908 void bad_super_trap (struct frame *fp)
910 console_verbose();
911 if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0]))
912 printk ("*** %s *** FORMAT=%X\n",
913 vec_names[(fp->ptregs.vector) >> 2],
914 fp->ptregs.format);
915 else
916 printk ("*** Exception %d *** FORMAT=%X\n",
917 (fp->ptregs.vector) >> 2,
918 fp->ptregs.format);
919 if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
920 unsigned short ssw = fp->un.fmtb.ssw;
922 printk ("SSW=%#06x ", ssw);
924 if (ssw & RC)
925 printk ("Pipe stage C instruction fault at %#010lx\n",
926 (fp->ptregs.format) == 0xA ?
927 fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
928 if (ssw & RB)
929 printk ("Pipe stage B instruction fault at %#010lx\n",
930 (fp->ptregs.format) == 0xA ?
931 fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
932 if (ssw & DF)
933 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
934 ssw & RW ? "read" : "write",
935 fp->un.fmtb.daddr, space_names[ssw & DFC],
936 fp->ptregs.pc);
938 printk ("Current process id is %d\n", current->pid);
939 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
942 asmlinkage void trap_c(struct frame *fp)
944 int sig;
945 siginfo_t info;
947 if (fp->ptregs.sr & PS_S) {
948 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
949 /* traced a trapping instruction */
950 current->ptrace |= PT_DTRACE;
951 } else
952 bad_super_trap(fp);
953 return;
956 /* send the appropriate signal to the user program */
957 switch ((fp->ptregs.vector) >> 2) {
958 case VEC_ADDRERR:
959 info.si_code = BUS_ADRALN;
960 sig = SIGBUS;
961 break;
962 case VEC_ILLEGAL:
963 case VEC_LINE10:
964 case VEC_LINE11:
965 info.si_code = ILL_ILLOPC;
966 sig = SIGILL;
967 break;
968 case VEC_PRIV:
969 info.si_code = ILL_PRVOPC;
970 sig = SIGILL;
971 break;
972 case VEC_COPROC:
973 info.si_code = ILL_COPROC;
974 sig = SIGILL;
975 break;
976 case VEC_TRAP1:
977 case VEC_TRAP2:
978 case VEC_TRAP3:
979 case VEC_TRAP4:
980 case VEC_TRAP5:
981 case VEC_TRAP6:
982 case VEC_TRAP7:
983 case VEC_TRAP8:
984 case VEC_TRAP9:
985 case VEC_TRAP10:
986 case VEC_TRAP11:
987 case VEC_TRAP12:
988 case VEC_TRAP13:
989 case VEC_TRAP14:
990 info.si_code = ILL_ILLTRP;
991 sig = SIGILL;
992 break;
993 case VEC_FPBRUC:
994 case VEC_FPOE:
995 case VEC_FPNAN:
996 info.si_code = FPE_FLTINV;
997 sig = SIGFPE;
998 break;
999 case VEC_FPIR:
1000 info.si_code = FPE_FLTRES;
1001 sig = SIGFPE;
1002 break;
1003 case VEC_FPDIVZ:
1004 info.si_code = FPE_FLTDIV;
1005 sig = SIGFPE;
1006 break;
1007 case VEC_FPUNDER:
1008 info.si_code = FPE_FLTUND;
1009 sig = SIGFPE;
1010 break;
1011 case VEC_FPOVER:
1012 info.si_code = FPE_FLTOVF;
1013 sig = SIGFPE;
1014 break;
1015 case VEC_ZERODIV:
1016 info.si_code = FPE_INTDIV;
1017 sig = SIGFPE;
1018 break;
1019 case VEC_CHK:
1020 case VEC_TRAP:
1021 info.si_code = FPE_INTOVF;
1022 sig = SIGFPE;
1023 break;
1024 case VEC_TRACE: /* ptrace single step */
1025 info.si_code = TRAP_TRACE;
1026 sig = SIGTRAP;
1027 break;
1028 case VEC_TRAP15: /* breakpoint */
1029 info.si_code = TRAP_BRKPT;
1030 sig = SIGTRAP;
1031 break;
1032 default:
1033 info.si_code = ILL_ILLOPC;
1034 sig = SIGILL;
1035 break;
1037 info.si_signo = sig;
1038 info.si_errno = 0;
1039 switch (fp->ptregs.format) {
1040 default:
1041 info.si_addr = (void *) fp->ptregs.pc;
1042 break;
1043 case 2:
1044 info.si_addr = (void *) fp->un.fmt2.iaddr;
1045 break;
1046 case 7:
1047 info.si_addr = (void *) fp->un.fmt7.effaddr;
1048 break;
1049 case 9:
1050 info.si_addr = (void *) fp->un.fmt9.iaddr;
1051 break;
1052 case 10:
1053 info.si_addr = (void *) fp->un.fmta.daddr;
1054 break;
1055 case 11:
1056 info.si_addr = (void *) fp->un.fmtb.daddr;
1057 break;
1059 force_sig_info (sig, &info, current);
1062 void die_if_kernel (char *str, struct pt_regs *fp, int nr)
1064 if (!(fp->sr & PS_S))
1065 return;
1067 console_verbose();
1068 printk("%s: %08x\n",str,nr);
1069 printk("PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
1070 fp->pc, fp->sr, fp, fp->a2);
1071 printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
1072 fp->d0, fp->d1, fp->d2, fp->d3);
1073 printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
1074 fp->d4, fp->d5, fp->a0, fp->a1);
1076 printk("Process %s (pid: %d, stackpage=%08lx)\n",
1077 current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
1078 dump_stack((struct frame *)fp);
1079 do_exit(SIGSEGV);
1083 * This function is called if an error occur while accessing
1084 * user-space from the fpsp040 code.
1086 asmlinkage void fpsp040_die(void)
1088 do_exit(SIGSEGV);
1091 #ifdef CONFIG_M68KFPU_EMU
1092 asmlinkage void fpemu_signal(int signal, int code, void *addr)
1094 siginfo_t info;
1096 info.si_signo = signal;
1097 info.si_errno = 0;
1098 info.si_code = code;
1099 info.si_addr = addr;
1100 force_sig_info(signal, &info, current);
1102 #endif