dump_stack: consolidate dump_stack() implementations and unify their behaviors
[linux-3.10.git] / arch / parisc / kernel / traps.c
index 15914f0..e64cf5f 100644 (file)
  * state in 'asm.s'.
  */
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/timer.h>
+#include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/console.h>
-#include <linux/kallsyms.h>
+#include <linux/bug.h>
 
 #include <asm/assembly.h>
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/unaligned.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <asm/smp.h>
 #include <asm/pdc.h>
 #include <asm/pdc_chassis.h>
 #include <asm/unwind.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 
 #include "../math-emu/math-emu.h"      /* for handle_fpe() */
 
 DEFINE_SPINLOCK(pa_dbit_lock);
 #endif
 
-int printbinary(char *buf, unsigned long x, int nbits)
+static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
+       struct pt_regs *regs);
+
+static int printbinary(char *buf, unsigned long x, int nbits)
 {
        unsigned long mask = 1UL << (nbits - 1);
        while (mask != 0) {
@@ -61,62 +64,47 @@ int printbinary(char *buf, unsigned long x, int nbits)
        return nbits;
 }
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define RFMT "%016lx"
 #else
 #define RFMT "%08lx"
 #endif
+#define FFMT "%016llx" /* fpregs are 64-bit always */
 
-void show_regs(struct pt_regs *regs)
+#define PRINTREGS(lvl,r,f,fmt,x)       \
+       printk("%s%s%02d-%02d  " fmt " " fmt " " fmt " " fmt "\n",      \
+               lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1],             \
+               (r)[(x)+2], (r)[(x)+3])
+
+static void print_gr(char *level, struct pt_regs *regs)
 {
        int i;
-       char buf[128], *p;
-       char *level;
-       unsigned long cr30;
-       unsigned long cr31;
-       /* carlos says that gcc understands better memory in a struct,
-        * and it makes our life easier with fpregs -- T-Bone */
-       struct { u32 sw[2]; } s;
-       
-       level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
-
-       printk("%s\n", level); /* don't want to have that pretty register dump messed up */
+       char buf[64];
 
+       printk("%s\n", level);
        printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
        printbinary(buf, regs->gr[0], 32);
        printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
-       for (i = 0; i < 32; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
-               for (j = 0; j < 4; j++) {
-                       p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
-               }
-               printk("%s\n", buf);
-       }
+       for (i = 0; i < 32; i += 4)
+               PRINTREGS(level, regs->gr, "r", RFMT, i);
+}
 
-       for (i = 0; i < 8; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
-               for (j = 0; j < 4; j++) {
-                       p += sprintf(p, " " RFMT, regs->sr[i + j]);
-               }
-               printk("%s\n", buf);
-       }
+static void print_fr(char *level, struct pt_regs *regs)
+{
+       int i;
+       char buf[64];
+       struct { u32 sw[2]; } s;
 
        /* FR are 64bit everywhere. Need to use asm to get the content
         * of fpsr/fper1, and we assume that we won't have a FP Identify
         * in our way, otherwise we're screwed.
         * The fldd is used to restore the T-bit if there was one, as the
         * store clears it anyway.
-        * BTW, PA2.0 book says "thou shall not use fstw on FPSR/FPERs". */ 
-       __asm__ (
-               "fstd %%fr0,0(%1)       \n\t"
-               "fldd 0(%1),%%fr0       \n\t"
-               : "=m" (s) : "r" (&s) : "%r0"
-               );
+        * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */
+       asm volatile ("fstd %%fr0,0(%1) \n\t"
+                     "fldd 0(%1),%%fr0 \n\t"
+                     : "=m" (s) : "r" (&s) : "r0");
 
        printk("%s\n", level);
        printk("%s      VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);
@@ -125,14 +113,26 @@ void show_regs(struct pt_regs *regs)
        printk("%sFPER1: %08x\n", level, s.sw[1]);
 
        /* here we'll print fr0 again, tho it'll be meaningless */
-       for (i = 0; i < 32; i += 4) {
-               int j;
-               p = buf;
-               p += sprintf(p, "%sfr%02d-%02d ", level, i, i + 3);
-               for (j = 0; j < 4; j++)
-                       p += sprintf(p, " %016llx", (i+j) == 0 ? 0 : regs->fr[i+j]);
-               printk("%s\n", buf);
-       }
+       for (i = 0; i < 32; i += 4)
+               PRINTREGS(level, regs->fr, "fr", FFMT, i);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       int i, user;
+       char *level;
+       unsigned long cr30, cr31;
+
+       user = user_mode(regs);
+       level = user ? KERN_DEBUG : KERN_CRIT;
+
+       print_gr(level, regs);
+
+       for (i = 0; i < 8; i += 4)
+               PRINTREGS(level, regs->sr, "sr", RFMT, i);
+
+       if (user)
+               print_fr(level, regs);
 
        cr30 = mfctl(30);
        cr31 = mfctl(31);
@@ -144,71 +144,83 @@ void show_regs(struct pt_regs *regs)
        printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",
               level, current_thread_info()->cpu, cr30, cr31);
        printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
-       printk(level);
-       print_symbol(" IAOQ[0]: %s\n", regs->iaoq[0]);
-       printk(level);
-       print_symbol(" IAOQ[1]: %s\n", regs->iaoq[1]);
-       printk(level);
-       print_symbol(" RP(r2): %s\n", regs->gr[2]);
-}
 
