summaryrefslogtreecommitdiffstats
path: root/arch/parisc/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/kernel/traps.c')
-rw-r--r--arch/parisc/kernel/traps.c153
1 files changed, 75 insertions, 78 deletions
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 65cd6ca32fe..55bc1471967 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/console.h>
#include <linux/kallsyms.h>
+#include <linux/bug.h>
#include <asm/assembly.h>
#include <asm/system.h>
@@ -39,6 +40,8 @@
#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() */
@@ -49,7 +52,7 @@
DEFINE_SPINLOCK(pa_dbit_lock);
#endif
-int printbinary(char *buf, unsigned long x, int nbits)
+static int printbinary(char *buf, unsigned long x, int nbits)
{
unsigned long mask = 1UL << (nbits - 1);
while (mask != 0) {
@@ -61,7 +64,7 @@ int printbinary(char *buf, unsigned long x, int nbits)
return nbits;
}
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
#define RFMT "%016lx"
#else
#define RFMT "%08lx"
@@ -160,13 +163,13 @@ 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);
+ printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip);
#ifdef CONFIG_KALLSYMS
print_symbol("%s\n", info->ip);
#else
@@ -185,18 +188,19 @@ void show_stack(struct task_struct *task, unsigned long *s)
if (!task) {
unsigned long sp;
- struct pt_regs *r;
HERE:
asm volatile ("copy %%r30, %0" : "=r"(sp));
- r = kzalloc(sizeof(struct pt_regs), GFP_KERNEL);
- if (!r)
- return;
- 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);
}
@@ -204,6 +208,11 @@ HERE:
do_show_stack(&info);
}
+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)) {
@@ -222,15 +231,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
oops_in_progress = 1;
/* 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"
+KERN_CRIT " < Your System ate a SPARC! Gah! >\n"
+KERN_CRIT " ------------------------------- \n"
+KERN_CRIT " \\ ^__^\n"
+KERN_CRIT " \\ (xx)\\_______\n"
+KERN_CRIT " (__)\\ )\\/\\\n"
+KERN_CRIT " U ||----w |\n"
+KERN_CRIT " || ||\n");
/* unlock the pdc lock if necessary */
pdc_emergency_unlock();
@@ -242,9 +251,20 @@ 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);
+ if (err)
+ printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+ current->comm, current->pid, str, err);
+
+ /* Wot's wrong wif bein' racy? */
+ if (current->thread.flags & PARISC_KERNEL_DEATH) {
+ printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
+ local_irq_enable();
+ while (1);
+ }
+ current->thread.flags |= PARISC_KERNEL_DEATH;
+
show_regs(regs);
+ dump_stack();
if (in_interrupt())
panic("Fatal exception in interrupt");
@@ -255,14 +275,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
panic("Fatal exception");
}
- /* Wot's wrong wif bein' racy? */
- if (current->thread.flags & PARISC_KERNEL_DEATH) {
- printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
- local_irq_enable();
- while (1);
- }
-
- current->thread.flags |= PARISC_KERNEL_DEATH;
do_exit(SIGSEGV);
}
@@ -273,61 +285,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);
+ 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),
+ current->pid, 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)
@@ -336,7 +332,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)
@@ -554,7 +550,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;
@@ -572,7 +569,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:
@@ -840,7 +837,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;
@@ -852,7 +849,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;