URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [mips/] [kernel/] [traps.c] - Rev 1777
Go to most recent revision | Compare with Previous | Blame | View Log
/* * arch/mips/kernel/traps.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ /* * '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). * * FIXME: This is the place for a fpu emulator. */ #include <linux/head.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/string.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/timer.h> #include <linux/mm.h> #include <asm/vector.h> #include <asm/page.h> #include <asm/pgtable.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; } /* * Machine specific interrupt handlers */ extern asmlinkage void acer_pica_61_handle_int(void); extern asmlinkage void decstation_handle_int(void); extern asmlinkage void deskstation_rpc44_handle_int(void); extern asmlinkage void deskstation_tyne_handle_int(void); extern asmlinkage void mips_magnum_4000_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); static char *cpu_names[] = CPU_NAMES; unsigned long page_colour_mask; int kstack_depth_to_print = 24; /* * These constant is for searching for possible module text segments. * MODULE_RANGE is a guess of how much space is likely to be vmalloced. */ #define MODULE_RANGE (8*1024*1024) void die_if_kernel(char * str, struct pt_regs * regs, long err) { int i; int *stack; u32 *sp, *pc, addr, module_start, module_end; extern char start_kernel, _etext; if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0) return; sp = (u32 *)regs->reg29; pc = (u32 *)regs->cp0_epc; console_verbose(); printk("%s: %08lx\n", str, err ); show_regs(regs); /* * Dump the stack */ if (STACK_MAGIC != *(u32 *)current->kernel_stack_page) printk("Corrupted stack page\n"); printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ", current->comm, current->pid, current->kernel_stack_page); for(i=0;i<5;i++) printk("%08x ", *sp++); stack = (int *) sp; for(i=0; i < kstack_depth_to_print; i++) { if (((u32) stack & (PAGE_SIZE -1)) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); printk("%08lx ", get_user(stack++)); } printk("\nCall Trace: "); stack = (int *)sp; i = 1; module_start = VMALLOC_START; module_end = module_start + MODULE_RANGE; while (((u32)stack & (PAGE_SIZE -1)) != 0) { addr = get_user(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 >= (u32) &start_kernel) && (addr <= (u32) &_etext)) || ((addr >= module_start) && (addr <= module_end))) { if (i && ((i % 8) == 0)) printk("\n "); printk("%08x ", addr); i++; } } printk("\nCode : "); if ((!verify_area(VERIFY_READ, pc, 5 * sizeof(*pc)) || KSEGX(pc) == KSEG0 || KSEGX(pc) == KSEG1) && (((unsigned long) pc & 3) == 0)) { for(i=0;i<5;i++) printk("%08x ", *pc++); printk("\n"); } else printk("(Bad address in epc)\n"); while(1); do_exit(SIGSEGV); } static void fix_ade(struct pt_regs *regs, int write) { printk("Received address error (ade%c)\n", write ? 's' : 'l'); panic("Fixing address errors not implemented yet"); } void do_adel(struct pt_regs *regs) { if(current->tss.mflags & MF_FIXADE) { fix_ade(regs, 0); return; } show_regs(regs); while(1); dump_tlb_nonwired(); send_sig(SIGSEGV, current, 1); } void do_ades(struct pt_regs *regs) { unsigned long pc = regs->cp0_epc; int i; if(current->tss.mflags & MF_FIXADE) { fix_ade(regs, 1); return; } while(1); for(i=0; i<NR_TASKS;i++) if(task[i] && task[i]->pid >= 2) { printk("Process %d\n", task[i]->pid); dump_list_process(task[i], pc); } show_regs(regs); dump_tlb_nonwired(); send_sig(SIGSEGV, current, 1); } /* * The ibe/dbe exceptions are signaled by onboard hardware and should get * a board specific handlers to get maximum available information. Bus * errors are always symptom of hardware malfunction or a kernel error. * * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong. * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe) * are bus errors and therefor should send a SIGBUS! (Andy) */ void do_ibe(struct pt_regs *regs) { show_regs(regs); while(1); send_sig(SIGBUS, current, 1); } void do_dbe(struct pt_regs *regs) { show_regs(regs); while(1); send_sig(SIGBUS, current, 1); } void do_ov(struct pt_regs *regs) { show_regs(regs); while(1); send_sig(SIGFPE, current, 1); } void do_fpe(struct pt_regs *regs) { show_regs(regs); while(1); send_sig(SIGFPE, current, 1); } void do_bp(struct pt_regs *regs) { show_regs(regs); while(1); send_sig(SIGILL, current, 1); } void do_tr(struct pt_regs *regs) { show_regs(regs); while(1); send_sig(SIGILL, current, 1); } void do_ri(struct pt_regs *regs) { int i; for(i=0; i<NR_TASKS;i++) if(task[i] && task[i]->pid >= 2) { printk("Process %d\n", task[i]->pid); dump_list_process(task[i], 0x7ffff000); } show_regs(regs); while(1); send_sig(SIGILL, current, 1); } void do_cpu(struct pt_regs *regs) { unsigned int cpid; cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; switch(cpid) { case 1: regs->cp0_status |= ST0_CU1; break; case 0: /* * CPU for cp0 can only happen in user mode */ case 2: case 3: send_sig(SIGILL, current, 1); break; } } 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) { 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 * after another deadly hard/software error. */ panic("Caught reserved exception - can't handle.\n"); } void trap_init(void) { unsigned long i; void watch_set(unsigned long, unsigned long); if(boot_info.machtype == MACH_MIPS_MAGNUM_4000) EISA_bus = 1; /* * 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) { /* * The R10000 is in most aspects similar to the R4400. It however * should get some special optimizations. */ case CPU_R10000: write_32bit_cp0_register(CP0_FRAMEMASK, 0); set_cp0_status(ST0_XX, ST0_XX); page_colour_mask = 0x3000; panic("CPU too expensive - making holiday in the ANDES!"); break; case CPU_R4000MC: case CPU_R4400MC: case CPU_R4000SC: case CPU_R4400SC: /* * Handlers not implemented yet. If should ever be used - * otherwise it's a bug in the Linux/MIPS kernel, anyway. */ set_except_vector(14, handle_vcei); set_except_vector(31, handle_vced); case CPU_R4000PC: case CPU_R4400PC: case CPU_R4200: /* case CPU_R4300: */ /* * Use watch exception to trap on access to address zero */ set_except_vector(23, handle_watch); watch_set(KSEG0, 3); 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); /* * The following two are signaled by onboard hardware and * should get board specific handlers to get maximum * available information. */ 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); /* * Compute mask for page_colour(). This is based on the * size of the data cache. Does the size of the icache * need to be accounted for? */ i = read_32bit_cp0_register(CP0_CONFIG); i = (i >> 26) & 7; page_colour_mask = 1 << (12 + i); 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: 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 CPU type"); } /* * The interrupt handler mostly depends of the board type. */ set_except_vector(0, feature->handle_int); }
Go to most recent revision | Compare with Previous | Blame | View Log