/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include 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"); } }