patch-2.4.21 linux-2.4.21/arch/ppc/kernel/traps.c
Next file: linux-2.4.21/arch/ppc/lib/Makefile
Previous file: linux-2.4.21/arch/ppc/kernel/todc_time.c
Back to the patch index
Back to the overall index
- Lines: 464
- Date:
2003-06-13 07:51:31.000000000 -0700
- Orig file:
linux-2.4.20/arch/ppc/kernel/traps.c
- Orig date:
2001-11-02 17:43:54.000000000 -0800
diff -urN linux-2.4.20/arch/ppc/kernel/traps.c linux-2.4.21/arch/ppc/kernel/traps.c
@@ -1,7 +1,4 @@
/*
- * BK Id: SCCS/s.traps.c 1.22 10/11/01 10:33:09 paulus
- */
-/*
* linux/arch/ppc/kernel/traps.c
*
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -38,6 +35,9 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
extern int fix_alignment(struct pt_regs *);
extern void bad_page_fault(struct pt_regs *, unsigned long, int sig);
@@ -66,6 +66,13 @@
int (*debugger_iabr_match)(struct pt_regs *regs);
int (*debugger_dabr_match)(struct pt_regs *regs);
void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#define debugger(regs) do { } while (0)
+#define debugger_bpt(regs) 0
+#define debugger_sstep(regs) 0
+#define debugger_iabr_match(regs) 0
+#define debugger_dabr_match(regs) 0
+#define debugger_fault_handler ((void (*)(struct pt_regs *))0)
#endif
#endif
@@ -74,15 +81,19 @@
*/
-spinlock_t oops_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
void die(const char * str, struct pt_regs * fp, long err)
{
console_verbose();
- spin_lock_irq(&oops_lock);
+ spin_lock_irq(&die_lock);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ set_backlight_enable(1);
+ set_backlight_level(BACKLIGHT_MAX);
+#endif
printk("Oops: %s, sig: %ld\n", str, err);
show_regs(fp);
- spin_unlock_irq(&oops_lock);
+ spin_unlock_irq(&die_lock);
/* do_exit() should take care of panic'ing from an interrupt
* context so we don't handle it here
*/
@@ -90,54 +101,37 @@
}
void
-_exception(int signr, struct pt_regs *regs)
+_exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
- if (!user_mode(regs))
- {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ siginfo_t info;
+
+ if (!user_mode(regs)) {
debugger(regs);
-#endif
die("Exception in kernel mode", regs, signr);
}
- force_sig(signr, current);
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = (void *) addr;
+ force_sig_info(signr, &info, current);
}
-void
-MachineCheckException(struct pt_regs *regs)
+/*
+ * I/O accesses can cause machine checks on powermacs.
+ * Check if the NIP corresponds to the address of a sync
+ * instruction for which there is an entry in the exception
+ * table.
+ * Note that the 601 only takes a machine check on TEA
+ * (transfer error ack) signal assertion, and does not
+ * set any of the top 16 bits of SRR1.
+ * -- paulus.
+ */
+static inline int check_io_access(struct pt_regs *regs)
{
#ifdef CONFIG_ALL_PPC
unsigned long fixup;
-#endif /* CONFIG_ALL_PPC */
unsigned long msr = regs->msr;
- if (user_mode(regs)) {
- _exception(SIGSEGV, regs);
- return;
- }
-
-#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
- /* the qspan pci read routines can cause machine checks -- Cort */
- bad_page_fault(regs, regs->dar, SIGBUS);
- return;
-#endif
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
- if (debugger_fault_handler) {
- debugger_fault_handler(regs);
- return;
- }
-#endif
-
-#ifdef CONFIG_ALL_PPC
- /*
- * I/O accesses can cause machine checks on powermacs.
- * Check if the NIP corresponds to the address of a sync
- * instruction for which there is an entry in the exception
- * table.
- * Note that the 601 only takes a machine check on TEA
- * (transfer error ack) signal assertion, and does not
- * set of the top 16 bits of SRR1.
- * -- paulus.
- */
if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000)))
&& (fixup = search_exception_table(regs->nip)) != 0) {
/*
@@ -163,18 +157,72 @@
(*nip & 0x100)? "OUT to": "IN from",
regs->gpr[rb] - _IO_BASE, nip);
regs->nip = fixup;
- return;
+ return 1;
}
}
#endif /* CONFIG_ALL_PPC */
+ return 0;
+}
+
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+/* On 4xx, the reason for the machine check or program exception
+ is in the ESR. */
+#define get_reason(regs) mfspr(SPRN_ESR);
+#define REASON_FP 0
+#define REASON_ILLEGAL ESR_PIL
+#define REASON_PRIVILEGED ESR_PPR
+#define REASON_TRAP ESR_PTR
+
+#else
+/* On non-4xx, the reason for the machine check or program
+ exception is in the MSR. */
+#define get_reason(regs) ((regs)->msr)
+#define REASON_FP 0x100000
+#define REASON_ILLEGAL 0x80000
+#define REASON_PRIVILEGED 0x40000
+#define REASON_TRAP 0x20000
+#endif
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long reason = get_reason(regs);
+
+ if (user_mode(regs)) {
+ _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
+ return;
+ }
+
+#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
+ /* the qspan pci read routines can cause machine checks -- Cort */
+ bad_page_fault(regs, regs->dar, SIGBUS);
+ return;
+#endif
+ if (debugger_fault_handler) {
+ debugger_fault_handler(regs);
+ return;
+ }
+ if (check_io_access(regs))
+ return;
+
+#ifdef CONFIG_4xx
+ if (reason & ESR_IMCP) {
+ printk("Instruction");
+ mtspr(SPRN_ESR, reason & ~ESR_IMCP);
+ } else
+ printk("Data");
+ printk(" machine check in kernel mode.\n");
+
+#else /* CONFIG_4xx */
printk("Machine check in kernel mode.\n");
- printk("Caused by (from SRR1=%lx): ", msr);
- switch (msr & 0xF0000) {
+ printk("Caused by (from SRR1=%lx): ", reason);
+ switch (reason & 0x601F0000) {
case 0x80000:
printk("Machine check signal\n");
break;
case 0: /* for 601 */
case 0x40000:
+ case 0x140000: /* 7450 MSS error and TEA */
printk("Transfer error ack signal\n");
break;
case 0x20000:
@@ -183,26 +231,32 @@
case 0x10000:
printk("Address parity error signal\n");
break;
+ case 0x20000000:
+ printk("L1 Data Cache error\n");
+ break;
+ case 0x40000000:
+ printk("L1 Instruction Cache error\n");
+ break;
+ case 0x00100000:
+ printk("L2 data cache parity error\n");
+ break;
default:
printk("Unknown values in msr\n");
}
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+#endif /* CONFIG_4xx */
+
debugger(regs);
-#endif
die("machine check", regs, SIGBUS);
}
void
SMIException(struct pt_regs *regs)
{
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
- {
- debugger(regs);
- return;
- }
-#endif
+ debugger(regs);
+#if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB))
show_regs(regs);
panic("System Management Interrupt");
+#endif
}
void
@@ -210,23 +264,21 @@
{
printk("Bad trap at PC: %lx, SR: %lx, vector=%lx %s\n",
regs->nip, regs->msr, regs->trap, print_tainted());
- _exception(SIGTRAP, regs);
+ _exception(SIGTRAP, regs, 0, 0);
}
void
InstructionBreakpoint(struct pt_regs *regs)
{
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_iabr_match(regs))
return;
-#endif
- _exception(SIGTRAP, regs);
+ _exception(SIGTRAP, regs, TRAP_BRKPT, 0);
}
void
RunModeException(struct pt_regs *regs)
{
- _exception(SIGTRAP, regs);
+ _exception(SIGTRAP, regs, 0, 0);
}
/* Illegal instruction emulation support. Originally written to
@@ -245,16 +297,16 @@
static int
emulate_instruction(struct pt_regs *regs)
{
- uint instword;
- uint rd;
- uint retval;
+ u32 instword;
+ u32 rd;
+ int retval;
- retval = EINVAL;
+ retval = -EINVAL;
if (!user_mode(regs))
return retval;
- if (get_user(instword, (uint *)(regs->nip)))
+ if (get_user(instword, (u32 *)(regs->nip)))
return -EFAULT;
/* Emulate the mfspr rD, PVR.
@@ -263,60 +315,71 @@
rd = (instword >> 21) & 0x1f;
regs->gpr[rd] = mfspr(PVR);
retval = 0;
- }
- if (retval == 0)
regs->nip += 4;
- return(retval);
+ }
+ return retval;
}
void
ProgramCheckException(struct pt_regs *regs)
{
-#if defined(CONFIG_4xx)
- unsigned int esr = mfspr(SPRN_ESR);
+ unsigned int reason = get_reason(regs);
+ extern int do_mathemu(struct pt_regs *regs);
- if (esr & ESR_PTR) {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
- if (debugger_bpt(regs))
- return;
-#endif
- _exception(SIGTRAP, regs);
- } else {
- _exception(SIGILL, regs);
- }
-#else
- if (regs->msr & 0x100000) {
+#ifdef CONFIG_MATH_EMULATION
+ if ((reason & REASON_ILLEGAL) && do_mathemu(regs) == 0)
+ return;
+#endif /* CONFIG_MATH_EMULATION */
+
+ if (reason & REASON_FP) {
/* IEEE FP exception */
- _exception(SIGFPE, regs);
- } else if (regs->msr & 0x20000) {
+ int code = 0;
+ u32 fpscr;
+
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
+ 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);
+ return;
+ }
+
+ if (reason & REASON_TRAP) {
/* trap exception */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_bpt(regs))
return;
-#endif
- _exception(SIGTRAP, regs);
- } else {
+ _exception(SIGTRAP, regs, TRAP_BRKPT, 0);
+ return;
+ }
+
+ if (reason & REASON_PRIVILEGED) {
/* Try to emulate it if we should. */
- int errcode;
- if ((errcode = emulate_instruction(regs))) {
- if (errcode == -EFAULT)
- _exception(SIGBUS, regs);
- else
- _exception(SIGILL, regs);
- }
+ if (emulate_instruction(regs) == 0)
+ return;
+ _exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+ return;
}
-#endif
+
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
}
void
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_sstep(regs))
return;
-#endif
- _exception(SIGTRAP, regs);
+ _exception(SIGTRAP, regs, TRAP_TRACE, 0);
}
void
@@ -332,12 +395,12 @@
if (fixed == -EFAULT) {
/* fixed == -EFAULT means the operand address was bad */
if (user_mode(regs))
- force_sig(SIGSEGV, current);
+ _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
else
bad_page_fault(regs, regs->dar, SIGSEGV);
return;
}
- _exception(SIGBUS, regs);
+ _exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
}
void
@@ -345,9 +408,7 @@
{
printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
current, regs->gpr[1]);
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
debugger(regs);
-#endif
show_regs(regs);
panic("kernel stack overflow");
}
@@ -365,29 +426,29 @@
SoftwareEmulation(struct pt_regs *regs)
{
extern int do_mathemu(struct pt_regs *);
+ extern int Soft_emulate_8xx(struct pt_regs *);
int errcode;
if (!user_mode(regs)) {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
debugger(regs);
-#endif
die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
}
#ifdef CONFIG_MATH_EMULATION
- if ((errcode = do_mathemu(regs))) {
+ errcode = do_mathemu(regs);
#else
- if ((errcode = Soft_emulate_8xx(regs))) {
+ errcode = Soft_emulate_8xx(regs);
#endif
+ if (errcode) {
if (errcode > 0)
- _exception(SIGFPE, regs);
+ _exception(SIGFPE, regs, 0, 0);
else if (errcode == -EFAULT)
- _exception(SIGSEGV, regs);
+ _exception(SIGSEGV, regs, 0, 0);
else
- _exception(SIGILL, regs);
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
}
}
-#endif
+#endif /* CONFIG_8xx */
#if !defined(CONFIG_TAU_INT)
void
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)