diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
| -rw-r--r-- | arch/mips/kernel/traps.c | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 426cced1e9dc..80b9e070c207 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -42,10 +42,14 @@ | |||
| 42 | #include <asm/tlbdebug.h> | 42 | #include <asm/tlbdebug.h> |
| 43 | #include <asm/traps.h> | 43 | #include <asm/traps.h> |
| 44 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
| 45 | #include <asm/watch.h> | ||
| 45 | #include <asm/mmu_context.h> | 46 | #include <asm/mmu_context.h> |
| 46 | #include <asm/types.h> | 47 | #include <asm/types.h> |
| 47 | #include <asm/stacktrace.h> | 48 | #include <asm/stacktrace.h> |
| 48 | 49 | ||
| 50 | extern void check_wait(void); | ||
| 51 | extern asmlinkage void r4k_wait(void); | ||
| 52 | extern asmlinkage void rollback_handle_int(void); | ||
| 49 | extern asmlinkage void handle_int(void); | 53 | extern asmlinkage void handle_int(void); |
| 50 | extern asmlinkage void handle_tlbm(void); | 54 | extern asmlinkage void handle_tlbm(void); |
| 51 | extern asmlinkage void handle_tlbl(void); | 55 | extern asmlinkage void handle_tlbl(void); |
| @@ -373,8 +377,8 @@ void __noreturn die(const char * str, const struct pt_regs * regs) | |||
| 373 | do_exit(SIGSEGV); | 377 | do_exit(SIGSEGV); |
| 374 | } | 378 | } |
| 375 | 379 | ||
| 376 | extern const struct exception_table_entry __start___dbe_table[]; | 380 | extern struct exception_table_entry __start___dbe_table[]; |
| 377 | extern const struct exception_table_entry __stop___dbe_table[]; | 381 | extern struct exception_table_entry __stop___dbe_table[]; |
| 378 | 382 | ||
| 379 | __asm__( | 383 | __asm__( |
| 380 | " .section __dbe_table, \"a\"\n" | 384 | " .section __dbe_table, \"a\"\n" |
| @@ -822,8 +826,10 @@ static void mt_ase_fp_affinity(void) | |||
| 822 | if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) { | 826 | if (cpus_intersects(current->cpus_allowed, mt_fpu_cpumask)) { |
| 823 | cpumask_t tmask; | 827 | cpumask_t tmask; |
| 824 | 828 | ||
| 825 | cpus_and(tmask, current->thread.user_cpus_allowed, | 829 | current->thread.user_cpus_allowed |
| 826 | mt_fpu_cpumask); | 830 | = current->cpus_allowed; |
| 831 | cpus_and(tmask, current->cpus_allowed, | ||
| 832 | mt_fpu_cpumask); | ||
| 827 | set_cpus_allowed(current, tmask); | 833 | set_cpus_allowed(current, tmask); |
| 828 | set_thread_flag(TIF_FPUBOUND); | 834 | set_thread_flag(TIF_FPUBOUND); |
| 829 | } | 835 | } |
| @@ -907,13 +913,26 @@ asmlinkage void do_mdmx(struct pt_regs *regs) | |||
| 907 | 913 | ||
| 908 | asmlinkage void do_watch(struct pt_regs *regs) | 914 | asmlinkage void do_watch(struct pt_regs *regs) |
| 909 | { | 915 | { |
| 916 | u32 cause; | ||
| 917 | |||
| 910 | /* | 918 | /* |
| 911 | * We use the watch exception where available to detect stack | 919 | * Clear WP (bit 22) bit of cause register so we don't loop |
| 912 | * overflows. | 920 | * forever. |
| 913 | */ | 921 | */ |
| 914 | dump_tlb_all(); | 922 | cause = read_c0_cause(); |
| 915 | show_regs(regs); | 923 | cause &= ~(1 << 22); |
| 916 | panic("Caught WATCH exception - probably caused by stack overflow."); | 924 | write_c0_cause(cause); |
| 925 | |||
| 926 | /* | ||
| 927 | * If the current thread has the watch registers loaded, save | ||
| 928 | * their values and send SIGTRAP. Otherwise another thread | ||
| 929 | * left the registers set, clear them and continue. | ||
| 930 | */ | ||
| 931 | if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) { | ||
| 932 | mips_read_watch_registers(); | ||
| 933 | force_sig(SIGTRAP, current); | ||
| 934 | } else | ||
| 935 | mips_clear_watch_registers(); | ||
| 917 | } | 936 | } |
| 918 | 937 | ||
| 919 | asmlinkage void do_mcheck(struct pt_regs *regs) | 938 | asmlinkage void do_mcheck(struct pt_regs *regs) |
| @@ -1200,7 +1219,7 @@ void *set_except_vector(int n, void *addr) | |||
| 1200 | if (n == 0 && cpu_has_divec) { | 1219 | if (n == 0 && cpu_has_divec) { |
| 1201 | *(u32 *)(ebase + 0x200) = 0x08000000 | | 1220 | *(u32 *)(ebase + 0x200) = 0x08000000 | |
| 1202 | (0x03ffffff & (handler >> 2)); | 1221 | (0x03ffffff & (handler >> 2)); |
| 1203 | flush_icache_range(ebase + 0x200, ebase + 0x204); | 1222 | local_flush_icache_range(ebase + 0x200, ebase + 0x204); |
| 1204 | } | 1223 | } |
| 1205 | return (void *)old_handler; | 1224 | return (void *)old_handler; |
| 1206 | } | 1225 | } |
| @@ -1251,6 +1270,9 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
| 1251 | 1270 | ||
| 1252 | extern char except_vec_vi, except_vec_vi_lui; | 1271 | extern char except_vec_vi, except_vec_vi_lui; |
| 1253 | extern char except_vec_vi_ori, except_vec_vi_end; | 1272 | extern char except_vec_vi_ori, except_vec_vi_end; |
| 1273 | extern char rollback_except_vec_vi; | ||
| 1274 | char *vec_start = (cpu_wait == r4k_wait) ? | ||
| 1275 | &rollback_except_vec_vi : &except_vec_vi; | ||
| 1254 | #ifdef CONFIG_MIPS_MT_SMTC | 1276 | #ifdef CONFIG_MIPS_MT_SMTC |
| 1255 | /* | 1277 | /* |
| 1256 | * We need to provide the SMTC vectored interrupt handler | 1278 | * We need to provide the SMTC vectored interrupt handler |
| @@ -1258,11 +1280,11 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
| 1258 | * Status.IM bit to be masked before going there. | 1280 | * Status.IM bit to be masked before going there. |
| 1259 | */ | 1281 | */ |
| 1260 | extern char except_vec_vi_mori; | 1282 | extern char except_vec_vi_mori; |
| 1261 | const int mori_offset = &except_vec_vi_mori - &except_vec_vi; | 1283 | const int mori_offset = &except_vec_vi_mori - vec_start; |
| 1262 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1284 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 1263 | const int handler_len = &except_vec_vi_end - &except_vec_vi; | 1285 | const int handler_len = &except_vec_vi_end - vec_start; |
| 1264 | const int lui_offset = &except_vec_vi_lui - &except_vec_vi; | 1286 | const int lui_offset = &except_vec_vi_lui - vec_start; |
| 1265 | const int ori_offset = &except_vec_vi_ori - &except_vec_vi; | 1287 | const int ori_offset = &except_vec_vi_ori - vec_start; |
| 1266 | 1288 | ||
| 1267 | if (handler_len > VECTORSPACING) { | 1289 | if (handler_len > VECTORSPACING) { |
| 1268 | /* | 1290 | /* |
| @@ -1272,7 +1294,7 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
| 1272 | panic("VECTORSPACING too small"); | 1294 | panic("VECTORSPACING too small"); |
| 1273 | } | 1295 | } |
| 1274 | 1296 | ||
| 1275 | memcpy(b, &except_vec_vi, handler_len); | 1297 | memcpy(b, vec_start, handler_len); |
| 1276 | #ifdef CONFIG_MIPS_MT_SMTC | 1298 | #ifdef CONFIG_MIPS_MT_SMTC |
| 1277 | BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ | 1299 | BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ |
| 1278 | 1300 | ||
| @@ -1283,7 +1305,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
| 1283 | *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); | 1305 | *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); |
| 1284 | w = (u32 *)(b + ori_offset); | 1306 | w = (u32 *)(b + ori_offset); |
| 1285 | *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); | 1307 | *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); |
| 1286 | flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len)); | 1308 | local_flush_icache_range((unsigned long)b, |
| 1309 | (unsigned long)(b+handler_len)); | ||
| 1287 | } | 1310 | } |
| 1288 | else { | 1311 | else { |
| 1289 | /* | 1312 | /* |
| @@ -1295,7 +1318,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) | |||
| 1295 | w = (u32 *)b; | 1318 | w = (u32 *)b; |
| 1296 | *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ | 1319 | *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ |
| 1297 | *w = 0; | 1320 | *w = 0; |
| 1298 | flush_icache_range((unsigned long)b, (unsigned long)(b+8)); | 1321 | local_flush_icache_range((unsigned long)b, |
| 1322 | (unsigned long)(b+8)); | ||
| 1299 | } | 1323 | } |
| 1300 | 1324 | ||
| 1301 | return (void *)old_handler; | 1325 | return (void *)old_handler; |
| @@ -1515,7 +1539,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1515 | void __init set_handler(unsigned long offset, void *addr, unsigned long size) | 1539 | void __init set_handler(unsigned long offset, void *addr, unsigned long size) |
| 1516 | { | 1540 | { |
| 1517 | memcpy((void *)(ebase + offset), addr, size); | 1541 | memcpy((void *)(ebase + offset), addr, size); |
| 1518 | flush_icache_range(ebase + offset, ebase + offset + size); | 1542 | local_flush_icache_range(ebase + offset, ebase + offset + size); |
| 1519 | } | 1543 | } |
| 1520 | 1544 | ||
| 1521 | static char panic_null_cerr[] __cpuinitdata = | 1545 | static char panic_null_cerr[] __cpuinitdata = |
| @@ -1552,6 +1576,10 @@ void __init trap_init(void) | |||
| 1552 | extern char except_vec3_generic, except_vec3_r4000; | 1576 | extern char except_vec3_generic, except_vec3_r4000; |
| 1553 | extern char except_vec4; | 1577 | extern char except_vec4; |
| 1554 | unsigned long i; | 1578 | unsigned long i; |
| 1579 | int rollback; | ||
| 1580 | |||
| 1581 | check_wait(); | ||
| 1582 | rollback = (cpu_wait == r4k_wait); | ||
| 1555 | 1583 | ||
| 1556 | #if defined(CONFIG_KGDB) | 1584 | #if defined(CONFIG_KGDB) |
| 1557 | if (kgdb_early_setup) | 1585 | if (kgdb_early_setup) |
| @@ -1616,7 +1644,7 @@ void __init trap_init(void) | |||
| 1616 | if (board_be_init) | 1644 | if (board_be_init) |
| 1617 | board_be_init(); | 1645 | board_be_init(); |
| 1618 | 1646 | ||
| 1619 | set_except_vector(0, handle_int); | 1647 | set_except_vector(0, rollback ? rollback_handle_int : handle_int); |
| 1620 | set_except_vector(1, handle_tlbm); | 1648 | set_except_vector(1, handle_tlbm); |
| 1621 | set_except_vector(2, handle_tlbl); | 1649 | set_except_vector(2, handle_tlbl); |
| 1622 | set_except_vector(3, handle_tlbs); | 1650 | set_except_vector(3, handle_tlbs); |
| @@ -1680,6 +1708,8 @@ void __init trap_init(void) | |||
| 1680 | signal32_init(); | 1708 | signal32_init(); |
| 1681 | #endif | 1709 | #endif |
| 1682 | 1710 | ||
| 1683 | flush_icache_range(ebase, ebase + 0x400); | 1711 | local_flush_icache_range(ebase, ebase + 0x400); |
| 1684 | flush_tlb_handlers(); | 1712 | flush_tlb_handlers(); |
| 1713 | |||
| 1714 | sort_extable(__start___dbe_table, __stop___dbe_table); | ||
| 1685 | } | 1715 | } |
