]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/traps.c
[PATCH] powerpc: Merge signal.h
[karo-tx-linux.git] / arch / powerpc / kernel / traps.c
index c7afbbba0f3681f3c604bd1efa1f40dd0f6582fe..0578f838760301d2dd7c20c1294ba5459c07e4cd 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  arch/powerpc/kernel/traps.c
- *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
  *  This program is free software; you can redistribute it and/or
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/prctl.h>
 #include <linux/delay.h>
 #include <linux/kprobes.h>
-#include <asm/kdebug.h>
 
+#include <asm/kdebug.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/rtas.h>
+#include <asm/pmc.h>
+#ifdef CONFIG_PPC32
 #include <asm/reg.h>
-#include <asm/xmon.h>
+#endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
-#include <asm/perfmon.h>
+#ifdef CONFIG_PPC64
+#include <asm/firmware.h>
+#include <asm/processor.h>
+#include <asm/systemcfg.h>
+#endif
+
+#ifdef CONFIG_PPC64    /* XXX */
+#define _IO_BASE       pci_io_base
+#endif
 
 #ifdef CONFIG_DEBUGGER
 int (*__debugger)(struct pt_regs *regs);
@@ -137,8 +146,8 @@ int die(const char *str, struct pt_regs *regs, long err)
                printk("POWERMAC ");
                nl = 1;
                break;
-       case PLATFORM_BPA:
-               printk("BPA ");
+       case PLATFORM_CELL:
+               printk("CELL ");
                nl = 1;
                break;
        }
@@ -154,6 +163,10 @@ int die(const char *str, struct pt_regs *regs, long err)
                panic("Fatal exception in interrupt");
 
        if (panic_on_oops) {
+#ifdef CONFIG_PPC64
+               printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+               ssleep(5);
+#endif
                panic("Fatal exception");
        }
        do_exit(err);
@@ -306,7 +319,7 @@ platform_machine_check(struct pt_regs *regs)
 {
 }
 
-void MachineCheckException(struct pt_regs *regs)
+void machine_check_exception(struct pt_regs *regs)
 {
 #ifdef CONFIG_PPC64
        int recover = 0;
@@ -478,7 +491,7 @@ void SMIException(struct pt_regs *regs)
        die("System Management Interrupt", regs, SIGABRT);
 }
 
-void UnknownException(struct pt_regs *regs)
+void unknown_exception(struct pt_regs *regs)
 {
        printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
               regs->nip, regs->msr, regs->trap);
@@ -486,7 +499,7 @@ void UnknownException(struct pt_regs *regs)
        _exception(SIGTRAP, regs, 0, 0);
 }
 
-void InstructionBreakpoint(struct pt_regs *regs)
+void instruction_breakpoint_exception(struct pt_regs *regs)
 {
        if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5,
                                        5, SIGTRAP) == NOTIFY_STOP)
@@ -501,7 +514,7 @@ void RunModeException(struct pt_regs *regs)
        _exception(SIGTRAP, regs, 0, 0);
 }
 
-void SingleStepException(struct pt_regs *regs)
+void __kprobes single_step_exception(struct pt_regs *regs)
 {
        regs->msr &= ~(MSR_SE | MSR_BE);  /* Turn off 'trace' bits */
 
@@ -528,7 +541,40 @@ static void emulate_single_step(struct pt_regs *regs)
        }
 }
 
-/* Illegal instruction emulation support.  Originally written to
+static void parse_fpe(struct pt_regs *regs)
+{
+       int code = 0;
+       unsigned long fpscr;
+
+       flush_fp_to_thread(current);
+
+       fpscr = current->thread.fpscr.val;
+
+       /* Invalid operation */
+       if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
+               code = FPE_FLTINV;
+
+       /* Overflow */
+       else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
+               code = FPE_FLTOVF;
+
+       /* Underflow */
+       else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
+               code = FPE_FLTUND;
+
+       /* Divide by zero */
+       else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
+               code = FPE_FLTDIV;
+
+       /* Inexact result */
+       else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
+               code = FPE_FLTRES;
+
+       _exception(SIGFPE, regs, code, regs->nip);
+}
+
+/*
+ * Illegal instruction emulation support.  Originally written to
  * provide the PVR to user applications using the mfspr rd, PVR.
  * Return non-zero if we can't emulate, or -EFAULT if the associated
  * memory access caused an access fault.  Return zero on success.
@@ -686,7 +732,7 @@ struct bug_entry *find_bug(unsigned long bugaddr)
        return module_find_bug(bugaddr);
 }
 
-int check_bug_trap(struct pt_regs *regs)
+static int check_bug_trap(struct pt_regs *regs)
 {
        struct bug_entry *bug;
        unsigned long addr;
@@ -701,29 +747,19 @@ int check_bug_trap(struct pt_regs *regs)
                return 0;
        if (bug->line & BUG_WARNING_TRAP) {
                /* this is a WARN_ON rather than BUG/BUG_ON */
