home *** CD-ROM | disk | FTP | other *** search
- /*
- * arch/mips/kernel/traps.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
- /*
- * 'traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
- * to mainly kill the offending process (probably by giving it a signal,
- * but possibly by killing it outright if necessary).
- */
- #include <linux/head.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/signal.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/ptrace.h>
- #include <linux/config.h>
- #include <linux/timer.h>
-
- #include <asm/system.h>
- #include <asm/segment.h>
- #include <asm/io.h>
- #include <asm/mipsregs.h>
- #include <asm/bootinfo.h>
-
- static inline void console_verbose(void)
- {
- extern int console_loglevel;
- console_loglevel = 15;
- }
-
- #define get_seg_byte(seg,addr) ({ \
- register unsigned char __res; \
- __res = get_user_byte(addr); \
- __res;})
-
- #define get_seg_long(seg,addr) ({ \
- register unsigned long __res; \
- __res = get_user_word(addr); \
- __res;})
-
- extern asmlinkage void deskstation_tyne_handle_int(void);
- extern asmlinkage void acer_pica_61_handle_int(void);
- extern asmlinkage void handle_mod(void);
- extern asmlinkage void handle_tlbl(void);
- extern asmlinkage void handle_tlbs(void);
- extern asmlinkage void handle_adel(void);
- extern asmlinkage void handle_ades(void);
- extern asmlinkage void handle_ibe(void);
- extern asmlinkage void handle_dbe(void);
- extern asmlinkage void handle_sys(void);
- extern asmlinkage void handle_bp(void);
- extern asmlinkage void handle_ri(void);
- extern asmlinkage void handle_cpu(void);
- extern asmlinkage void handle_ov(void);
- extern asmlinkage void handle_tr(void);
- extern asmlinkage void handle_vcei(void);
- extern asmlinkage void handle_fpe(void);
- extern asmlinkage void handle_vced(void);
- extern asmlinkage void handle_watch(void);
- extern asmlinkage void handle_reserved(void);
-
- char *cpu_names[] = CPU_NAMES;
-
- int kstack_depth_to_print = 24;
-
- /*
- * These constants are for searching for possible module text
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
- #define VMALLOC_OFFSET (8*1024*1024)
- #define MODULE_RANGE (8*1024*1024)
-
- void die_if_kernel(char * str, struct pt_regs * regs, long err)
- {
- int i;
- unsigned long *sp, *pc;
- unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, etext;
-
- if (regs->cp0_status & (ST0_ERL|ST0_EXL) == 0)
- return;
-
- sp = (unsigned long *)regs->reg29;
- pc = (unsigned long *)regs->cp0_epc;
-
- console_verbose();
- printk("%s: %08lx\n", str, err );
-
- /*
- * Saved main processor registers
- */
- printk("at : %08lx\n", regs->reg1);
- printk("v0 : %08lx %08lx\n", regs->reg2, regs->reg3);
- printk("a0 : %08lx %08lx %08lx %08lx\n",
- regs->reg4, regs->reg5, regs->reg6, regs->reg7);
- printk("t0 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg8, regs->reg9, regs->reg10, regs->reg11, regs->reg12);
- printk("t5 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg13, regs->reg14, regs->reg15, regs->reg24, regs->reg25);
- printk("s0 : %08lx %08lx %08lx %08lx\n",
- regs->reg16, regs->reg17, regs->reg18, regs->reg19);
- printk("s4 : %08lx %08lx %08lx %08lx\n",
- regs->reg20, regs->reg21, regs->reg22, regs->reg23);
- printk("gp : %08lx\n", regs->reg28);
- printk("sp : %08lx\n", regs->reg29);
- printk("fp/s8: %08lx\n", regs->reg30);
- printk("ra : %08lx\n", regs->reg31);
-
- /*
- * Saved cp0 registers
- */
- printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
- regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
-
- /*
- * Some goodies...
- */
- printk("Int : %ld\n", regs->interrupt);
-
- /*
- * Dump the stack
- */
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
- printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i,
- current->kernel_stack_page);
- for(i=0;i<5;i++)
- printk("%08lx ", *sp++);
- stack = (unsigned long *) sp;
- for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & 4095) == 0)
- break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", get_seg_long(ss,stack++));
- }
- printk("\nCall Trace: ");
- stack = (unsigned long *) sp;
- i = 1;
- module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
- module_end = module_start + MODULE_RANGE;
- while (((long) stack & 4095) != 0) {
- addr = get_seg_long(ss, stack++);
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (((addr >= (unsigned long) &start_kernel) &&
- (addr <= (unsigned long) &etext)) ||
- ((addr >= module_start) && (addr <= module_end))) {
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", addr);
- i++;
- }
- }
-
- printk("\nCode : ");
- for(i=0;i<5;i++)
- printk("%08lx ", *pc++);
- printk("\n");
- do_exit(SIGSEGV);
- }
-
- void do_adel(struct pt_regs *regs)
- {
- send_sig(SIGSEGV, current, 1);
- }
-
- void do_ades(struct pt_regs *regs)
- {
- send_sig(SIGSEGV, current, 1);
- }
-
- void do_ibe(struct pt_regs *regs)
- {
- send_sig(SIGSEGV, current, 1);
- }
-
- void do_dbe(struct pt_regs *regs)
- {
- send_sig(SIGSEGV, current, 1);
- }
-
- void do_ov(struct pt_regs *regs)
- {
- send_sig(SIGFPE, current, 1);
- }
-
- void do_fpe(struct pt_regs *regs)
- {
- /*
- * FIXME: This is the place for a fpu emulator. Not written
- * yet and the demand seems to be quite low.
- */
- printk("Caught FPE exception at %lx.\n", regs->cp0_epc);
- send_sig(SIGFPE, current, 1);
- }
-
- void do_bp(struct pt_regs *regs)
- {
- send_sig(SIGILL, current, 1);
- }
-
- void do_tr(struct pt_regs *regs)
- {
- send_sig(SIGILL, current, 1);
- }
-
- void do_ri(struct pt_regs *regs)
- {
- send_sig(SIGILL, current, 1);
- }
-
- void do_cpu(struct pt_regs *regs)
- {
- unsigned long pc;
- unsigned int insn;
-
- /*
- * Check whether this was a cp1 instruction
- */
- pc = regs->cp0_epc;
- if (regs->cp0_cause & (1<<31))
- pc += 4;
- insn = *(unsigned int *)pc;
- insn &= 0xfc000000;
- switch(insn) {
- case 0x44000000:
- case 0xc4000000:
- case 0xe4000000:
- printk("CP1 instruction - enabling cp1.\n");
- regs->cp0_status |= ST0_CU1;
- /*
- * No need to handle branch delay slots
- */
- break;
- default:
- /*
- * This wasn't a cp1 instruction and therefore illegal.
- * Default is to kill the process.
- */
- send_sig(SIGILL, current, 1);
- }
- }
-
- void do_vcei(struct pt_regs *regs)
- {
- /*
- * Only possible on R4[04]00[SM]C. No handler because
- * I don't have such a cpu.
- */
- panic("Caught VCEI exception - can't handle yet\n");
- }
-
- void do_vced(struct pt_regs *regs)
- {
- /*
- * Only possible on R4[04]00[SM]C. No handler because
- * I don't have such a cpu.
- */
- panic("Caught VCED exception - can't handle yet\n");
- }
-
- void do_watch(struct pt_regs *regs)
- {
- /*
- * Only possible on R4[04]00. No way to handle this because
- * I don't have such a cpu.
- */
- panic("Caught WATCH exception - can't handle yet\n");
- }
-
- void do_reserved(struct pt_regs *regs)
- {
- /*
- * Game over - no way to handle this if it ever occurs.
- * Most probably caused by a new unknown cpu type or a
- * after another deadly hard/software error.
- */
- panic("Caught reserved exception - can't handle.\n");
- }
-
- void trap_init(void)
- {
- int i;
-
- /*
- * FIXME: Mips Magnum R4000 has an EISA bus!
- */
- EISA_bus = 0;
-
- /*
- * Setup default vectors
- */
- for (i=0;i<=31;i++)
- set_except_vector(i, handle_reserved);
-
- /*
- * Handling the following exceptions depends mostly of the cpu type
- */
- switch(boot_info.cputype) {
- case CPU_R4000MC:
- case CPU_R4400MC:
- case CPU_R4000SC:
- case CPU_R4400SC:
- /*
- * Handlers not implemented yet
- */
- set_except_vector(14, handle_vcei);
- set_except_vector(31, handle_vced);
- case CPU_R4000PC:
- case CPU_R4400PC:
- /*
- * Handler not implemented yet
- */
- set_except_vector(23, handle_watch);
- case CPU_R4200:
- case CPU_R4600:
- set_except_vector(1, handle_mod);
- set_except_vector(2, handle_tlbl);
- set_except_vector(3, handle_tlbs);
- set_except_vector(4, handle_adel);
- set_except_vector(5, handle_ades);
- set_except_vector(6, handle_ibe);
- set_except_vector(7, handle_dbe);
- set_except_vector(8, handle_sys);
- set_except_vector(9, handle_bp);
- set_except_vector(10, handle_ri);
- set_except_vector(11, handle_cpu);
- set_except_vector(12, handle_ov);
- set_except_vector(13, handle_tr);
- set_except_vector(15, handle_fpe);
- break;
- case CPU_R2000:
- case CPU_R3000:
- case CPU_R3000A:
- case CPU_R3041:
- case CPU_R3051:
- case CPU_R3052:
- case CPU_R3081:
- case CPU_R3081E:
- case CPU_R6000:
- case CPU_R6000A:
- case CPU_R8000:
- case CPU_R10000:
- printk("Detected unsupported CPU type %s.\n",
- cpu_names[boot_info.cputype]);
- panic("Can't handle CPU\n");
- break;
- case CPU_UNKNOWN:
- default:
- panic("Unknown type of CPU");
- }
-
- /*
- * The interrupt handler depends of both type of the board and cpu
- */
- switch(boot_info.machtype) {
- case MACH_DESKSTATION_TYNE:
- set_except_vector(0, deskstation_tyne_handle_int);
- break;
- case MACH_ACER_PICA_61:
- set_except_vector(0, acer_pica_61_handle_int);
- break;
- default:
- panic("Unknown machine type");
- }
- }
-