diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 83efa2f7d926..a7a648f6b750 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/kdebug.h> | 35 | #include <linux/kdebug.h> |
36 | #include <linux/debugfs.h> | 36 | #include <linux/debugfs.h> |
37 | #include <linux/ratelimit.h> | 37 | #include <linux/ratelimit.h> |
38 | #include <linux/context_tracking.h> | ||
38 | 39 | ||
39 | #include <asm/emulated_ops.h> | 40 | #include <asm/emulated_ops.h> |
40 | #include <asm/pgtable.h> | 41 | #include <asm/pgtable.h> |
@@ -667,6 +668,7 @@ int machine_check_generic(struct pt_regs *regs) | |||
667 | 668 | ||
668 | void machine_check_exception(struct pt_regs *regs) | 669 | void machine_check_exception(struct pt_regs *regs) |
669 | { | 670 | { |
671 | enum ctx_state prev_state = exception_enter(); | ||
670 | int recover = 0; | 672 | int recover = 0; |
671 | 673 | ||
672 | __get_cpu_var(irq_stat).mce_exceptions++; | 674 | __get_cpu_var(irq_stat).mce_exceptions++; |
@@ -683,7 +685,7 @@ void machine_check_exception(struct pt_regs *regs) | |||
683 | recover = cur_cpu_spec->machine_check(regs); | 685 | recover = cur_cpu_spec->machine_check(regs); |
684 | 686 | ||
685 | if (recover > 0) | 687 | if (recover > 0) |
686 | return; | 688 | goto bail; |
687 | 689 | ||
688 | #if defined(CONFIG_8xx) && defined(CONFIG_PCI) | 690 | #if defined(CONFIG_8xx) && defined(CONFIG_PCI) |
689 | /* the qspan pci read routines can cause machine checks -- Cort | 691 | /* the qspan pci read routines can cause machine checks -- Cort |
@@ -693,20 +695,23 @@ void machine_check_exception(struct pt_regs *regs) | |||
693 | * -- BenH | 695 | * -- BenH |
694 | */ | 696 | */ |
695 | bad_page_fault(regs, regs->dar, SIGBUS); | 697 | bad_page_fault(regs, regs->dar, SIGBUS); |
696 | return; | 698 | goto bail; |
697 | #endif | 699 | #endif |
698 | 700 | ||
699 | if (debugger_fault_handler(regs)) | 701 | if (debugger_fault_handler(regs)) |
700 | return; | 702 | goto bail; |
701 | 703 | ||
702 | if (check_io_access(regs)) | 704 | if (check_io_access(regs)) |
703 | return; | 705 | goto bail; |
704 | 706 | ||
705 | die("Machine check", regs, SIGBUS); | 707 | die("Machine check", regs, SIGBUS); |
706 | 708 | ||
707 | /* Must die if the interrupt is not recoverable */ | 709 | /* Must die if the interrupt is not recoverable */ |
708 | if (!(regs->msr & MSR_RI)) | 710 | if (!(regs->msr & MSR_RI)) |
709 | panic("Unrecoverable Machine check"); | 711 | panic("Unrecoverable Machine check"); |
712 | |||
713 | bail: | ||
714 | exception_exit(prev_state); | ||
710 | } | 715 | } |
711 | 716 | ||
712 | void SMIException(struct pt_regs *regs) | 717 | void SMIException(struct pt_regs *regs) |
@@ -716,20 +721,29 @@ void SMIException(struct pt_regs *regs) | |||
716 | 721 | ||
717 | void unknown_exception(struct pt_regs *regs) | 722 | void unknown_exception(struct pt_regs *regs) |
718 | { | 723 | { |
724 | enum ctx_state prev_state = exception_enter(); | ||
725 | |||
719 | printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", | 726 | printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", |
720 | regs->nip, regs->msr, regs->trap); | 727 | regs->nip, regs->msr, regs->trap); |
721 | 728 | ||
722 | _exception(SIGTRAP, regs, 0, 0); | 729 | _exception(SIGTRAP, regs, 0, 0); |
730 | |||
731 | exception_exit(prev_state); | ||
723 | } | 732 | } |
724 | 733 | ||
725 | void instruction_breakpoint_exception(struct pt_regs *regs) | 734 | void instruction_breakpoint_exception(struct pt_regs *regs) |
726 | { | 735 | { |
736 | enum ctx_state prev_state = exception_enter(); | ||
737 | |||
727 | if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5, | 738 | if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5, |
728 | 5, SIGTRAP) == NOTIFY_STOP) | 739 | 5, SIGTRAP) == NOTIFY_STOP) |
729 | return; | 740 | goto bail; |
730 | if (debugger_iabr_match(regs)) | 741 | if (debugger_iabr_match(regs)) |
731 | return; | 742 | goto bail; |
732 | _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); | 743 | _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); |
744 | |||
745 | bail: | ||
746 | exception_exit(prev_state); | ||
733 | } | 747 | } |
734 | 748 | ||
735 | void RunModeException(struct pt_regs *regs) | 749 | void RunModeException(struct pt_regs *regs) |
@@ -739,15 +753,20 @@ void RunModeException(struct pt_regs *regs) | |||
739 | 753 | ||
740 | void __kprobes single_step_exception(struct pt_regs *regs) | 754 | void __kprobes single_step_exception(struct pt_regs *regs) |
741 | { | 755 | { |
756 | enum ctx_state prev_state = exception_enter(); | ||
757 | |||
742 | clear_single_step(regs); | 758 | clear_single_step(regs); |
743 | 759 | ||
744 | if (notify_die(DIE_SSTEP, "single_step", regs, 5, | 760 | if (notify_die(DIE_SSTEP, "single_step", regs, 5, |
745 | 5, SIGTRAP) == NOTIFY_STOP) | 761 | 5, SIGTRAP) == NOTIFY_STOP) |
746 | return; | 762 | goto bail; |
747 | if (debugger_sstep(regs)) | 763 | if (debugger_sstep(regs)) |
748 | return; | 764 | goto bail; |
749 | 765 | ||
750 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); | 766 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); |
767 | |||
768 | bail: | ||
769 | exception_exit(prev_state); | ||
751 | } | 770 | } |
752 | 771 | ||
753 | /* | 772 | /* |
@@ -1005,6 +1024,7 @@ int is_valid_bugaddr(unsigned long addr) | |||
1005 | 1024 | ||
1006 | void __kprobes program_check_exception(struct pt_regs *regs) | 1025 | void __kprobes program_check_exception(struct pt_regs *regs) |
1007 | { | 1026 | { |
1027 | enum ctx_state prev_state = exception_enter(); | ||
1008 | unsigned int reason = get_reason(regs); | 1028 | unsigned int reason = get_reason(regs); |
1009 | extern int do_mathemu(struct pt_regs *regs); | 1029 | extern int do_mathemu(struct pt_regs *regs); |
1010 | 1030 | ||
@@ -1014,26 +1034,26 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1014 | if (reason & REASON_FP) { | 1034 | if (reason & REASON_FP) { |
1015 | /* IEEE FP exception */ | 1035 | /* IEEE FP exception */ |
1016 | parse_fpe(regs); | 1036 | parse_fpe(regs); |
1017 | return; | 1037 | goto bail; |
1018 | } | 1038 | } |
1019 | if (reason & REASON_TRAP) { | 1039 | if (reason & REASON_TRAP) { |
1020 | /* Debugger is first in line to stop recursive faults in | 1040 | /* Debugger is first in line to stop recursive faults in |
1021 | * rcu_lock, notify_die, or atomic_notifier_call_chain */ | 1041 | * rcu_lock, notify_die, or atomic_notifier_call_chain */ |
1022 | if (debugger_bpt(regs)) | 1042 | if (debugger_bpt(regs)) |
1023 | return; | 1043 | goto bail; |
1024 | 1044 | ||
1025 | /* trap exception */ | 1045 | /* trap exception */ |
1026 | if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP) | 1046 | if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP) |
1027 | == NOTIFY_STOP) | 1047 | == NOTIFY_STOP) |
1028 | return; | 1048 | goto bail; |
1029 | 1049 | ||
1030 | if (!(regs->msr & MSR_PR) && /* not user-mode */ | 1050 | if (!(regs->msr & MSR_PR) && /* not user-mode */ |
1031 | report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) { | 1051 | report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) { |
1032 | regs->nip += 4; | 1052 | regs->nip += 4; |
1033 | return; | 1053 | goto bail; |
1034 | } | 1054 | } |
1035 | _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); | 1055 | _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); |
1036 | return; | 1056 | goto bail; |
1037 | } | 1057 | } |
1038 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 1058 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
1039 | if (reason & REASON_TM) { | 1059 | if (reason & REASON_TM) { |
@@ -1049,7 +1069,7 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1049 | if (!user_mode(regs) && | 1069 | if (!user_mode(regs) && |
1050 | report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) { | 1070 | report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) { |
1051 | regs->nip += 4; | 1071 | regs->nip += 4; |
1052 | return; | 1072 | goto bail; |
1053 | } | 1073 | } |
1054 | /* If usermode caused this, it's done something illegal and | 1074 | /* If usermode caused this, it's done something illegal and |
1055 | * gets a SIGILL slap on the wrist. We call it an illegal | 1075 | * gets a SIGILL slap on the wrist. We call it an illegal |
@@ -1059,7 +1079,7 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1059 | */ | 1079 | */ |
1060 | if (user_mode(regs)) { | 1080 | if (user_mode(regs)) { |
1061 | _exception(SIGILL, regs, ILL_ILLOPN, regs->nip); | 1081 | _exception(SIGILL, regs, ILL_ILLOPN, regs->nip); |
1062 | return; | 1082 | goto bail; |
1063 | } else { | 1083 | } else { |
1064 | printk(KERN_EMERG "Unexpected TM Bad Thing exception " | 1084 | printk(KERN_EMERG "Unexpected TM Bad Thing exception " |
1065 | "at %lx (msr 0x%x)\n", regs->nip, reason); | 1085 | "at %lx (msr 0x%x)\n", regs->nip, reason); |
@@ -1083,16 +1103,16 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1083 | switch (do_mathemu(regs)) { | 1103 | switch (do_mathemu(regs)) { |
1084 | case 0: | 1104 | case 0: |
1085 | emulate_single_step(regs); | 1105 | emulate_single_step(regs); |
1086 | return; | 1106 | goto bail; |
1087 | case 1: { | 1107 | case 1: { |
1088 | int code = 0; | 1108 | int code = 0; |
1089 | code = __parse_fpscr(current->thread.fpscr.val); | 1109 | code = __parse_fpscr(current->thread.fpscr.val); |
1090 | _exception(SIGFPE, regs, code, regs->nip); | 1110 | _exception(SIGFPE, regs, code, regs->nip); |
1091 | return; | 1111 | goto bail; |
1092 | } | 1112 | } |
1093 | case -EFAULT: | 1113 | case -EFAULT: |
1094 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); | 1114 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); |
1095 | return; | 1115 | goto bail; |
1096 | } | 1116 | } |
1097 | /* fall through on any other errors */ | 1117 | /* fall through on any other errors */ |
1098 | #endif /* CONFIG_MATH_EMULATION */ | 1118 | #endif /* CONFIG_MATH_EMULATION */ |
@@ -1103,10 +1123,10 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1103 | case 0: | 1123 | case 0: |
1104 | regs->nip += 4; | 1124 | regs->nip += 4; |
1105 | emulate_single_step(regs); | 1125 | emulate_single_step(regs); |
1106 | return; | 1126 | goto bail; |
1107 | case -EFAULT: | 1127 | case -EFAULT: |
1108 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); | 1128 | _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); |
1109 | return; | 1129 | goto bail; |
1110 | } | 1130 | } |
1111 | } | 1131 | } |
1112 | 1132 | ||
@@ -1114,10 +1134,14 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
1114 | _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); | 1134 | _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); |
1115 | else | 1135 | else |
1116 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 1136 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
1137 | |||
1138 | bail: | ||
1139 | exception_exit(prev_state); | ||
1117 | } | 1140 | } |
1118 | 1141 | ||
1119 | void alignment_exception(struct pt_regs *regs) | 1142 | void alignment_exception(struct pt_regs *regs) |
1120 | { | 1143 | { |
1144 | enum ctx_state prev_state = exception_enter(); | ||
1121 | int sig, code, fixed = 0; | 1145 | int sig, code, fixed = 0; |
1122 | 1146 | ||
1123 | /* We restore the interrupt state now */ | 1147 | /* We restore the interrupt state now */ |
@@ -1131,7 +1155,7 @@ void alignment_exception(struct pt_regs *regs) | |||
1131 | if (fixed == 1) { | 1155 | if (fixed == 1) { |
1132 | regs->nip += 4; /* skip over emulated instruction */ | 1156 | regs->nip += 4; /* skip over emulated instruction */ |
1133 | emulate_single_step(regs); | 1157 | emulate_single_step(regs); |
1134 | return; | 1158 | goto bail; |
1135 | } | 1159 | } |
1136 | 1160 | ||
1137 | /* Operand address was bad */ | 1161 | /* Operand address was bad */ |
@@ -1146,6 +1170,9 @@ void alignment_exception(struct pt_regs *regs) | |||
1146 | _exception(sig, regs, code, regs->dar); | 1170 | _exception(sig, regs, code, regs->dar); |
1147 | else | 1171 | else |
1148 | bad_page_fault(regs, regs->dar, sig); | 1172 | bad_page_fault(regs, regs->dar, sig); |
1173 | |||
1174 | bail: | ||
1175 | exception_exit(prev_state); | ||
1149 | } | 1176 | } |
1150 | 1177 | ||
1151 | void StackOverflow(struct pt_regs *regs) | 1178 | void StackOverflow(struct pt_regs *regs) |
@@ -1174,23 +1201,32 @@ void trace_syscall(struct pt_regs *regs) | |||
1174 | 1201 | ||
1175 | void kernel_fp_unavailable_exception(struct pt_regs *regs) | 1202 | void kernel_fp_unavailable_exception(struct pt_regs *regs) |
1176 | { | 1203 | { |
1204 | enum ctx_state prev_state = exception_enter(); | ||
1205 | |||
1177 | printk(KERN_EMERG "Unrecoverable FP Unavailable Exception " | 1206 | printk(KERN_EMERG "Unrecoverable FP Unavailable Exception " |
1178 | "%lx at %lx\n", regs->trap, regs->nip); | 1207 | "%lx at %lx\n", regs->trap, regs->nip); |
1179 | die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); | 1208 | die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); |
1209 | |||
1210 | exception_exit(prev_state); | ||
1180 | } | 1211 | } |
1181 | 1212 | ||
1182 | void altivec_unavailable_exception(struct pt_regs *regs) | 1213 | void altivec_unavailable_exception(struct pt_regs *regs) |
1183 | { | 1214 | { |
1215 | enum ctx_state prev_state = exception_enter(); | ||
1216 | |||
1184 | if (user_mode(regs)) { | 1217 | if (user_mode(regs)) { |
1185 | /* A user program has executed an altivec instruction, | 1218 | /* A user program has executed an altivec instruction, |
1186 | but this kernel doesn't support altivec. */ | 1219 | but this kernel doesn't support altivec. */ |
1187 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 1220 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
1188 | return; | 1221 | goto bail; |
1189 | } | 1222 | } |
1190 | 1223 | ||
1191 | printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " | 1224 | printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " |
1192 | "%lx at %lx\n", regs->trap, regs->nip); | 1225 | "%lx at %lx\n", regs->trap, regs->nip); |
1193 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); | 1226 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); |
1227 | |||
1228 | bail: | ||
1229 | exception_exit(prev_state); | ||
1194 | } | 1230 | } |
1195 | 1231 | ||
1196 | void vsx_unavailable_exception(struct pt_regs *regs) | 1232 | void vsx_unavailable_exception(struct pt_regs *regs) |