aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorLi Zhong <zhong@linux.vnet.ibm.com>2013-05-13 12:16:41 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-05-14 02:00:19 -0400
commitba12eedee321eeb5baecaada285daeb3462c35f5 (patch)
tree68e9481dc69d8f5f412b5bba278ade75a4686a8f /arch/powerpc
parent22ecbe8dcef4f6bf80ed4358600e8f6e03105c5c (diff)
powerpc: Exception hooks for context tracking subsystem
This is the exception hooks for context tracking subsystem, including data access, program check, single step, instruction breakpoint, machine check, alignment, fp unavailable, altivec assist, unknown exception, whose handlers might use RCU. This patch corresponds to [PATCH] x86: Exception hooks for userspace RCU extended QS commit 6ba3c97a38803883c2eee489505796cb0a727122 But after the exception handling moved to generic code, and some changes in following two commits: 56dd9470d7c8734f055da2a6bac553caf4a468eb context_tracking: Move exception handling to generic code 6c1e0256fad84a843d915414e4b5973b7443d48d context_tracking: Restore correct previous context state on exception exit it is able for exception hooks to use the generic code above instead of a redundant arch implementation. Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/traps.c80
-rw-r--r--arch/powerpc/mm/fault.c41
-rw-r--r--arch/powerpc/mm/hash_utils_64.c36
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
668void machine_check_exception(struct pt_regs *regs) 669void 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
713bail:
714 exception_exit(prev_state);
710} 715}
711 716
712void SMIException(struct pt_regs *regs) 717void SMIException(struct pt_regs *regs)
@@ -716,20 +721,29 @@ void SMIException(struct pt_regs *regs)
716 721
717void unknown_exception(struct pt_regs *regs) 722void 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
725void instruction_breakpoint_exception(struct pt_regs *regs) 734void 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
745bail:
746 exception_exit(prev_state);
733} 747}
734 748
735void RunModeException(struct pt_regs *regs) 749void RunModeException(struct pt_regs *regs)
@@ -739,15 +753,20 @@ void RunModeException(struct pt_regs *regs)
739 753
740void __kprobes single_step_exception(struct pt_regs *regs) 754void __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
768bail:
769 exception_exit(prev_state);
751} 770}
752 771
753/* 772/*
@@ -1005,6 +1024,7 @@ int is_valid_bugaddr(unsigned long addr)
1005 1024
1006void __kprobes program_check_exception(struct pt_regs *regs) 1025void __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
1138bail:
1139 exception_exit(prev_state);
1117} 1140}
1118 1141
1119void alignment_exception(struct pt_regs *regs) 1142void 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
1174bail:
1175 exception_exit(prev_state);
1149} 1176}
1150 1177
1151void StackOverflow(struct pt_regs *regs) 1178void StackOverflow(struct pt_regs *regs)
@@ -1174,23 +1201,32 @@ void trace_syscall(struct pt_regs *regs)
1174 1201
1175void kernel_fp_unavailable_exception(struct pt_regs *regs) 1202void 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
1182void altivec_unavailable_exception(struct pt_regs *regs) 1213void 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
1228bail:
1229 exception_exit(prev_state);
1194} 1230}
1195 1231
1196void vsx_unavailable_exception(struct pt_regs *regs) 1232void 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)
196int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, 197int __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
459bad_area: 468bad_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
485bail:
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 */
955int hash_page(unsigned long ea, unsigned long access, unsigned long trap) 956int 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
1139bail:
1140 exception_exit(prev_state);
1127 return rc; 1141 return rc;
1128} 1142}
1129EXPORT_SYMBOL_GPL(hash_page); 1143EXPORT_SYMBOL_GPL(hash_page);
@@ -1259,6 +1273,8 @@ void flush_hash_range(unsigned long number, int local)
1259 */ 1273 */
1260void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) 1274void 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
1273long hpte_insert_repeating(unsigned long hash, unsigned long vpn, 1291long hpte_insert_repeating(unsigned long hash, unsigned long vpn,