aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /arch/mips/kernel/traps.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c184
1 files changed, 73 insertions, 111 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 0a18b4c62afb..d612c6dcb746 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -25,10 +25,12 @@
25#include <linux/ptrace.h> 25#include <linux/ptrace.h>
26#include <linux/kgdb.h> 26#include <linux/kgdb.h>
27#include <linux/kdebug.h> 27#include <linux/kdebug.h>
28#include <linux/notifier.h>
28 29
29#include <asm/bootinfo.h> 30#include <asm/bootinfo.h>
30#include <asm/branch.h> 31#include <asm/branch.h>
31#include <asm/break.h> 32#include <asm/break.h>
33#include <asm/cop2.h>
32#include <asm/cpu.h> 34#include <asm/cpu.h>
33#include <asm/dsp.h> 35#include <asm/dsp.h>
34#include <asm/fpu.h> 36#include <asm/fpu.h>
@@ -48,6 +50,7 @@
48#include <asm/types.h> 50#include <asm/types.h>
49#include <asm/stacktrace.h> 51#include <asm/stacktrace.h>
50#include <asm/irq.h> 52#include <asm/irq.h>
53#include <asm/uasm.h>
51 54
52extern void check_wait(void); 55extern void check_wait(void);
53extern asmlinkage void r4k_wait(void); 56extern asmlinkage void r4k_wait(void);
@@ -79,10 +82,6 @@ extern asmlinkage void handle_reserved(void);
79extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, 82extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
80 struct mips_fpu_struct *ctx, int has_fpu); 83 struct mips_fpu_struct *ctx, int has_fpu);
81 84
82#ifdef CONFIG_CPU_CAVIUM_OCTEON
83extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
84#endif
85
86void (*board_be_init)(void); 85void (*board_be_init)(void);
87int (*board_be_handler)(struct pt_regs *regs, int is_fixup); 86int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
88void (*board_nmi_handler_setup)(void); 87void (*board_nmi_handler_setup)(void);
@@ -353,9 +352,10 @@ void show_registers(const struct pt_regs *regs)
353 352
354static DEFINE_SPINLOCK(die_lock); 353static DEFINE_SPINLOCK(die_lock);
355 354
356void __noreturn die(const char * str, const struct pt_regs * regs) 355void __noreturn die(const char * str, struct pt_regs * regs)
357{ 356{
358 static int die_counter; 357 static int die_counter;
358 int sig = SIGSEGV;
359#ifdef CONFIG_MIPS_MT_SMTC 359#ifdef CONFIG_MIPS_MT_SMTC
360 unsigned long dvpret = dvpe(); 360 unsigned long dvpret = dvpe();
361#endif /* CONFIG_MIPS_MT_SMTC */ 361#endif /* CONFIG_MIPS_MT_SMTC */
@@ -366,6 +366,10 @@ void __noreturn die(const char * str, const struct pt_regs * regs)
366#ifdef CONFIG_MIPS_MT_SMTC 366#ifdef CONFIG_MIPS_MT_SMTC
367 mips_mt_regdump(dvpret); 367 mips_mt_regdump(dvpret);
368#endif /* CONFIG_MIPS_MT_SMTC */ 368#endif /* CONFIG_MIPS_MT_SMTC */
369
370 if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
371 sig = 0;
372
369 printk("%s[#%d]:\n", str, ++die_counter); 373 printk("%s[#%d]:\n", str, ++die_counter);
370 show_registers(regs); 374 show_registers(regs);
371 add_taint(TAINT_DIE); 375 add_taint(TAINT_DIE);
@@ -380,7 +384,7 @@ void __noreturn die(const char * str, const struct pt_regs * regs)
380 panic("Fatal exception"); 384 panic("Fatal exception");
381 } 385 }
382 386
383 do_exit(SIGSEGV); 387 do_exit(sig);
384} 388}
385 389
386extern struct exception_table_entry __start___dbe_table[]; 390extern struct exception_table_entry __start___dbe_table[];
@@ -857,6 +861,44 @@ static void mt_ase_fp_affinity(void)
857#endif /* CONFIG_MIPS_MT_FPAFF */ 861#endif /* CONFIG_MIPS_MT_FPAFF */
858} 862}
859 863
864/*
865 * No lock; only written during early bootup by CPU 0.
866 */
867static RAW_NOTIFIER_HEAD(cu2_chain);
868
869int __ref register_cu2_notifier(struct notifier_block *nb)
870{
871 return raw_notifier_chain_register(&cu2_chain, nb);
872}
873
874int cu2_notifier_call_chain(unsigned long val, void *v)
875{
876 return raw_notifier_call_chain(&cu2_chain, val, v);
877}
878
879static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
880 void *data)
881{
882 struct pt_regs *regs = data;
883
884 switch (action) {
885 default:
886 die_if_kernel("Unhandled kernel unaligned access or invalid "
887 "instruction", regs);
888 /* Fall through */
889
890 case CU2_EXCEPTION:
891 force_sig(SIGILL, current);
892 }
893
894 return NOTIFY_OK;
895}
896
897static struct notifier_block default_cu2_notifier = {
898 .notifier_call = default_cu2_call,
899 .priority = 0x80000000, /* Run last */
900};
901
860asmlinkage void do_cpu(struct pt_regs *regs) 902asmlinkage void do_cpu(struct pt_regs *regs)
861{ 903{
862 unsigned int __user *epc; 904 unsigned int __user *epc;
@@ -920,17 +962,9 @@ asmlinkage void do_cpu(struct pt_regs *regs)
920 return; 962 return;
921 963
922 case 2: 964 case 2:
923#ifdef CONFIG_CPU_CAVIUM_OCTEON 965 raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
924 prefetch(&current->thread.cp2); 966 break;
925 local_irq_save(flags); 967
926 KSTK_STATUS(current) |= ST0_CU2;
927 status = read_c0_status();
928 write_c0_status(status | ST0_CU2);
929 octeon_cop2_restore(&(current->thread.cp2));
930 write_c0_status(status & ~ST0_CU2);
931 local_irq_restore(flags);
932 return;
933#endif
934 case 3: 968 case 3:
935 break; 969 break;
936 } 970 }
@@ -1243,21 +1277,25 @@ unsigned long ebase;
1243unsigned long exception_handlers[32]; 1277unsigned long exception_handlers[32];
1244unsigned long vi_handlers[64]; 1278unsigned long vi_handlers[64];
1245 1279
1246/* 1280void __init *set_except_vector(int n, void *addr)
1247 * As a side effect of the way this is implemented we're limited
1248 * to interrupt handlers in the address range from
1249 * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ...
1250 */
1251void *set_except_vector(int n, void *addr)
1252{ 1281{
1253 unsigned long handler = (unsigned long) addr; 1282 unsigned long handler = (unsigned long) addr;
1254 unsigned long old_handler = exception_handlers[n]; 1283 unsigned long old_handler = exception_handlers[n];
1255 1284
1256 exception_handlers[n] = handler; 1285 exception_handlers[n] = handler;
1257 if (n == 0 && cpu_has_divec) { 1286 if (n == 0 && cpu_has_divec) {
1258 *(u32 *)(ebase + 0x200) = 0x08000000 | 1287 unsigned long jump_mask = ~((1 << 28) - 1);
1259 (0x03ffffff & (handler >> 2)); 1288 u32 *buf = (u32 *)(ebase + 0x200);
1260 local_flush_icache_range(ebase + 0x200, ebase + 0x204); 1289 unsigned int k0 = 26;
1290 if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) {
1291 uasm_i_j(&buf, handler & ~jump_mask);
1292 uasm_i_nop(&buf);
1293 } else {
1294 UASM_i_LA(&buf, k0, handler);
1295 uasm_i_jr(&buf, k0);
1296 uasm_i_nop(&buf);
1297 }
1298 local_flush_icache_range(ebase + 0x200, (unsigned long)buf);
1261 } 1299 }
1262 return (void *)old_handler; 1300 return (void *)old_handler;
1263} 1301}
@@ -1367,77 +1405,6 @@ void *set_vi_handler(int n, vi_handler_t addr)
1367 return set_vi_srs_handler(n, addr, 0); 1405 return set_vi_srs_handler(n, addr, 0);
1368} 1406}
1369 1407
1370/*
1371 * This is used by native signal handling
1372 */
1373asmlinkage int (*save_fp_context)(struct sigcontext __user *sc);
1374asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc);
1375
1376extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
1377extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
1378
1379extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
1380extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
1381
1382#ifdef CONFIG_SMP
1383static int smp_save_fp_context(struct sigcontext __user *sc)
1384{
1385 return raw_cpu_has_fpu
1386 ? _save_fp_context(sc)
1387 : fpu_emulator_save_context(sc);
1388}
1389
1390static int smp_restore_fp_context(struct sigcontext __user *sc)
1391{
1392 return raw_cpu_has_fpu
1393 ? _restore_fp_context(sc)
1394 : fpu_emulator_restore_context(sc);
1395}
1396#endif
1397
1398static inline void signal_init(void)
1399{
1400#ifdef CONFIG_SMP
1401 /* For now just do the cpu_has_fpu check when the functions are invoked */
1402 save_fp_context = smp_save_fp_context;
1403 restore_fp_context = smp_restore_fp_context;
1404#else
1405 if (cpu_has_fpu) {
1406 save_fp_context = _save_fp_context;
1407 restore_fp_context = _restore_fp_context;
1408 } else {
1409 save_fp_context = fpu_emulator_save_context;
1410 restore_fp_context = fpu_emulator_restore_context;
1411 }
1412#endif
1413}
1414
1415#ifdef CONFIG_MIPS32_COMPAT
1416
1417/*
1418 * This is used by 32-bit signal stuff on the 64-bit kernel
1419 */
1420asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc);
1421asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc);
1422
1423extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
1424extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
1425
1426extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
1427extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
1428
1429static inline void signal32_init(void)
1430{
1431 if (cpu_has_fpu) {
1432 save_fp_context32 = _save_fp_context32;
1433 restore_fp_context32 = _restore_fp_context32;
1434 } else {
1435 save_fp_context32 = fpu_emulator_save_context32;
1436 restore_fp_context32 = fpu_emulator_restore_context32;
1437 }
1438}
1439#endif
1440
1441extern void cpu_cache_init(void); 1408extern void cpu_cache_init(void);
1442extern void tlb_init(void); 1409extern void tlb_init(void);
1443extern void flush_tlb_handlers(void); 1410extern void flush_tlb_handlers(void);
@@ -1446,6 +1413,7 @@ extern void flush_tlb_handlers(void);
1446 * Timer interrupt 1413 * Timer interrupt
1447 */ 1414 */
1448int cp0_compare_irq; 1415int cp0_compare_irq;
1416int cp0_compare_irq_shift;
1449 1417
1450/* 1418/*
1451 * Performance counter IRQ or -1 if shared with timer 1419 * Performance counter IRQ or -1 if shared with timer
@@ -1536,12 +1504,14 @@ void __cpuinit per_cpu_trap_init(void)
1536 * o read IntCtl.IPPCI to determine the performance counter interrupt 1504 * o read IntCtl.IPPCI to determine the performance counter interrupt
1537 */ 1505 */
1538 if (cpu_has_mips_r2) { 1506 if (cpu_has_mips_r2) {
1539 cp0_compare_irq = (read_c0_intctl() >> 29) & 7; 1507 cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
1540 cp0_perfcount_irq = (read_c0_intctl() >> 26) & 7; 1508 cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
1509 cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
1541 if (cp0_perfcount_irq == cp0_compare_irq) 1510 if (cp0_perfcount_irq == cp0_compare_irq)
1542 cp0_perfcount_irq = -1; 1511 cp0_perfcount_irq = -1;
1543 } else { 1512 } else {
1544 cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; 1513 cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
1514 cp0_compare_irq_shift = cp0_compare_irq;
1545 cp0_perfcount_irq = -1; 1515 cp0_perfcount_irq = -1;
1546 } 1516 }
1547 1517
@@ -1592,12 +1562,7 @@ static char panic_null_cerr[] __cpuinitdata =
1592void __cpuinit set_uncached_handler(unsigned long offset, void *addr, 1562void __cpuinit set_uncached_handler(unsigned long offset, void *addr,
1593 unsigned long size) 1563 unsigned long size)
1594{ 1564{
1595#ifdef CONFIG_32BIT 1565 unsigned long uncached_ebase = CKSEG1ADDR(ebase);
1596 unsigned long uncached_ebase = KSEG1ADDR(ebase);
1597#endif
1598#ifdef CONFIG_64BIT
1599 unsigned long uncached_ebase = TO_UNCAC(ebase);
1600#endif
1601 1566
1602 if (!addr) 1567 if (!addr)
1603 panic(panic_null_cerr); 1568 panic(panic_null_cerr);
@@ -1634,7 +1599,7 @@ void __init trap_init(void)
1634 ebase = (unsigned long) 1599 ebase = (unsigned long)
1635 __alloc_bootmem(size, 1 << fls(size), 0); 1600 __alloc_bootmem(size, 1 << fls(size), 0);
1636 } else { 1601 } else {
1637 ebase = CAC_BASE; 1602 ebase = CKSEG0;
1638 if (cpu_has_mips_r2) 1603 if (cpu_has_mips_r2)
1639 ebase += (read_c0_ebase() & 0x3ffff000); 1604 ebase += (read_c0_ebase() & 0x3ffff000);
1640 } 1605 }
@@ -1751,13 +1716,10 @@ void __init trap_init(void)
1751 else 1716 else
1752 memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80); 1717 memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80);
1753 1718
1754 signal_init();
1755#ifdef CONFIG_MIPS32_COMPAT
1756 signal32_init();
1757#endif
1758
1759 local_flush_icache_range(ebase, ebase + 0x400); 1719 local_flush_icache_range(ebase, ebase + 0x400);
1760 flush_tlb_handlers(); 1720 flush_tlb_handlers();
1761 1721
1762 sort_extable(__start___dbe_table, __stop___dbe_table); 1722 sort_extable(__start___dbe_table, __stop___dbe_table);
1723
1724 register_cu2_notifier(&default_cu2_notifier);
1763} 1725}