+       if (user) {
+               printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]);
+               printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]);
+               printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]);
+       } else {
+               printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]);
+               printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
+               printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
 
-void dump_stack(void)
-{
-       show_stack(NULL, NULL);
+               parisc_show_stack(current, NULL, regs);
+       }
 }
 
-EXPORT_SYMBOL(dump_stack);
-
 static void do_show_stack(struct unwind_frame_info *info)
 {
        int i = 1;
 
-       printk("Backtrace:\n");
+       printk(KERN_CRIT "Backtrace:\n");
        while (i <= 16) {
                if (unwind_once(info) < 0 || info->ip == 0)
                        break;
 
                if (__kernel_text_address(info->ip)) {
-                       printk(" [<" RFMT ">] ", info->ip);
-#ifdef CONFIG_KALLSYMS
-                       print_symbol("%s\n", info->ip);
-#else
-                       if ((i & 0x03) == 0)
-                               printk("\n");
-#endif
+                       printk(KERN_CRIT " [<" RFMT ">] %pS\n",
+                               info->ip, (void *) info->ip);
                        i++;
                }
        }
-       printk("\n");
+       printk(KERN_CRIT "\n");
 }
 
-void show_stack(struct task_struct *task, unsigned long *s)
+static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
+       struct pt_regs *regs)
 {
        struct unwind_frame_info info;
+       struct task_struct *t;
 
-       if (!task) {
+       t = task ? task : current;
+       if (regs) {
+               unwind_frame_init(&info, t, regs);
+               goto show_stack;
+       }
+
+       if (t == current) {
                unsigned long sp;
-               struct pt_regs *r;
 
 HERE:
                asm volatile ("copy %%r30, %0" : "=r"(sp));
-               r = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
-               if (!r)
-                       return;
-               memset(r, 0, sizeof(struct pt_regs));
-               r->iaoq[0] = (unsigned long)&&HERE;
-               r->gr[2] = (unsigned long)__builtin_return_address(0);
-               r->gr[30] = sp;
-               unwind_frame_init(&info, current, r);
-               kfree(r);
+               {
+                       struct pt_regs r;
+
+                       memset(&r, 0, sizeof(struct pt_regs));
+                       r.iaoq[0] = (unsigned long)&&HERE;
+                       r.gr[2] = (unsigned long)__builtin_return_address(0);
+                       r.gr[30] = sp;
+
+                       unwind_frame_init(&info, current, &r);
+               }
        } else {
-               unwind_frame_init_from_blocked_task(&info, task);
+               unwind_frame_init_from_blocked_task(&info, t);
        }
 
+show_stack:
        do_show_stack(&info);
 }
 
+void show_stack(struct task_struct *t, unsigned long *sp)
+{
+       return parisc_show_stack(t, sp, NULL);
+}
+
+int is_valid_bugaddr(unsigned long iaoq)
+{
+       return 1;
+}
+
 void die_if_kernel(char *str, struct pt_regs *regs, long err)
 {
        if (user_mode(regs)) {
@@ -216,7 +228,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
                        return; /* STFU */
 
                printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",
-                       current->comm, current->pid, str, err, regs->iaoq[0]);
+                       current->comm, task_pid_nr(current), str, err, regs->iaoq[0]);
 #ifdef PRINT_USER_FAULTS
                /* XXX for debugging only */
                show_regs(regs);
@@ -226,16 +238,17 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
 
        oops_in_progress = 1;
 
+       oops_enter();
+
        /* Amuse the user in a SPARC fashion */
-       printk(
-"      _______________________________ \n"
-"     < Your System ate a SPARC! Gah! >\n"
-"      ------------------------------- \n"
-"             \\   ^__^\n"
-"              \\  (xx)\\_______\n"
-"                 (__)\\       )\\/\\\n"
-"                  U  ||----w |\n"
-"                     ||     ||\n");
+       if (err) printk(KERN_CRIT
+                       "      _______________________________ \n"
+                       "     < Your System ate a SPARC! Gah! >\n"
+                       "      ------------------------------- \n"
+                       "             \\   ^__^\n"
+                       "                 (__)\\       )\\/\\\n"
+                       "                  U  ||----w |\n"
+                       "                     ||     ||\n");
        
        /* unlock the pdc lock if necessary */
        pdc_emergency_unlock();
@@ -247,18 +260,32 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        if (!console_drivers)
                pdc_console_restart();
        
-       printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
-               current->comm, current->pid, str, err);
-       show_regs(regs);
+       if (err)
+               printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+                       current->comm, task_pid_nr(current), str, err);
 
        /* Wot's wrong wif bein' racy? */
        if (current->thread.flags & PARISC_KERNEL_DEATH) {
-               printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
+               printk(KERN_CRIT "%s() recursion detected.\n", __func__);
                local_irq_enable();
                while (1);
        }