-#ifdef CONFIG_XMON
-               xmon_printf(KERN_ERR "Badness in %s at %s:%d\n",
-                      bug->function, bug->file,
-                      bug->line & ~BUG_WARNING_TRAP);
-#endif /* CONFIG_XMON */               
-               printk(KERN_ERR "Badness in %s at %s:%d\n",
+               printk(KERN_ERR "Badness in %s at %s:%ld\n",
                       bug->function, bug->file,
                       bug->line & ~BUG_WARNING_TRAP);
                dump_stack();
                return 1;
        }
-#ifdef CONFIG_XMON
-       xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%d!\n",
-              bug->function, bug->file, bug->line);
-       xmon(regs);
-#endif /* CONFIG_XMON */
-       printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n",
+       printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
               bug->function, bug->file, bug->line);
 
        return 0;
 }
 
-void ProgramCheckException(struct pt_regs *regs)
+void __kprobes program_check_exception(struct pt_regs *regs)
 {
        unsigned int reason = get_reason(regs);
        extern int do_mathemu(struct pt_regs *regs);
@@ -744,42 +780,21 @@ void ProgramCheckException(struct pt_regs *regs)
 
        if (reason & REASON_FP) {
                /* IEEE FP exception */
-               int code = 0;
-               u32 fpscr;
-
-               /* We must make sure the FP state is consistent with
-                * our MSR_FP in regs
-                */
-               preempt_disable();
-               if (regs->msr & MSR_FP)
-                       giveup_fpu(current);
-               preempt_enable();
-
-               fpscr = current->thread.fpscr;
-               fpscr &= fpscr << 22;   /* mask summary bits with enables */
-               if (fpscr & FPSCR_VX)
-                       code = FPE_FLTINV;
-               else if (fpscr & FPSCR_OX)
-                       code = FPE_FLTOVF;
-               else if (fpscr & FPSCR_UX)
-                       code = FPE_FLTUND;
-               else if (fpscr & FPSCR_ZX)
-                       code = FPE_FLTDIV;
-               else if (fpscr & FPSCR_XX)
-                       code = FPE_FLTRES;
-               _exception(SIGFPE, regs, code, regs->nip);
+               parse_fpe(regs);
                return;
        }
-
        if (reason & REASON_TRAP) {
                /* trap exception */
+               if (notify_die(DIE_BPT, "breakpoint", regs, 5, 5, SIGTRAP)
+                               == NOTIFY_STOP)
+                       return;
                if (debugger_bpt(regs))
                        return;
                if (check_bug_trap(regs)) {
                        regs->nip += 4;
                        return;
                }
-               _exception(SIGTRAP, regs, TRAP_BRKPT, 0);
+               _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
                return;
        }
 
@@ -802,7 +817,7 @@ void ProgramCheckException(struct pt_regs *regs)
                _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 }
 
-void AlignmentException(struct pt_regs *regs)
+void alignment_exception(struct pt_regs *regs)
 {
        int fixed;
 
@@ -814,7 +829,7 @@ void AlignmentException(struct pt_regs *regs)
                return;
        }
 
-       /* Operand address was bad */   
+       /* Operand address was bad */
        if (fixed == -EFAULT) {
                if (user_mode(regs))
                        _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
@@ -850,6 +865,35 @@ void trace_syscall(struct pt_regs *regs)
               regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted());
 }
 
