These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / mips / kernel / traps.c
index 5f5f44e..ca9a810 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/irq.h>
 #include <linux/perf_event.h>
 
+#include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
 #include <asm/break.h>
@@ -243,6 +244,7 @@ static void __show_regs(const struct pt_regs *regs)
 {
        const int field = 2 * sizeof(unsigned long);
        unsigned int cause = regs->cp0_cause;
+       unsigned int exccode;
        int i;
 
        show_regs_print_info(KERN_DEFAULT);
@@ -324,10 +326,10 @@ static void __show_regs(const struct pt_regs *regs)
        }
        printk("\n");
 
-       printk("Cause : %08x\n", cause);
+       exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
+       printk("Cause : %08x (ExcCode %02x)\n", cause, exccode);
 
-       cause = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
-       if (1 <= cause && cause <= 5)
+       if (1 <= exccode && exccode <= 5)
                printk("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
 
        printk("PrId  : %08x (%s)\n", read_c0_prid(),
@@ -369,11 +371,6 @@ void show_registers(struct pt_regs *regs)
        set_fs(old_fs);
 }
 
-static int regs_to_trapnr(struct pt_regs *regs)
-{
-       return (regs->cp0_cause >> 2) & 0x1f;
-}
-
 static DEFINE_RAW_SPINLOCK(die_lock);
 
 void __noreturn die(const char *str, struct pt_regs *regs)
@@ -383,7 +380,7 @@ void __noreturn die(const char *str, struct pt_regs *regs)
 
        oops_enter();
 
-       if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_nr,
                       SIGSEGV) == NOTIFY_STOP)
                sig = 0;
 
@@ -469,7 +466,7 @@ asmlinkage void do_be(struct pt_regs *regs)
        printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
               data ? "Data" : "Instruction",
               field, regs->cp0_epc, field, regs->regs[31]);
-       if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_OOPS, "bus error", regs, 0, current->thread.trap_nr,
                       SIGBUS) == NOTIFY_STOP)
                goto out;
 
@@ -693,15 +690,15 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
 asmlinkage void do_ov(struct pt_regs *regs)
 {
        enum ctx_state prev_state;
-       siginfo_t info;
+       siginfo_t info = {
+               .si_signo = SIGFPE,
+               .si_code = FPE_INTOVF,
+               .si_addr = (void __user *)regs->cp0_epc,
+       };
 
        prev_state = exception_enter();
        die_if_kernel("Integer overflow", regs);
 
-       info.si_code = FPE_INTOVF;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_addr = (void __user *) regs->cp0_epc;
        force_sig_info(SIGFPE, &info, current);
        exception_exit(prev_state);
 }
@@ -825,7 +822,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        int sig;
 
        prev_state = exception_enter();
-       if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_FP, "FP exception", regs, 0, current->thread.trap_nr,
                       SIGFPE) == NOTIFY_STOP)
                goto out;
 
@@ -877,15 +874,16 @@ out:
 void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
        const char *str)
 {
-       siginfo_t info;
+       siginfo_t info = { 0 };
        char b[40];
 
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
-       if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+       if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr,
+                        SIGTRAP) == NOTIFY_STOP)
                return;
 #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
 
-       if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs),
+       if (notify_die(DIE_TRAP, str, regs, code, current->thread.trap_nr,
                       SIGTRAP) == NOTIFY_STOP)
                return;
 
@@ -905,7 +903,6 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
                else
                        info.si_code = FPE_INTOVF;
                info.si_signo = SIGFPE;
-               info.si_errno = 0;
                info.si_addr = (void __user *) regs->cp0_epc;
                force_sig_info(SIGFPE, &info, current);
                break;