-
        current->thread.flags |= PARISC_KERNEL_DEATH;
+
+       show_regs(regs);
+       dump_stack();
+       add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
+
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+
+       if (panic_on_oops) {
+               printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+               ssleep(5);
+               panic("Fatal exception");
+       }
+
+       oops_exit();
        do_exit(SIGSEGV);
 }
 
@@ -269,61 +296,45 @@ int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
 
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
-void handle_gdb_break(struct pt_regs *regs, int wot)
+static void handle_gdb_break(struct pt_regs *regs, int wot)
 {
        struct siginfo si;
 
-       si.si_code = wot;
-       si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
        si.si_signo = SIGTRAP;
        si.si_errno = 0;
+       si.si_code = wot;
+       si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
        force_sig_info(SIGTRAP, &si, current);
 }
 
-void handle_break(unsigned iir, struct pt_regs *regs)
+static void handle_break(struct pt_regs *regs)
 {
-       struct siginfo si;
-
-       switch(iir) {
-       case 0x00:
-#ifdef PRINT_USER_FAULTS
-               printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n",
-                      current->pid, current->comm);
-#endif
-               die_if_kernel("Breakpoint", regs, 0);
-#ifdef PRINT_USER_FAULTS
-               show_regs(regs);
-#endif
-               si.si_code = TRAP_BRKPT;
-               si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
-               si.si_signo = SIGTRAP;
-               force_sig_info(SIGTRAP, &si, current);
-               break;
-
-       case GDB_BREAK_INSN:
-               die_if_kernel("Breakpoint", regs, 0);
-               handle_gdb_break(regs, TRAP_BRKPT);
-               break;
+       unsigned iir = regs->iir;
+
+       if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) {
+               /* check if a BUG() or WARN() trapped here.  */
+               enum bug_trap_type tt;
+               tt = report_bug(regs->iaoq[0] & ~3, regs);
+               if (tt == BUG_TRAP_TYPE_WARN) {
+                       regs->iaoq[0] += 4;
+                       regs->iaoq[1] += 4;
+                       return; /* return to next instruction when WARN_ON().  */
+               }
+               die_if_kernel("Unknown kernel breakpoint", regs,
+                       (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
+       }
 
-       default:
 #ifdef PRINT_USER_FAULTS
-               printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
-                      iir, current->pid, current->comm);
+       if (unlikely(iir != GDB_BREAK_INSN)) {
+               printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
+                       iir & 31, (iir>>13) & ((1<<13)-1),
+                       task_pid_nr(current), current->comm);
                show_regs(regs);
-#endif
-               si.si_signo = SIGTRAP;
-               si.si_code = TRAP_BRKPT;
-               si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
-               force_sig_info(SIGTRAP, &si, current);
-               return;
        }
-}
-
+#endif
 
-int handle_toc(void)
-{
-       printk(KERN_CRIT "TOC call.\n");
-       return 0;
+       /* send standard GDB signal */
+       handle_gdb_break(regs, TRAP_BRKPT);
 }
 
 static void default_trap(int code, struct pt_regs *regs)
@@ -332,7 +343,7 @@ static void default_trap(int code, struct pt_regs *regs)
        show_regs(regs);
 }
 