+void kernel_fp_unavailable_exception(struct pt_regs *regs)
+{
+       printk(KERN_EMERG "Unrecoverable FP Unavailable Exception "
+                         "%lx at %lx\n", regs->trap, regs->nip);
+       die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);
+}
+
+void altivec_unavailable_exception(struct pt_regs *regs)
+{
+#if !defined(CONFIG_ALTIVEC)
+       if (user_mode(regs)) {
+               /* A user program has executed an altivec instruction,
+                  but this kernel doesn't support altivec. */
+               _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+               return;
+       }
+#endif
+       printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
+                       "%lx at %lx\n", regs->trap, regs->nip);
+       die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
+}
+
+#if defined(CONFIG_PPC64) || defined(CONFIG_E500)
+void performance_monitor_exception(struct pt_regs *regs)
+{
+       perf_irq(regs);
+}
+#endif
+
 #ifdef CONFIG_8xx
 void SoftwareEmulation(struct pt_regs *regs)
 {
@@ -910,41 +954,19 @@ void TAUException(struct pt_regs *regs)
 }
 #endif /* CONFIG_INT_TAU */
 
-void AltivecUnavailException(struct pt_regs *regs)
-{
-       static int kernel_altivec_count;
-
-#ifndef CONFIG_ALTIVEC
-       if (user_mode(regs)) {
-               /* A user program has executed an altivec instruction,
-                  but this kernel doesn't support altivec. */
-               _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
-               return;
-       }
-#endif
-       /* The kernel has executed an altivec instruction without
-          first enabling altivec.  Whinge but let it do it. */
-       if (++kernel_altivec_count < 10)
-               printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n",
-                      current, regs->nip);
-       regs->msr |= MSR_VEC;
-}
-
 #ifdef CONFIG_ALTIVEC
-void AltivecAssistException(struct pt_regs *regs)
+void altivec_assist_exception(struct pt_regs *regs)
 {
        int err;
 
-       preempt_disable();
-       if (regs->msr & MSR_VEC)
-               giveup_altivec(current);
-       preempt_enable();
        if (!user_mode(regs)) {
                printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode"
                       " at %lx\n", regs->nip);
-               die("Kernel Altivec assist exception", regs, SIGILL);
+               die("Kernel VMX/Altivec assist exception", regs, SIGILL);
        }
 
+       flush_altivec_to_thread(current);
+
        err = emulate_altivec(regs);
        if (err == 0) {
                regs->nip += 4;         /* skip emulated instruction */
@@ -966,13 +988,6 @@ void AltivecAssistException(struct pt_regs *regs)
 }
 #endif /* CONFIG_ALTIVEC */
 
-#ifdef CONFIG_E500
-void PerformanceMonitorException(struct pt_regs *regs)
-{
-       perf_irq(regs);
-}
-#endif
-
 #ifdef CONFIG_FSL_BOOKE
 void CacheLockingException(struct pt_regs *regs, unsigned long address,
                           unsigned long error_code)
@@ -1023,6 +1038,19 @@ void SPEFloatingPointException(struct pt_regs *regs)
 }
 #endif
 
+/*
+ * We enter here if we get an unrecoverable exception, that is, one
+ * that happened at a point where the RI (recoverable interrupt) bit
+ * in the MSR is 0.  This indicates that SRR0/1 are live, and that
+ * we therefore lost state by taking this exception.
+ */
+void unrecoverable_exception(struct pt_regs *regs)
+{
+       printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n",
+              regs->trap, regs->nip);
+       die("Unrecoverable exception", regs, SIGABRT);
+}
+
 #ifdef CONFIG_BOOKE_WDT
 /*
  * Default handler for a Watchdog exception,
@@ -1042,6 +1070,17 @@ void WatchdogException(struct pt_regs *regs)
 }
 #endif
 
+/*
+ * We enter here if we discover during exception entry that we are
+ * running in supervisor mode with a userspace value in the stack pointer.
+ */
+void kernel_bad_stack(struct pt_regs *regs)
+{
+       printk(KERN_EMERG "Bad kernel stack pointer %lx at %lx\n",
+              regs->gpr[1], regs->nip);
+       die("Bad kernel stack pointer", regs, SIGABRT);
+}
+
 void __init trap_init(void)
 {
 }