summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/traps.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
commit545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch)
treee9ce4bc598d06374bda906f18365984bf22a526a /arch/ppc/kernel/traps.c
parent4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff)
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'arch/ppc/kernel/traps.c')
-rw-r--r--arch/ppc/kernel/traps.c109
1 files changed, 89 insertions, 20 deletions
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 84ce1c5ca..edfcb4d63 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -1,9 +1,15 @@
/*
* linux/arch/ppc/kernel/traps.c
*
- * Copyright (C) 1995 Gary Thomas
- * Adapted for PowerPC by Gary Thomas
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
*/
/*
@@ -24,9 +30,21 @@
#include <linux/config.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/processor.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern void xmon(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
/*
* Trap & Exception support
@@ -43,40 +61,53 @@ _exception(int signr, struct pt_regs *regs)
if (!user_mode(regs))
{
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
}
+void
MachineCheckException(struct pt_regs *regs)
{
if ( !user_mode(regs) )
{
+#ifdef CONFIG_XMON
+ if (xmon_fault_handler) {
+ xmon_fault_handler(regs);
+ return;
+ }
+#endif
printk("Machine check in kernel mode.\n");
printk("Caused by (from msr): ");
- printk("regs %08x ",regs);
+ printk("regs %p ",regs);
switch( regs->msr & 0x0000F000)
{
case (1<<12) :
printk("Machine check signal - probably due to mm fault\n"
"with mmu off\n");
- break;
+ break;
case (1<<13) :
printk("Transfer error ack signal\n");
- break;
+ break;
case (1<<14) :
printk("Data parity signal\n");
- break;
+ break;
case (1<<15) :
printk("Address parity signal\n");
- break;
+ break;
default:
printk("Unknown values in msr\n");
}
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("");
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("machine check");
}
_exception(SIGSEGV, regs);
}
@@ -105,33 +136,71 @@ RunModeException(struct pt_regs *regs)
_exception(SIGTRAP, regs);
}
+void
ProgramCheckException(struct pt_regs *regs)
{
- if (current->flags & PF_PTRACED)
+ if (regs->msr & 0x100000) {
+ /* IEEE FP exception */
+ _exception(SIGFPE, regs);
+ } else if (regs->msr & 0x20000) {
+ /* trap exception */
+#ifdef CONFIG_XMON
+ if (xmon_bpt(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
- else
+ } else {
_exception(SIGILL, regs);
+ }
}
+void
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+#ifdef CONFIG_XMON
+ if (xmon_sstep(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
}
+void
AlignmentException(struct pt_regs *regs)
{
+ int fixed;
+
+ if (last_task_used_math == current)
+ giveup_fpu();
+ fixed = fix_alignment(regs);
+ if (fixed == 1) {
+ regs->nip += 4; /* skip over emulated instruction */
+ return;
+ }
+ if (fixed == -EFAULT) {
+ /* fixed == -EFAULT means the operand address was bad */
+ bad_page_fault(regs, regs->dar);
+ return;
+ }
_exception(SIGBUS, regs);
}
+void
+PromException(struct pt_regs *regs, int trap)
+{
+ regs->trap = trap;
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
+ regs->trap, regs->nip, regs->msr);
+ /* probably should turn up the toes here */
+}
+
+void
trace_syscall(struct pt_regs *regs)
{
- static int count;
- printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+ printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n",
current, current->pid, regs->nip, regs->link, regs->gpr[0],
regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
- if (++count == 20)
- {
- count = 0;
- }
}