diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 213 |
1 files changed, 148 insertions, 65 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 984c0d0a7b4d..cb8b0e2c7954 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/kallsyms.h> | 22 | #include <linux/kallsyms.h> |
23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/ptrace.h> | ||
25 | 26 | ||
26 | #include <asm/bootinfo.h> | 27 | #include <asm/bootinfo.h> |
27 | #include <asm/branch.h> | 28 | #include <asm/branch.h> |
@@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset); | |||
80 | 81 | ||
81 | static void show_raw_backtrace(unsigned long reg29) | 82 | static void show_raw_backtrace(unsigned long reg29) |
82 | { | 83 | { |
83 | unsigned long *sp = (unsigned long *)reg29; | 84 | unsigned long *sp = (unsigned long *)(reg29 & ~3); |
84 | unsigned long addr; | 85 | unsigned long addr; |
85 | 86 | ||
86 | printk("Call Trace:"); | 87 | printk("Call Trace:"); |
87 | #ifdef CONFIG_KALLSYMS | 88 | #ifdef CONFIG_KALLSYMS |
88 | printk("\n"); | 89 | printk("\n"); |
89 | #endif | 90 | #endif |
90 | while (!kstack_end(sp)) { | 91 | #define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000) |
91 | addr = *sp++; | 92 | if (IS_KVA01(sp)) { |
92 | if (__kernel_text_address(addr)) | 93 | while (!kstack_end(sp)) { |
93 | print_ip_sym(addr); | 94 | addr = *sp++; |
95 | if (__kernel_text_address(addr)) | ||
96 | print_ip_sym(addr); | ||
97 | } | ||
98 | printk("\n"); | ||
94 | } | 99 | } |
95 | printk("\n"); | ||
96 | } | 100 | } |
97 | 101 | ||
98 | #ifdef CONFIG_KALLSYMS | 102 | #ifdef CONFIG_KALLSYMS |
@@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack); | |||
192 | static void show_code(unsigned int __user *pc) | 196 | static void show_code(unsigned int __user *pc) |
193 | { | 197 | { |
194 | long i; | 198 | long i; |
199 | unsigned short __user *pc16 = NULL; | ||
195 | 200 | ||
196 | printk("\nCode:"); | 201 | printk("\nCode:"); |
197 | 202 | ||
203 | if ((unsigned long)pc & 1) | ||
204 | pc16 = (unsigned short __user *)((unsigned long)pc & ~1); | ||
198 | for(i = -3 ; i < 6 ; i++) { | 205 | for(i = -3 ; i < 6 ; i++) { |
199 | unsigned int insn; | 206 | unsigned int insn; |
200 | if (__get_user(insn, pc + i)) { | 207 | if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) { |
201 | printk(" (Bad address in epc)\n"); | 208 | printk(" (Bad address in epc)\n"); |
202 | break; | 209 | break; |
203 | } | 210 | } |
204 | printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>')); | 211 | printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>')); |
205 | } | 212 | } |
206 | } | 213 | } |
207 | 214 | ||
@@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs) | |||
311 | 318 | ||
312 | void show_registers(const struct pt_regs *regs) | 319 | void show_registers(const struct pt_regs *regs) |
313 | { | 320 | { |
321 | const int field = 2 * sizeof(unsigned long); | ||
322 | |||
314 | __show_regs(regs); | 323 | __show_regs(regs); |
315 | print_modules(); | 324 | print_modules(); |
316 | printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", | 325 | printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n", |
317 | current->comm, task_pid_nr(current), current_thread_info(), current); | 326 | current->comm, current->pid, current_thread_info(), current, |
327 | field, current_thread_info()->tp_value); | ||
328 | if (cpu_has_userlocal) { | ||
329 | unsigned long tls; | ||
330 | |||
331 | tls = read_c0_userlocal(); | ||
332 | if (tls != current_thread_info()->tp_value) | ||
333 | printk("*HwTLS: %0*lx\n", field, tls); | ||
334 | } | ||
335 | |||
318 | show_stacktrace(current, regs); | 336 | show_stacktrace(current, regs); |
319 | show_code((unsigned int __user *) regs->cp0_epc); | 337 | show_code((unsigned int __user *) regs->cp0_epc); |
320 | printk("\n"); | 338 | printk("\n"); |
@@ -657,35 +675,24 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
657 | force_sig_info(SIGFPE, &info, current); | 675 | force_sig_info(SIGFPE, &info, current); |
658 | } | 676 | } |
659 | 677 | ||
660 | asmlinkage void do_bp(struct pt_regs *regs) | 678 | static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, |
679 | const char *str) | ||
661 | { | 680 | { |
662 | unsigned int opcode, bcode; | ||
663 | siginfo_t info; | 681 | siginfo_t info; |
664 | 682 | char b[40]; | |
665 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | ||
666 | goto out_sigsegv; | ||
667 | |||
668 | /* | ||
669 | * There is the ancient bug in the MIPS assemblers that the break | ||
670 | * code starts left to bit 16 instead to bit 6 in the opcode. | ||
671 | * Gas is bug-compatible, but not always, grrr... | ||
672 | * We handle both cases with a simple heuristics. --macro | ||
673 | */ | ||
674 | bcode = ((opcode >> 6) & ((1 << 20) - 1)); | ||
675 | if (bcode < (1 << 10)) | ||
676 | bcode <<= 10; | ||
677 | 683 | ||
678 | /* | 684 | /* |
679 | * (A short test says that IRIX 5.3 sends SIGTRAP for all break | 685 | * A short test says that IRIX 5.3 sends SIGTRAP for all trap |
680 | * insns, even for break codes that indicate arithmetic failures. | 686 | * insns, even for trap and break codes that indicate arithmetic |
681 | * Weird ...) | 687 | * failures. Weird ... |
682 | * But should we continue the brokenness??? --macro | 688 | * But should we continue the brokenness??? --macro |
683 | */ | 689 | */ |
684 | switch (bcode) { | 690 | switch (code) { |
685 | case BRK_OVERFLOW << 10: | 691 | case BRK_OVERFLOW: |
686 | case BRK_DIVZERO << 10: | 692 | case BRK_DIVZERO: |
687 | die_if_kernel("Break instruction in kernel code", regs); | 693 | scnprintf(b, sizeof(b), "%s instruction in kernel code", str); |
688 | if (bcode == (BRK_DIVZERO << 10)) | 694 | die_if_kernel(b, regs); |
695 | if (code == BRK_DIVZERO) | ||
689 | info.si_code = FPE_INTDIV; | 696 | info.si_code = FPE_INTDIV; |
690 | else | 697 | else |
691 | info.si_code = FPE_INTOVF; | 698 | info.si_code = FPE_INTOVF; |
@@ -695,12 +702,34 @@ asmlinkage void do_bp(struct pt_regs *regs) | |||
695 | force_sig_info(SIGFPE, &info, current); | 702 | force_sig_info(SIGFPE, &info, current); |
696 | break; | 703 | break; |
697 | case BRK_BUG: | 704 | case BRK_BUG: |
698 | die("Kernel bug detected", regs); | 705 | die_if_kernel("Kernel bug detected", regs); |
706 | force_sig(SIGTRAP, current); | ||
699 | break; | 707 | break; |
700 | default: | 708 | default: |
701 | die_if_kernel("Break instruction in kernel code", regs); | 709 | scnprintf(b, sizeof(b), "%s instruction in kernel code", str); |
710 | die_if_kernel(b, regs); | ||
702 | force_sig(SIGTRAP, current); | 711 | force_sig(SIGTRAP, current); |
703 | } | 712 | } |
713 | } | ||
714 | |||
715 | asmlinkage void do_bp(struct pt_regs *regs) | ||
716 | { | ||
717 | unsigned int opcode, bcode; | ||
718 | |||
719 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | ||
720 | goto out_sigsegv; | ||
721 | |||
722 | /* | ||
723 | * There is the ancient bug in the MIPS assemblers that the break | ||
724 | * code starts left to bit 16 instead to bit 6 in the opcode. | ||
725 | * Gas is bug-compatible, but not always, grrr... | ||
726 | * We handle both cases with a simple heuristics. --macro | ||
727 | */ | ||
728 | bcode = ((opcode >> 6) & ((1 << 20) - 1)); | ||
729 | if (bcode >= (1 << 10)) | ||
730 | bcode >>= 10; | ||
731 | |||
732 | do_trap_or_bp(regs, bcode, "Break"); | ||
704 | return; | 733 | return; |
705 | 734 | ||
706 | out_sigsegv: | 735 | out_sigsegv: |
@@ -710,7 +739,6 @@ out_sigsegv: | |||
710 | asmlinkage void do_tr(struct pt_regs *regs) | 739 | asmlinkage void do_tr(struct pt_regs *regs) |
711 | { | 740 | { |
712 | unsigned int opcode, tcode = 0; | 741 | unsigned int opcode, tcode = 0; |
713 | siginfo_t info; | ||
714 | 742 | ||
715 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | 743 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) |
716 | goto out_sigsegv; | 744 | goto out_sigsegv; |
@@ -719,32 +747,7 @@ asmlinkage void do_tr(struct pt_regs *regs) | |||
719 | if (!(opcode & OPCODE)) | 747 | if (!(opcode & OPCODE)) |
720 | tcode = ((opcode >> 6) & ((1 << 10) - 1)); | 748 | tcode = ((opcode >> 6) & ((1 << 10) - 1)); |
721 | 749 | ||
722 | /* | 750 | do_trap_or_bp(regs, tcode, "Trap"); |
723 | * (A short test says that IRIX 5.3 sends SIGTRAP for all trap | ||
724 | * insns, even for trap codes that indicate arithmetic failures. | ||
725 | * Weird ...) | ||
726 | * But should we continue the brokenness??? --macro | ||
727 | */ | ||
728 | switch (tcode) { | ||
729 | case BRK_OVERFLOW: | ||
730 | case BRK_DIVZERO: | ||
731 | die_if_kernel("Trap instruction in kernel code", regs); | ||
732 | if (tcode == BRK_DIVZERO) | ||
733 | info.si_code = FPE_INTDIV; | ||
734 | else | ||
735 | info.si_code = FPE_INTOVF; | ||
736 | info.si_signo = SIGFPE; | ||
737 | info.si_errno = 0; | ||
738 | info.si_addr = (void __user *) regs->cp0_epc; | ||
739 | force_sig_info(SIGFPE, &info, current); | ||
740 | break; | ||
741 | case BRK_BUG: | ||
742 | die("Kernel bug detected", regs); | ||
743 | break; | ||
744 | default: | ||
745 | die_if_kernel("Trap instruction in kernel code", regs); | ||
746 | force_sig(SIGTRAP, current); | ||
747 | } | ||
748 | return; | 751 | return; |
749 | 752 | ||
750 | out_sigsegv: | 753 | out_sigsegv: |
@@ -985,6 +988,21 @@ asmlinkage void do_reserved(struct pt_regs *regs) | |||
985 | (regs->cp0_cause & 0x7f) >> 2); | 988 | (regs->cp0_cause & 0x7f) >> 2); |
986 | } | 989 | } |
987 | 990 | ||
991 | static int __initdata l1parity = 1; | ||
992 | static int __init nol1parity(char *s) | ||
993 | { | ||
994 | l1parity = 0; | ||
995 | return 1; | ||
996 | } | ||
997 | __setup("nol1par", nol1parity); | ||
998 | static int __initdata l2parity = 1; | ||
999 | static int __init nol2parity(char *s) | ||
1000 | { | ||
1001 | l2parity = 0; | ||
1002 | return 1; | ||
1003 | } | ||
1004 | __setup("nol2par", nol2parity); | ||
1005 | |||
988 | /* | 1006 | /* |
989 | * Some MIPS CPUs can enable/disable for cache parity detection, but do | 1007 | * Some MIPS CPUs can enable/disable for cache parity detection, but do |
990 | * it different ways. | 1008 | * it different ways. |
@@ -994,6 +1012,62 @@ static inline void parity_protection_init(void) | |||
994 | switch (current_cpu_type()) { | 1012 | switch (current_cpu_type()) { |
995 | case CPU_24K: | 1013 | case CPU_24K: |
996 | case CPU_34K: | 1014 | case CPU_34K: |
1015 | case CPU_74K: | ||
1016 | case CPU_1004K: | ||
1017 | { | ||
1018 | #define ERRCTL_PE 0x80000000 | ||
1019 | #define ERRCTL_L2P 0x00800000 | ||
1020 | unsigned long errctl; | ||
1021 | unsigned int l1parity_present, l2parity_present; | ||
1022 | |||
1023 | errctl = read_c0_ecc(); | ||
1024 | errctl &= ~(ERRCTL_PE|ERRCTL_L2P); | ||
1025 | |||
1026 | /* probe L1 parity support */ | ||
1027 | write_c0_ecc(errctl | ERRCTL_PE); | ||
1028 | back_to_back_c0_hazard(); | ||
1029 | l1parity_present = (read_c0_ecc() & ERRCTL_PE); | ||
1030 | |||
1031 | /* probe L2 parity support */ | ||
1032 | write_c0_ecc(errctl|ERRCTL_L2P); | ||
1033 | back_to_back_c0_hazard(); | ||
1034 | l2parity_present = (read_c0_ecc() & ERRCTL_L2P); | ||
1035 | |||
1036 | if (l1parity_present && l2parity_present) { | ||
1037 | if (l1parity) | ||
1038 | errctl |= ERRCTL_PE; | ||
1039 | if (l1parity ^ l2parity) | ||
1040 | errctl |= ERRCTL_L2P; | ||
1041 | } else if (l1parity_present) { | ||
1042 | if (l1parity) | ||
1043 | errctl |= ERRCTL_PE; | ||
1044 | } else if (l2parity_present) { | ||
1045 | if (l2parity) | ||
1046 | errctl |= ERRCTL_L2P; | ||
1047 | } else { | ||
1048 | /* No parity available */ | ||
1049 | } | ||
1050 | |||
1051 | printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl); | ||
1052 | |||
1053 | write_c0_ecc(errctl); | ||
1054 | back_to_back_c0_hazard(); | ||
1055 | errctl = read_c0_ecc(); | ||
1056 | printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl); | ||
1057 | |||
1058 | if (l1parity_present) | ||
1059 | printk(KERN_INFO "Cache parity protection %sabled\n", | ||
1060 | (errctl & ERRCTL_PE) ? "en" : "dis"); | ||
1061 | |||
1062 | if (l2parity_present) { | ||
1063 | if (l1parity_present && l1parity) | ||
1064 | errctl ^= ERRCTL_L2P; | ||
1065 | printk(KERN_INFO "L2 cache parity protection %sabled\n", | ||
1066 | (errctl & ERRCTL_L2P) ? "en" : "dis"); | ||
1067 | } | ||
1068 | } | ||
1069 | break; | ||
1070 | |||
997 | case CPU_5KC: | 1071 | case CPU_5KC: |
998 | write_c0_ecc(0x80000000); | 1072 | write_c0_ecc(0x80000000); |
999 | back_to_back_c0_hazard(); | 1073 | back_to_back_c0_hazard(); |
@@ -1306,6 +1380,17 @@ int cp0_compare_irq; | |||
1306 | int cp0_perfcount_irq; | 1380 | int cp0_perfcount_irq; |
1307 | EXPORT_SYMBOL_GPL(cp0_perfcount_irq); | 1381 | EXPORT_SYMBOL_GPL(cp0_perfcount_irq); |
1308 | 1382 | ||
1383 | static int __cpuinitdata noulri; | ||
1384 | |||
1385 | static int __init ulri_disable(char *s) | ||
1386 | { | ||
1387 | pr_info("Disabling ulri\n"); | ||
1388 | noulri = 1; | ||
1389 | |||
1390 | return 1; | ||
1391 | } | ||
1392 | __setup("noulri", ulri_disable); | ||
1393 | |||
1309 | void __cpuinit per_cpu_trap_init(void) | 1394 | void __cpuinit per_cpu_trap_init(void) |
1310 | { | 1395 | { |
1311 | unsigned int cpu = smp_processor_id(); | 1396 | unsigned int cpu = smp_processor_id(); |
@@ -1342,16 +1427,14 @@ void __cpuinit per_cpu_trap_init(void) | |||
1342 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, | 1427 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, |
1343 | status_set); | 1428 | status_set); |
1344 | 1429 | ||
1345 | #ifdef CONFIG_CPU_MIPSR2 | ||
1346 | if (cpu_has_mips_r2) { | 1430 | if (cpu_has_mips_r2) { |
1347 | unsigned int enable = 0x0000000f; | 1431 | unsigned int enable = 0x0000000f; |
1348 | 1432 | ||
1349 | if (cpu_has_userlocal) | 1433 | if (!noulri && cpu_has_userlocal) |
1350 | enable |= (1 << 29); | 1434 | enable |= (1 << 29); |
1351 | 1435 | ||
1352 | write_c0_hwrena(enable); | 1436 | write_c0_hwrena(enable); |
1353 | } | 1437 | } |
1354 | #endif | ||
1355 | 1438 | ||
1356 | #ifdef CONFIG_MIPS_MT_SMTC | 1439 | #ifdef CONFIG_MIPS_MT_SMTC |
1357 | if (!secondaryTC) { | 1440 | if (!secondaryTC) { |