diff options
-rw-r--r-- | arch/powerpc/kernel/traps.c | 80 | ||||
-rw-r--r-- | arch/powerpc/mm/fault.c | 41 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 36 |
3 files changed, 112 insertions, 45 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) |
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 229951ffc351..8726779e1409 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/perf_event.h> | 32 | #include <linux/perf_event.h> |
33 | #include <linux/magic.h> | 33 | #include <linux/magic.h> |
34 | #include <linux/ratelimit.h> | 34 | #include <linux/ratelimit.h> |
35 | #include <linux/context_tracking.h> | ||
35 | 36 | ||
36 | #include <asm/firmware.h> | 37 | #include <asm/firmware.h> |
37 | #include <asm/page.h> | 38 | #include <asm/page.h> |
@@ -196,6 +197,7 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) | |||
196 | int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | 197 | int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, |
197 | unsigned long error_code) | 198 | unsigned long error_code) |
198 | { | 199 | { |
200 | enum ctx_state prev_state = exception_enter(); | ||
199 | struct vm_area_struct * vma; | 201 | struct vm_area_struct * vma; |
200 | struct mm_struct *mm = current->mm; | 202 | struct mm_struct *mm = current->mm; |
201 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; | 203 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; |
@@ -204,6 +206,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
204 | int trap = TRAP(regs); | 206 | int trap = TRAP(regs); |
205 | int is_exec = trap == 0x400; | 207 | int is_exec = trap == 0x400; |
206 | int fault; | 208 | int fault; |
209 | int rc = 0; | ||
207 | 210 | ||
208 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) | 211 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) |
209 | /* | 212 | /* |
@@ -230,28 +233,30 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
230 | * look at it | 233 | * look at it |
231 | */ | 234 | */ |
232 | if (error_code & ICSWX_DSI_UCT) { | 235 | if (error_code & ICSWX_DSI_UCT) { |
233 | int rc = acop_handle_fault(regs, address, error_code); | 236 | rc = acop_handle_fault(regs, address, error_code); |
234 | if (rc) | 237 | if (rc) |
235 | return rc; | 238 | goto bail; |
236 | } | 239 | } |
237 | #endif /* CONFIG_PPC_ICSWX */ | 240 | #endif /* CONFIG_PPC_ICSWX */ |
238 | 241 | ||
239 | if (notify_page_fault(regs)) | 242 | if (notify_page_fault(regs)) |
240 | return 0; | 243 | goto bail; |
241 | 244 | ||
242 | if (unlikely(debugger_fault_handler(regs))) | 245 | if (unlikely(debugger_fault_handler(regs))) |
243 | return 0; | 246 | goto bail; |
244 | 247 | ||
245 | /* On a kernel SLB miss we can only check for a valid exception entry */ | 248 | /* On a kernel SLB miss we can only check for a valid exception entry */ |
246 | if (!user_mode(regs) && (address >= TASK_SIZE)) | 249 | if (!user_mode(regs) && (address >= TASK_SIZE)) { |
247 | return SIGSEGV; | 250 | rc = SIGSEGV; |
251 | goto bail; | ||
252 | } | ||
248 | 253 | ||
249 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \ | 254 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \ |
250 | defined(CONFIG_PPC_BOOK3S_64)) | 255 | defined(CONFIG_PPC_BOOK3S_64)) |
251 | if (error_code & DSISR_DABRMATCH) { | 256 | if (error_code & DSISR_DABRMATCH) { |
252 | /* breakpoint match */ | 257 | /* breakpoint match */ |
253 | do_break(regs, address, error_code); | 258 | do_break(regs, address, error_code); |
254 | return 0; | 259 | goto bail; |
255 | } | 260 | } |
256 | #endif | 261 | #endif |
257 | 262 | ||
@@ -260,8 +265,10 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
260 | local_irq_enable(); | 265 | local_irq_enable(); |
261 | 266 | ||
262 | if (in_atomic() || mm == NULL) { | 267 | if (in_atomic() || mm == NULL) { |
263 | if (!user_mode(regs)) | 268 | if (!user_mode(regs)) { |
264 | return SIGSEGV; | 269 | rc = SIGSEGV; |
270 | goto bail; | ||
271 | } | ||
265 | /* in_atomic() in user mode is really bad, | 272 | /* in_atomic() in user mode is really bad, |
266 | as is current->mm == NULL. */ | 273 | as is current->mm == NULL. */ |
267 | printk(KERN_EMERG "Page fault in user mode with " | 274 | printk(KERN_EMERG "Page fault in user mode with " |
@@ -417,9 +424,11 @@ good_area: | |||
417 | */ | 424 | */ |
418 | fault = handle_mm_fault(mm, vma, address, flags); | 425 | fault = handle_mm_fault(mm, vma, address, flags); |
419 | if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { | 426 | if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { |
420 | int rc = mm_fault_error(regs, address, fault); | 427 | rc = mm_fault_error(regs, address, fault); |
421 | if (rc >= MM_FAULT_RETURN) | 428 | if (rc >= MM_FAULT_RETURN) |
422 | return rc; | 429 | goto bail; |
430 | else | ||
431 | rc = 0; | ||
423 | } | 432 | } |
424 | 433 | ||
425 | /* | 434 | /* |
@@ -454,7 +463,7 @@ good_area: | |||
454 | } | 463 | } |
455 | 464 | ||
456 | up_read(&mm->mmap_sem); | 465 | up_read(&mm->mmap_sem); |
457 | return 0; | 466 | goto bail; |
458 | 467 | ||
459 | bad_area: | 468 | bad_area: |
460 | up_read(&mm->mmap_sem); | 469 | up_read(&mm->mmap_sem); |
@@ -463,7 +472,7 @@ bad_area_nosemaphore: | |||
463 | /* User mode accesses cause a SIGSEGV */ | 472 | /* User mode accesses cause a SIGSEGV */ |
464 | if (user_mode(regs)) { | 473 | if (user_mode(regs)) { |
465 | _exception(SIGSEGV, regs, code, address); | 474 | _exception(SIGSEGV, regs, code, address); |
466 | return 0; | 475 | goto bail; |
467 | } | 476 | } |
468 | 477 | ||
469 | if (is_exec && (error_code & DSISR_PROTFAULT)) | 478 | if (is_exec && (error_code & DSISR_PROTFAULT)) |
@@ -471,7 +480,11 @@ bad_area_nosemaphore: | |||
471 | " page (%lx) - exploit attempt? (uid: %d)\n", | 480 | " page (%lx) - exploit attempt? (uid: %d)\n", |
472 | address, from_kuid(&init_user_ns, current_uid())); | 481 | address, from_kuid(&init_user_ns, current_uid())); |
473 | 482 | ||
474 | return SIGSEGV; | 483 | rc = SIGSEGV; |
484 | |||
485 | bail: | ||
486 | exception_exit(prev_state); | ||
487 | return rc; | ||
475 | 488 | ||
476 | } | 489 | } |
477 | 490 | ||
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 88ac0eeaadde..e303a6d74e3a 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/signal.h> | 34 | #include <linux/signal.h> |
35 | #include <linux/memblock.h> | 35 | #include <linux/memblock.h> |
36 | #include <linux/context_tracking.h> | ||
36 | 37 | ||
37 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
38 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
@@ -954,6 +955,7 @@ void hash_failure_debug(unsigned long ea, unsigned long access, | |||
954 | */ | 955 | */ |
955 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | 956 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap) |
956 | { | 957 | { |
958 | enum ctx_state prev_state = exception_enter(); | ||
957 | pgd_t *pgdir; | 959 | pgd_t *pgdir; |
958 | unsigned long vsid; | 960 | unsigned long vsid; |
959 | struct mm_struct *mm; | 961 | struct mm_struct *mm; |
@@ -973,7 +975,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
973 | mm = current->mm; | 975 | mm = current->mm; |
974 | if (! mm) { | 976 | if (! mm) { |
975 | DBG_LOW(" user region with no mm !\n"); | 977 | DBG_LOW(" user region with no mm !\n"); |
976 | return 1; | 978 | rc = 1; |
979 | goto bail; | ||
977 | } | 980 | } |
978 | psize = get_slice_psize(mm, ea); | 981 | psize = get_slice_psize(mm, ea); |
979 | ssize = user_segment_size(ea); | 982 | ssize = user_segment_size(ea); |
@@ -992,19 +995,23 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
992 | /* Not a valid range | 995 | /* Not a valid range |
993 | * Send the problem up to do_page_fault | 996 | * Send the problem up to do_page_fault |
994 | */ | 997 | */ |
995 | return 1; | 998 | rc = 1; |
999 | goto bail; | ||
996 | } | 1000 | } |
997 | DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid); | 1001 | DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid); |
998 | 1002 | ||
999 | /* Bad address. */ | 1003 | /* Bad address. */ |
1000 | if (!vsid) { | 1004 | if (!vsid) { |
1001 | DBG_LOW("Bad address!\n"); | 1005 | DBG_LOW("Bad address!\n"); |
1002 | return 1; | 1006 | rc = 1; |
1007 | goto bail; | ||
1003 | } | 1008 | } |
1004 | /* Get pgdir */ | 1009 | /* Get pgdir */ |
1005 | pgdir = mm->pgd; | 1010 | pgdir = mm->pgd; |
1006 | if (pgdir == NULL) | 1011 | if (pgdir == NULL) { |
1007 | return 1; | 1012 | rc = 1; |
1013 | goto bail; | ||
1014 | } | ||
1008 | 1015 | ||
1009 | /* Check CPU locality */ | 1016 | /* Check CPU locality */ |
1010 | tmp = cpumask_of(smp_processor_id()); | 1017 | tmp = cpumask_of(smp_processor_id()); |
@@ -1027,7 +1034,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1027 | ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift); | 1034 | ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift); |
1028 | if (ptep == NULL || !pte_present(*ptep)) { | 1035 | if (ptep == NULL || !pte_present(*ptep)) { |
1029 | DBG_LOW(" no PTE !\n"); | 1036 | DBG_LOW(" no PTE !\n"); |
1030 | return 1; | 1037 | rc = 1; |
1038 | goto bail; | ||
1031 | } | 1039 | } |
1032 | 1040 | ||
1033 | /* Add _PAGE_PRESENT to the required access perm */ | 1041 | /* Add _PAGE_PRESENT to the required access perm */ |
@@ -1038,13 +1046,16 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1038 | */ | 1046 | */ |
1039 | if (access & ~pte_val(*ptep)) { | 1047 | if (access & ~pte_val(*ptep)) { |
1040 | DBG_LOW(" no access !\n"); | 1048 | DBG_LOW(" no access !\n"); |
1041 | return 1; | 1049 | rc = 1; |
1050 | goto bail; | ||
1042 | } | 1051 | } |
1043 | 1052 | ||
1044 | #ifdef CONFIG_HUGETLB_PAGE | 1053 | #ifdef CONFIG_HUGETLB_PAGE |
1045 | if (hugeshift) | 1054 | if (hugeshift) { |
1046 | return __hash_page_huge(ea, access, vsid, ptep, trap, local, | 1055 | rc = __hash_page_huge(ea, access, vsid, ptep, trap, local, |
1047 | ssize, hugeshift, psize); | 1056 | ssize, hugeshift, psize); |
1057 | goto bail; | ||
1058 | } | ||
1048 | #endif /* CONFIG_HUGETLB_PAGE */ | 1059 | #endif /* CONFIG_HUGETLB_PAGE */ |
1049 | 1060 | ||
1050 | #ifndef CONFIG_PPC_64K_PAGES | 1061 | #ifndef CONFIG_PPC_64K_PAGES |
@@ -1124,6 +1135,9 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1124 | pte_val(*(ptep + PTRS_PER_PTE))); | 1135 | pte_val(*(ptep + PTRS_PER_PTE))); |
1125 | #endif | 1136 | #endif |
1126 | DBG_LOW(" -> rc=%d\n", rc); | 1137 | DBG_LOW(" -> rc=%d\n", rc); |
1138 | |||
1139 | bail: | ||
1140 | exception_exit(prev_state); | ||
1127 | return rc; | 1141 | return rc; |
1128 | } | 1142 | } |
1129 | EXPORT_SYMBOL_GPL(hash_page); | 1143 | EXPORT_SYMBOL_GPL(hash_page); |
@@ -1259,6 +1273,8 @@ void flush_hash_range(unsigned long number, int local) | |||
1259 | */ | 1273 | */ |
1260 | void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) | 1274 | void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) |
1261 | { | 1275 | { |
1276 | enum ctx_state prev_state = exception_enter(); | ||
1277 | |||
1262 | if (user_mode(regs)) { | 1278 | if (user_mode(regs)) { |
1263 | #ifdef CONFIG_PPC_SUBPAGE_PROT | 1279 | #ifdef CONFIG_PPC_SUBPAGE_PROT |
1264 | if (rc == -2) | 1280 | if (rc == -2) |
@@ -1268,6 +1284,8 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) | |||
1268 | _exception(SIGBUS, regs, BUS_ADRERR, address); | 1284 | _exception(SIGBUS, regs, BUS_ADRERR, address); |
1269 | } else | 1285 | } else |
1270 | bad_page_fault(regs, address, SIGBUS); | 1286 | bad_page_fault(regs, address, SIGBUS); |
1287 | |||
1288 | exception_exit(prev_state); | ||
1271 | } | 1289 | } |
1272 | 1290 | ||
1273 | long hpte_insert_repeating(unsigned long hash, unsigned long vpn, | 1291 | long hpte_insert_repeating(unsigned long hash, unsigned long vpn, |