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) |
