Merge remote-tracking branch 'arm64/for-next/fixes' into for-next/core
[sfrench/cifs-2.6.git] / arch / arm64 / kernel / traps.c
index 8af4e0e8573666e8f3bf68930ad412b189bfd04f..08156be755691d6cb7dd239119326ef4a3904b87 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
 #include <asm/esr.h>
+#include <asm/exception.h>
 #include <asm/extable.h>
 #include <asm/insn.h>
 #include <asm/kprobes.h>
@@ -170,32 +171,32 @@ static void arm64_show_signal(int signo, const char *str)
        __show_regs(regs);
 }
 
-void arm64_force_sig_fault(int signo, int code, void __user *addr,
+void arm64_force_sig_fault(int signo, int code, unsigned long far,
                           const char *str)
 {
        arm64_show_signal(signo, str);
        if (signo == SIGKILL)
                force_sig(SIGKILL);
        else
-               force_sig_fault(signo, code, addr);
+               force_sig_fault(signo, code, (void __user *)far);
 }
 
-void arm64_force_sig_mceerr(int code, void __user *addr, short lsb,
+void arm64_force_sig_mceerr(int code, unsigned long far, short lsb,
                            const char *str)
 {
        arm64_show_signal(SIGBUS, str);
-       force_sig_mceerr(code, addr, lsb);
+       force_sig_mceerr(code, (void __user *)far, lsb);
 }
 
-void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr,
+void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far,
                                       const char *str)
 {
        arm64_show_signal(SIGTRAP, str);
-       force_sig_ptrace_errno_trap(errno, addr);
+       force_sig_ptrace_errno_trap(errno, (void __user *)far);
 }
 
 void arm64_notify_die(const char *str, struct pt_regs *regs,
-                     int signo, int sicode, void __user *addr,
+                     int signo, int sicode, unsigned long far,
                      int err)
 {
        if (user_mode(regs)) {
@@ -203,7 +204,7 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
                current->thread.fault_address = 0;
                current->thread.fault_code = err;
 
-               arm64_force_sig_fault(signo, sicode, addr, str);
+               arm64_force_sig_fault(signo, sicode, far, str);
        } else {
                die(str, regs, err);
        }
@@ -374,7 +375,7 @@ void force_signal_inject(int signal, int code, unsigned long address, unsigned i
                signal = SIGKILL;
        }
 
-       arm64_notify_die(desc, regs, signal, code, (void __user *)address, err);
+       arm64_notify_die(desc, regs, signal, code, address, err);
 }
 
 /*
@@ -385,7 +386,7 @@ void arm64_notify_segfault(unsigned long addr)
        int code;
 
        mmap_read_lock(current->mm);
-       if (find_vma(current->mm, addr) == NULL)
+       if (find_vma(current->mm, untagged_addr(addr)) == NULL)
                code = SEGV_MAPERR;
        else
                code = SEGV_ACCERR;
@@ -448,12 +449,13 @@ NOKPROBE_SYMBOL(do_ptrauth_fault);
 
 static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
 {
-       unsigned long address;
+       unsigned long tagged_address, address;
        int rt = ESR_ELx_SYS64_ISS_RT(esr);
        int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
        int ret = 0;
 
-       address = untagged_addr(pt_regs_read_reg(regs, rt));
+       tagged_address = pt_regs_read_reg(regs, rt);
+       address = untagged_addr(tagged_address);
 
        switch (crm) {
        case ESR_ELx_SYS64_ISS_CRM_DC_CVAU:     /* DC CVAU, gets promoted */
@@ -480,7 +482,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
        }
 
        if (ret)
-               arm64_notify_segfault(address);
+               arm64_notify_segfault(tagged_address);
        else
                arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
 }
@@ -753,8 +755,10 @@ const char *esr_get_class_string(u32 esr)
  * bad_mode handles the impossible case in the exception vector. This is always
  * fatal.
  */
-asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
+asmlinkage void notrace bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
 {
+       arm64_enter_nmi(regs);
+
        console_verbose();
 
        pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %s\n",
@@ -772,7 +776,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
  */
 void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
 {
-       void __user *pc = (void __user *)instruction_pointer(regs);
+       unsigned long pc = instruction_pointer(regs);
 
        current->thread.fault_address = 0;
        current->thread.fault_code = esr;
@@ -786,7 +790,7 @@ void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
 DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
        __aligned(16);
 
-asmlinkage void handle_bad_stack(struct pt_regs *regs)
+asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
 {
        unsigned long tsk_stk = (unsigned long)current->stack;
        unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr);
@@ -794,6 +798,8 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
        unsigned int esr = read_sysreg(esr_el1);
        unsigned long far = read_sysreg(far_el1);
 
+       arm64_enter_nmi(regs);
+
        console_verbose();
        pr_emerg("Insufficient stack space to handle exception!");
 
@@ -865,23 +871,16 @@ bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr)
        }
 }
 
-asmlinkage void do_serror(struct pt_regs *regs, unsigned int esr)
+asmlinkage void noinstr do_serror(struct pt_regs *regs, unsigned int esr)
 {
-       nmi_enter();
+       arm64_enter_nmi(regs);
 
        /* non-RAS errors are not containable */
        if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(regs, esr))
                arm64_serror_panic(regs, esr);
 
-       nmi_exit();
-}
-
-asmlinkage void enter_from_user_mode(void)
-{
-       CT_WARN_ON(ct_state() != CONTEXT_USER);
-       user_exit_irqoff();
+       arm64_exit_nmi(regs);
 }
-NOKPROBE_SYMBOL(enter_from_user_mode);
 
 /* GENERIC_BUG traps */