Merge branch 'for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[sfrench/cifs-2.6.git] / arch / arm64 / mm / fault.c
index 9b7f89df49dbfe108da2eadc59421ce99a4432b4..ce441d29e7f6ed797b74228ff6284a6224baef9b 100644 (file)
@@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 
        info.si_signo = SIGBUS;
        info.si_errno = 0;
-       info.si_code  = 0;
+       info.si_code  = BUS_FIXME;
        if (esr & ESR_ELx_FnV)
                info.si_addr = NULL;
        else
@@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 }
 
 static const struct fault_info fault_info[] = {
-       { do_bad,               SIGBUS,  0,             "ttbr address size fault"       },
-       { do_bad,               SIGBUS,  0,             "level 1 address size fault"    },
-       { do_bad,               SIGBUS,  0,             "level 2 address size fault"    },
-       { do_bad,               SIGBUS,  0,             "level 3 address size fault"    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "ttbr address size fault"       },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "level 1 address size fault"    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "level 2 address size fault"    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "level 3 address size fault"    },
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 0 translation fault"     },
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 1 translation fault"     },
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 2 translation fault"     },
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 3 translation fault"     },
-       { do_bad,               SIGBUS,  0,             "unknown 8"                     },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 8"                     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault"     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 access flag fault"     },
-       { do_bad,               SIGBUS,  0,             "unknown 12"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 12"                    },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"      },
-       { do_sea,               SIGBUS,  0,             "synchronous external abort"    },
-       { do_bad,               SIGBUS,  0,             "unknown 17"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 18"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 19"                    },
-       { do_sea,               SIGBUS,  0,             "level 0 (translation table walk)"      },
-       { do_sea,               SIGBUS,  0,             "level 1 (translation table walk)"      },
-       { do_sea,               SIGBUS,  0,             "level 2 (translation table walk)"      },
-       { do_sea,               SIGBUS,  0,             "level 3 (translation table walk)"      },
-       { do_sea,               SIGBUS,  0,             "synchronous parity or ECC error" },    // Reserved when RAS is implemented
-       { do_bad,               SIGBUS,  0,             "unknown 25"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 26"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 27"                    },
-       { do_sea,               SIGBUS,  0,             "level 0 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
-       { do_sea,               SIGBUS,  0,             "level 1 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
-       { do_sea,               SIGBUS,  0,             "level 2 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
-       { do_sea,               SIGBUS,  0,             "level 3 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
-       { do_bad,               SIGBUS,  0,             "unknown 32"                    },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "synchronous external abort"    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 17"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 18"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 19"                    },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 0 (translation table walk)"      },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 1 (translation table walk)"      },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 2 (translation table walk)"      },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 3 (translation table walk)"      },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "synchronous parity or ECC error" },    // Reserved when RAS is implemented
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 25"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 26"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 27"                    },
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 0 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 1 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 2 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
+       { do_sea,               SIGBUS,  BUS_FIXME,     "level 3 synchronous parity error (translation table walk)"     },      // Reserved when RAS is implemented
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 32"                    },
        { do_alignment_fault,   SIGBUS,  BUS_ADRALN,    "alignment fault"               },
-       { do_bad,               SIGBUS,  0,             "unknown 34"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 35"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 36"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 37"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 38"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 39"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 40"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 41"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 42"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 43"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 44"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 45"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 46"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 47"                    },
-       { do_bad,               SIGBUS,  0,             "TLB conflict abort"            },
-       { do_bad,               SIGBUS,  0,             "Unsupported atomic hardware update fault"      },
-       { do_bad,               SIGBUS,  0,             "unknown 50"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 51"                    },
-       { do_bad,               SIGBUS,  0,             "implementation fault (lockdown abort)" },
-       { do_bad,               SIGBUS,  0,             "implementation fault (unsupported exclusive)" },
-       { do_bad,               SIGBUS,  0,             "unknown 54"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 55"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 56"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 57"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 58"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 59"                    },
-       { do_bad,               SIGBUS,  0,             "unknown 60"                    },
-       { do_bad,               SIGBUS,  0,             "section domain fault"          },
-       { do_bad,               SIGBUS,  0,             "page domain fault"             },
-       { do_bad,               SIGBUS,  0,             "unknown 63"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 34"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 35"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 36"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 37"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 38"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 39"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 40"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 41"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 42"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 43"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 44"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 45"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 46"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 47"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "TLB conflict abort"            },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "Unsupported atomic hardware update fault"      },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 50"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 51"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "implementation fault (lockdown abort)" },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "implementation fault (unsupported exclusive)" },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 54"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 55"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 56"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 57"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 58"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 59"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 60"                    },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "section domain fault"          },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "page domain fault"             },
+       { do_bad,               SIGBUS,  BUS_FIXME,     "unknown 63"                    },
 };
 
 int handle_guest_sea(phys_addr_t addr, unsigned int esr)
@@ -707,6 +707,23 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
        arm64_notify_die("", regs, &info, esr);
 }
 
+asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr,
+                                                  unsigned int esr,
+                                                  struct pt_regs *regs)
+{
+       /*
+        * We've taken an instruction abort from userspace and not yet
+        * re-enabled IRQs. If the address is a kernel address, apply
+        * BP hardening prior to enabling IRQs and pre-emption.
+        */
+       if (addr > TASK_SIZE)
+               arm64_apply_bp_hardening();
+
+       local_irq_enable();
+       do_mem_abort(addr, esr, regs);
+}
+
+
 asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
                                           unsigned int esr,
                                           struct pt_regs *regs)
@@ -739,11 +756,11 @@ static struct fault_info __refdata debug_fault_info[] = {
        { do_bad,       SIGTRAP,        TRAP_HWBKPT,    "hardware breakpoint"   },
        { do_bad,       SIGTRAP,        TRAP_HWBKPT,    "hardware single-step"  },
        { do_bad,       SIGTRAP,        TRAP_HWBKPT,    "hardware watchpoint"   },
-       { do_bad,       SIGBUS,         0,              "unknown 3"             },
+       { do_bad,       SIGBUS,         BUS_FIXME,      "unknown 3"             },
        { do_bad,       SIGTRAP,        TRAP_BRKPT,     "aarch32 BKPT"          },
-       { do_bad,       SIGTRAP,        0,              "aarch32 vector catch"  },
+       { do_bad,       SIGTRAP,        TRAP_FIXME,     "aarch32 vector catch"  },
        { early_brk64,  SIGTRAP,        TRAP_BRKPT,     "aarch64 BRK"           },
-       { do_bad,       SIGBUS,         0,              "unknown 7"             },
+       { do_bad,       SIGBUS,         BUS_FIXME,      "unknown 7"             },
 };
 
 void __init hook_debug_fault_code(int nr,