@@ -947,6 +944,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
                set_fs(KERNEL_DS);
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
        if (get_isa16_mode(regs->cp0_epc)) {
                u16 instr[2];
 
@@ -986,15 +984,27 @@ asmlinkage void do_bp(struct pt_regs *regs)
         * pertain to them.
         */
        switch (bcode) {
+       case BRK_UPROBE:
+               if (notify_die(DIE_UPROBE, "uprobe", regs, bcode,
+                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
+                       goto out;
+               else
+                       break;
+       case BRK_UPROBE_XOL:
+               if (notify_die(DIE_UPROBE_XOL, "uprobe_xol", regs, bcode,
+                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
+                       goto out;
+               else
+                       break;
        case BRK_KPROBE_BP:
                if (notify_die(DIE_BREAK, "debug", regs, bcode,
-                              regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
                        goto out;
                else
                        break;
        case BRK_KPROBE_SSTEPBP:
                if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode,
-                              regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
                        goto out;
                else
                        break;
@@ -1027,6 +1037,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
                set_fs(get_ds());
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
        if (get_isa16_mode(regs->cp0_epc)) {
                if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
                    __get_user(instr[1], (u16 __user *)(epc + 2)))
@@ -1093,8 +1104,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
 no_r2_instr:
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
 
-       if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_RI, "RI Fault", regs, 0, current->thread.trap_nr,
                       SIGILL) == NOTIFY_STOP)
                goto out;
 
@@ -1443,8 +1455,9 @@ asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr)
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
        if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0,
-                      regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP)
+                      current->thread.trap_nr, SIGFPE) == NOTIFY_STOP)
                goto out;
 
        /* Clear MSACSR.Cause before enabling interrupts */
@@ -1522,7 +1535,6 @@ asmlinkage void do_watch(struct pt_regs *regs)
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
-       const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
        enum ctx_state prev_state;
        mm_segment_t old_fs = get_fs();
@@ -1531,19 +1543,8 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
        show_regs(regs);
 
        if (multi_match) {
-               pr_err("Index   : %0x\n", read_c0_index());
-               pr_err("Pagemask: %0x\n", read_c0_pagemask());
-               pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi());
-               pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0());
-               pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1());
-               pr_err("Wired   : %0x\n", read_c0_wired());
-               pr_err("Pagegrain: %0x\n", read_c0_pagegrain());
-               if (cpu_has_htw) {
-                       pr_err("PWField : %0*lx\n", field, read_c0_pwfield());
-                       pr_err("PWSize  : %0*lx\n", field, read_c0_pwsize());
-                       pr_err("PWCtl   : %0x\n", read_c0_pwctl());
-               }
-               pr_err("\n");
+               dump_tlb_regs();
+               pr_info("\n");
                dump_tlb_all();
        }
 
@@ -1650,6 +1651,7 @@ static inline void parity_protection_init(void)
        case CPU_PROAPTIV:
        case CPU_P5600:
        case CPU_QEMU_GENERIC:
+       case CPU_I6400:
                {
 #define ERRCTL_PE      0x80000000
 #define ERRCTL_L2P     0x00800000
@@ -1854,12 +1856,14 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs)
 {
        char str[100];
 
+       nmi_enter();
        raw_notifier_call_chain(&nmi_chain, 0, regs);
        bust_spinlocks(1);
        snprintf(str, 100, "CPU%d NMI taken, CP0_EPC=%lx\n",
                 smp_processor_id(), regs->cp0_epc);
        regs->cp0_epc = read_c0_errorepc();
        die(str, regs);
+       nmi_exit();
 }
 
 #define VECTORSPACING 0x100    /* for EI/VI mode */
@@ -2142,10 +2146,10 @@ void per_cpu_trap_init(bool is_boot_cpu)
        BUG_ON(current->mm);
        enter_lazy_tlb(&init_mm, current);
 
-               /* Boot CPU's cache setup in setup_arch(). */
-               if (!is_boot_cpu)
-                       cpu_cache_init();
-               tlb_init();
+       /* Boot CPU's cache setup in setup_arch(). */
+       if (!is_boot_cpu)
+               cpu_cache_init();
+       tlb_init();
        TLBMISS_HANDLER_SETUP();
 }
 
@@ -2197,22 +2201,13 @@ void __init trap_init(void)
 
        check_wait();
 
-#if defined(CONFIG_KGDB)
-       if (kgdb_early_setup)
-               return; /* Already done */
-#endif
-
        if (cpu_has_veic || cpu_has_vint) {
                unsigned long size = 0x200 + VECTORSPACING*64;
                ebase = (unsigned long)
                        __alloc_bootmem(size, 1 << fls(size), 0);
        } else {
-#ifdef CONFIG_KVM_GUEST
-#define KVM_GUEST_KSEG0     0x40000000
-        ebase = KVM_GUEST_KSEG0;
-#else
-        ebase = CKSEG0;
-#endif
+               ebase = CAC_BASE;
+
                if (cpu_has_mips_r2_r6)
                        ebase += (read_c0_ebase() & 0x3ffff000);
        }