diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
| -rw-r--r-- | arch/mips/kernel/traps.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 308e43460864..d612c6dcb746 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -50,6 +50,7 @@ #include <asm/types.h> #include <asm/stacktrace.h> #include <asm/irq.h> +#include <asm/uasm.h> extern void check_wait(void); extern asmlinkage void r4k_wait(void); @@ -351,9 +352,10 @@ void show_registers(const struct pt_regs *regs) static DEFINE_SPINLOCK(die_lock); -void __noreturn die(const char * str, const struct pt_regs * regs) +void __noreturn die(const char * str, struct pt_regs * regs) { static int die_counter; + int sig = SIGSEGV; #ifdef CONFIG_MIPS_MT_SMTC unsigned long dvpret = dvpe(); #endif /* CONFIG_MIPS_MT_SMTC */ @@ -364,6 +366,10 @@ void __noreturn die(const char * str, const struct pt_regs * regs) #ifdef CONFIG_MIPS_MT_SMTC mips_mt_regdump(dvpret); #endif /* CONFIG_MIPS_MT_SMTC */ + + if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) + sig = 0; + printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); add_taint(TAINT_DIE); @@ -378,7 +384,7 @@ void __noreturn die(const char * str, const struct pt_regs * regs) panic("Fatal exception"); } - do_exit(SIGSEGV); + do_exit(sig); } extern struct exception_table_entry __start___dbe_table[]; @@ -1271,21 +1277,25 @@ unsigned long ebase; unsigned long exception_handlers[32]; unsigned long vi_handlers[64]; -/* - * As a side effect of the way this is implemented we're limited - * to interrupt handlers in the address range from - * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ... - */ -void *set_except_vector(int n, void *addr) +void __init *set_except_vector(int n, void *addr) { unsigned long handler = (unsigned long) addr; unsigned long old_handler = exception_handlers[n]; exception_handlers[n] = handler; if (n == 0 && cpu_has_divec) { - *(u32 *)(ebase + 0x200) = 0x08000000 | - (0x03ffffff & (handler >> 2)); - local_flush_icache_range(ebase + 0x200, ebase + 0x204); + unsigned long jump_mask = ~((1 << 28) - 1); + u32 *buf = (u32 *)(ebase + 0x200); + unsigned int k0 = 26; + if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) { + uasm_i_j(&buf, handler & ~jump_mask); + uasm_i_nop(&buf); + } else { + UASM_i_LA(&buf, k0, handler); + uasm_i_jr(&buf, k0); + uasm_i_nop(&buf); + } + local_flush_icache_range(ebase + 0x200, (unsigned long)buf); } return (void *)old_handler; } @@ -1403,6 +1413,7 @@ extern void flush_tlb_handlers(void); * Timer interrupt */ int cp0_compare_irq; +int cp0_compare_irq_shift; /* * Performance counter IRQ or -1 if shared with timer @@ -1493,12 +1504,14 @@ void __cpuinit per_cpu_trap_init(void) * o read IntCtl.IPPCI to determine the performance counter interrupt */ if (cpu_has_mips_r2) { - cp0_compare_irq = (read_c0_intctl() >> 29) & 7; - cp0_perfcount_irq = (read_c0_intctl() >> 26) & 7; + cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; + cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; + cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; if (cp0_perfcount_irq == cp0_compare_irq) cp0_perfcount_irq = -1; } else { cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; + cp0_compare_irq_shift = cp0_compare_irq; cp0_perfcount_irq = -1; } @@ -1549,12 +1562,7 @@ static char panic_null_cerr[] __cpuinitdata = void __cpuinit set_uncached_handler(unsigned long offset, void *addr, unsigned long size) { -#ifdef CONFIG_32BIT - unsigned long uncached_ebase = KSEG1ADDR(ebase); -#endif -#ifdef CONFIG_64BIT - unsigned long uncached_ebase = TO_UNCAC(ebase); -#endif + unsigned long uncached_ebase = CKSEG1ADDR(ebase); if (!addr) panic(panic_null_cerr); @@ -1591,7 +1599,7 @@ void __init trap_init(void) ebase = (unsigned long) __alloc_bootmem(size, 1 << fls(size), 0); } else { - ebase = CAC_BASE; + ebase = CKSEG0; if (cpu_has_mips_r2) ebase += (read_c0_ebase() & 0x3ffff000); } |
