Merge branch 'akpm' (patches from Andrew)
[linux-2.6-microblaze.git] / arch / powerpc / mm / fault.c
index 34f641d..eb8ecd7 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/kfence.h>
 #include <linux/pkeys.h>
 
+#include <asm/asm-prototypes.h>
 #include <asm/firmware.h>
 #include <asm/interrupt.h>
 #include <asm/page.h>
@@ -199,9 +200,7 @@ static bool bad_kernel_fault(struct pt_regs *regs, unsigned long error_code,
 {
        int is_exec = TRAP(regs) == INTERRUPT_INST_STORAGE;
 
-       /* NX faults set DSISR_PROTFAULT on the 8xx, DSISR_NOEXEC_OR_G on others */
-       if (is_exec && (error_code & (DSISR_NOEXEC_OR_G | DSISR_KEYFAULT |
-                                     DSISR_PROTFAULT))) {
+       if (is_exec) {
                pr_crit_ratelimited("kernel tried to execute %s page (%lx) - exploit attempt? (uid: %d)\n",
                                    address >= TASK_SIZE ? "exec-protected" : "user",
                                    address,
@@ -518,10 +517,8 @@ retry:
         * case.
         */
        if (unlikely(fault & VM_FAULT_RETRY)) {
-               if (flags & FAULT_FLAG_ALLOW_RETRY) {
-                       flags |= FAULT_FLAG_TRIED;
-                       goto retry;
-               }
+               flags |= FAULT_FLAG_TRIED;
+               goto retry;
        }
 
        mmap_read_unlock(current->mm);
@@ -622,4 +619,27 @@ DEFINE_INTERRUPT_HANDLER(do_bad_page_fault_segv)
 {
        bad_page_fault(regs, SIGSEGV);
 }
+
+/*
+ * In radix, segment interrupts indicate the EA is not addressable by the
+ * page table geometry, so they are always sent here.
+ *
+ * In hash, this is called if do_slb_fault returns error. Typically it is
+ * because the EA was outside the region allowed by software.
+ */
+DEFINE_INTERRUPT_HANDLER(do_bad_segment_interrupt)
+{
+       int err = regs->result;
+
+       if (err == -EFAULT) {
+               if (user_mode(regs))
+                       _exception(SIGSEGV, regs, SEGV_BNDERR, regs->dar);
+               else
+                       bad_page_fault(regs, SIGSEGV);
+       } else if (err == -EINVAL) {
+               unrecoverable_exception(regs);
+       } else {
+               BUG();
+       }
+}
 #endif