vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc / kernel / traps.c
index 544ea9f..0d7eb74 100644 (file)
@@ -41,6 +41,7 @@
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
+#include <asm/perfmon.h>
 
 #ifdef CONFIG_XMON
 void (*debugger)(struct pt_regs *regs) = xmon;
@@ -71,8 +72,7 @@ void (*debugger_fault_handler)(struct pt_regs *regs);
  * Trap & Exception support
  */
 
-
-spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * fp, long err)
 {
@@ -199,6 +199,15 @@ static inline int check_io_access(struct pt_regs *regs)
 #define clear_single_step(regs)        ((regs)->msr &= ~MSR_SE)
 #endif
 
+/*
+ * This is "fall-back" implementation for configurations
+ * which don't provide platform-specific machine check info
+ */
+void __attribute__ ((weak))
+platform_machine_check(struct pt_regs *regs)
+{
+}
+
 void MachineCheckException(struct pt_regs *regs)
 {
        unsigned long reason = get_mc_reason(regs);
@@ -323,6 +332,12 @@ void MachineCheckException(struct pt_regs *regs)
        }
 #endif /* CONFIG_4xx */
 
+       /*
+        * Optional platform-provided routine to print out
+        * additional info, e.g. bus error registers.
+        */
+       platform_machine_check(regs);
+
        debugger(regs);
        die("machine check", regs, SIGBUS);
 }
@@ -357,7 +372,7 @@ void RunModeException(struct pt_regs *regs)
 
 /* 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
+ * Return non-zero if we can't emulate, or -EFAULT if the associated
  * memory access caused an access fault.  Return zero on success.
  *
  * There are a couple of ways to do this, either "decode" the instruction
@@ -368,16 +383,19 @@ void RunModeException(struct pt_regs *regs)
 #define INST_MFSPR_PVR         0x7c1f42a6
 #define INST_MFSPR_PVR_MASK    0xfc1fffff
 
+#define INST_DCBA              0x7c0005ec
+#define INST_DCBA_MASK         0x7c0007fe
+
+#define INST_MCRXR             0x7c000400
+#define INST_MCRXR_MASK                0x7c0007fe
+
 static int emulate_instruction(struct pt_regs *regs)
 {
        u32 instword;
        u32 rd;
-       int retval;
-
-       retval = -EINVAL;
 
        if (!user_mode(regs))
-               return retval;
+               return -EINVAL;
        CHECK_FULL_REGS(regs);
 
        if (get_user(instword, (u32 __user *)(regs->nip)))
@@ -388,10 +406,24 @@ static int emulate_instruction(struct pt_regs *regs)
        if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
                rd = (instword >> 21) & 0x1f;
                regs->gpr[rd] = mfspr(PVR);
-               retval = 0;
-               regs->nip += 4;
+               return 0;
+       }
+
+       /* Emulating the dcba insn is just a no-op.  */
+       if ((instword & INST_DCBA_MASK) == INST_DCBA)
+               return 0;
+
+       /* Emulate the mcrxr insn.  */
+       if ((instword & INST_MCRXR_MASK) == INST_MCRXR) {
+               int shift = (instword >> 21) & 0x1c;
+               unsigned long msk = 0xf0000000UL >> shift;
+
+               regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk);
+               regs->xer &= ~0xf0000000UL;
+               return 0;
        }
-       return retval;
+
+       return -EINVAL;
 }
 
 /*
@@ -528,22 +560,28 @@ void ProgramCheckException(struct pt_regs *regs)
                return;
        }
 
-       if (reason & REASON_PRIVILEGED) {
-               /* Try to emulate it if we should. */
-               if (emulate_instruction(regs) == 0) {
+       /* Try to emulate it if we should. */
+       if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) {
+               switch (emulate_instruction(regs)) {
+               case 0:
+                       regs->nip += 4;
                        emulate_single_step(regs);
                        return;
+               case -EFAULT:
+                       _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+                       return;
                }
-               _exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
-               return;
        }
 
-       _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+       if (reason & REASON_PRIVILEGED)
+               _exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+       else
+               _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 }
 
 void SingleStepException(struct pt_regs *regs)
 {
-       regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+       regs->msr &= ~(MSR_SE | MSR_BE);  /* Turn off 'trace' bits */
        if (debugger_sstep(regs))
                return;
        _exception(SIGTRAP, regs, TRAP_TRACE, 0);
@@ -624,22 +662,22 @@ void SoftwareEmulation(struct pt_regs *regs)
 }
 #endif /* CONFIG_8xx */
 
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
 
 void DebugException(struct pt_regs *regs, unsigned long debug_status)
 {
-#if 0
-       if (debug_status & DBSR_TIE) {          /* trap instruction*/
-               if (!user_mode(regs) && debugger_bpt(regs))
-                       return;
-               _exception(SIGTRAP, regs, 0, 0);
-
-       }
-#endif
        if (debug_status & DBSR_IC) {   /* instruction completion */
-               if (!user_mode(regs) && debugger_sstep(regs))
-                       return;
-               current->thread.dbcr0 &= ~DBCR0_IC;
+               regs->msr &= ~MSR_DE;
+               if (user_mode(regs)) {
+                       current->thread.dbcr0 &= ~DBCR0_IC;
+               } else {
+                       /* Disable instruction completion */
+                       mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
+                       /* Clear the instruction completion event */
+                       mtspr(SPRN_DBSR, DBSR_IC);
+                       if (debugger_sstep(regs))
+                               return;
+               }
                _exception(SIGTRAP, regs, TRAP_TRACE, 0);
        }
 }
@@ -703,6 +741,11 @@ void AltivecAssistException(struct pt_regs *regs)
 }
 #endif /* CONFIG_ALTIVEC */
 
+void PerformanceMonitorException(struct pt_regs *regs)
+{
+       perf_irq(regs);
+}
+
 #ifdef CONFIG_FSL_BOOKE
 void CacheLockingException(struct pt_regs *regs, unsigned long address,
                           unsigned long error_code)