-void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
+void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap;
 
 
 void transfer_pim_to_trap_frame(struct pt_regs *regs)
@@ -476,7 +487,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
        panic(msg);
 }
 
-void handle_interruption(int code, struct pt_regs *regs)
+void notrace handle_interruption(int code, struct pt_regs *regs)
 {
        unsigned long fault_address = 0;
        unsigned long fault_space = 0;
@@ -512,7 +523,7 @@ void handle_interruption(int code, struct pt_regs *regs)
                /* Kill the user process later */
                regs->iaoq[0] = 0 | 3;
                regs->iaoq[1] = regs->iaoq[0] + 4;
-               regs->iasq[0] = regs->iasq[0] = regs->sr[7];
+               regs->iasq[0] = regs->iasq[1] = regs->sr[7];
                regs->gr[0] &= ~PSW_B;
                return;
        }
@@ -550,7 +561,8 @@ void handle_interruption(int code, struct pt_regs *regs)
                /* Low-priority machine check */
                pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
                
-               flush_all_caches();
+               flush_cache_all();
+               flush_tlb_all();
                cpu_lpmc(5, regs);
                return;
 
@@ -568,7 +580,7 @@ void handle_interruption(int code, struct pt_regs *regs)
 
        case  9:
                /* Break instruction trap */
-               handle_break(regs->iir,regs);
+               handle_break(regs);
                return;
        
        case 10:
@@ -615,7 +627,7 @@ void handle_interruption(int code, struct pt_regs *regs)
                
        case 13:
                /* Conditional Trap
-                  The condition succees in an instruction which traps 
+                  The condition succeeds in an instruction which traps
                   on condition  */
                if(user_mode(regs)){
                        si.si_signo = SIGFPE;
@@ -726,6 +738,10 @@ void handle_interruption(int code, struct pt_regs *regs)
                /* Fall Through */
        case 27: 
                /* Data memory protection ID trap */
+               if (code == 27 && !user_mode(regs) &&
+                       fixup_exception(regs))
+                       return;
+
                die_if_kernel("Protection id trap", regs, code);
                si.si_code = SEGV_MAPERR;
                si.si_signo = SIGSEGV;
@@ -746,7 +762,7 @@ void handle_interruption(int code, struct pt_regs *regs)
                if (user_mode(regs)) {
 #ifdef PRINT_USER_FAULTS
                        printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n",
-                           current->pid, current->comm);
+                           task_pid_nr(current), current->comm);
                        show_regs(regs);
 #endif
                        /* SIGBUS, for lack of a better one. */
@@ -771,7 +787,8 @@ void handle_interruption(int code, struct pt_regs *regs)
                else
                        printk(KERN_DEBUG "User Fault (long pointer) (fault %d) ",
                               code);
-               printk("pid=%d command='%s'\n", current->pid, current->comm);
+               printk(KERN_CONT "pid=%d command='%s'\n",
+                      task_pid_nr(current), current->comm);
                show_regs(regs);
 #endif
                si.si_signo = SIGSEGV;
@@ -802,13 +819,14 @@ void handle_interruption(int code, struct pt_regs *regs)
 
 int __init check_ivt(void *iva)
 {
+       extern u32 os_hpmc_size;
+       extern const u32 os_hpmc[];
+
        int i;
        u32 check = 0;
        u32 *ivap;
        u32 *hpmcp;
        u32 length;
-       extern void os_hpmc(void);
-       extern void os_hpmc_end(void);
 
        if (strcmp((char *)iva, "cows can fly"))
                return -1;
@@ -819,8 +837,7 @@ int __init check_ivt(void *iva)
            *ivap++ = 0;
 
        /* Compute Checksum for HPMC handler */
-
-       length = (u32)((unsigned long)os_hpmc_end - (unsigned long)os_hpmc);
+       length = os_hpmc_size;
        ivap[7] = length;
 
        hpmcp = (u32 *)os_hpmc;
@@ -836,7 +853,7 @@ int __init check_ivt(void *iva)
        return 0;
 }
        
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 extern const void fault_vector_11;
 #endif
 extern const void fault_vector_20;
@@ -848,7 +865,7 @@ void __init trap_init(void)
        if (boot_cpu_data.cpu_type >= pcxu)
                iva = (void *) &fault_vector_20;
        else
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                panic("Can't boot 64-bit OS on PA1.1 processor!");
 #else
                iva = (void *) &fault_vector_11;