patch-2.4.19 linux-2.4.19/arch/ppc64/kernel/traps.c

Next file: linux-2.4.19/arch/ppc64/kernel/udbg.c
Previous file: linux-2.4.19/arch/ppc64/kernel/time.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/arch/ppc64/kernel/traps.c linux-2.4.19/arch/ppc64/kernel/traps.c
@@ -0,0 +1,309 @@
+/*
+ *  linux/arch/ppc/kernel/traps.c
+ *
+ *  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)
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/ppcdebug.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+/* This is true if we are using the firmware NMI handler (typically LPAR) */
+extern int fwnmi_active;
+
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *regs);
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern int xmon_dabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
+
+#ifdef CONFIG_XMON
+void (*debugger)(struct pt_regs *regs) = xmon;
+int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
+int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
+int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
+int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#ifdef CONFIG_KGDB
+void (*debugger)(struct pt_regs *regs);
+int (*debugger_bpt)(struct pt_regs *regs);
+int (*debugger_sstep)(struct pt_regs *regs);
+int (*debugger_iabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs);
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif
+#endif
+/*
+ * Trap & Exception support
+ */
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+	if (!user_mode(regs))
+	{
+		show_regs(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		debugger(regs);
+#endif
+#if defined(CONFIG_KDB)
+		kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs);
+#endif
+		print_backtrace((unsigned long *)regs->gpr[1]);
+		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+#if defined(CONFIG_PPCDBG) && (defined(CONFIG_XMON) || defined(CONFIG_KGDB))
+	/* Allow us to catch SIGILLs for 64-bit app/glibc debugging. -Peter */
+	} else if (signr == SIGILL) {
+		ifppcdebug(PPCDBG_SIGNALXMON)
+			debugger(regs);
+#endif
+	}
+	force_sig(signr, current);
+}
+
+/* Get the error information for errors coming through the
+ * FWNMI vectors.  The pt_regs' r3 will be updated to reflect
+ * the actual r3 if possible, and a ptr to the error log entry
+ * will be returned if found.
+ */
+static struct rtas_error_log *FWNMI_get_errinfo(struct pt_regs *regs)
+{
+	unsigned long errdata = regs->gpr[3];
+	struct rtas_error_log *errhdr = NULL;
+	unsigned long *savep;
+
+	if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
+	    (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
+		savep = __va(errdata);
+		regs->gpr[3] = savep[0];	/* restore original r3 */
+		errhdr = (struct rtas_error_log *)(savep + 1);
+	} else {
+		printk("FWNMI: corrupt r3\n");
+	}
+	return errhdr;
+}
+
+/* Call this when done with the data returned by FWNMI_get_errinfo.
+ * It will release the saved data area for other CPUs in the
+ * partition to receive FWNMI errors.
+ */
+static void FWNMI_release_errinfo(void)
+{
+	unsigned long ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
+	if (ret != 0)
+		printk("FWNMI: nmi-interlock failed: %ld\n", ret);
+}
+
+void
+SystemResetException(struct pt_regs *regs)
+{
+	char *msg = "System Reset in kernel mode.\n";
+	udbg_printf(msg); printk(msg);
+	if (fwnmi_active) {
+		unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
+		struct rtas_error_log *errlog;
+
+		msg = "FWNMI is active with save area at %016lx\n";
+		udbg_printf(msg, r3); printk(msg, r3);
+		errlog = FWNMI_get_errinfo(regs);
+	}
+#if defined(CONFIG_XMON)
+	xmon(regs);
+	udbg_printf("leaving xmon...\n");
+#endif
+	for(;;);
+}
+
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	if (fwnmi_active) {
+		struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
+		if (errhdr) {
+			/* ToDo: attempt to recover from some errors here */
+		}
+		FWNMI_release_errinfo();
+	}
+	if ( !user_mode(regs) )
+	{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		if (debugger_fault_handler) {
+			debugger_fault_handler(regs);
+			return;
+		}
+#endif
+#ifdef CONFIG_KDB
+		if (kdb(KDB_REASON_FAULT, 0, regs))
+			return;
+#endif
+		printk("Machine check in kernel mode.\n");
+		printk("Caused by (from SRR1=%lx): ", regs->msr);
+		show_regs(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		debugger(regs);
+#endif
+#ifdef CONFIG_KDB
+		if (kdb(KDB_REASON_FAULT, 0, regs))
+			return ;
+#endif
+		print_backtrace((unsigned long *)regs->gpr[1]);
+		panic("machine check");
+	}
+	_exception(SIGSEGV, regs);	
+}
+
+void
+SMIException(struct pt_regs *regs)
+{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	{
+		debugger(regs);
+		return;
+	}
+#endif
+#ifdef CONFIG_KDB
+	{
+		kdb(KDB_REASON_OOPS, 0, regs);
+		return;
+	}
+#endif
+	show_regs(regs);
+	print_backtrace((unsigned long *)regs->gpr[1]);
+	panic("System Management Interrupt");
+}
+
+void
+UnknownException(struct pt_regs *regs)
+{
+	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
+	_exception(SIGTRAP, regs);	
+}
+
+void
+InstructionBreakpointException(struct pt_regs *regs)
+{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	if (debugger_iabr_match(regs))
+		return;
+#endif
+#ifdef CONFIG_KDB
+	if (kdb(KDB_REASON_BREAK, 0, regs))
+		return ;
+#endif
+	_exception(SIGTRAP, regs);
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+	if (regs->msr & 0x100000) {
+		/* IEEE FP exception */
+		_exception(SIGFPE, regs);
+	} else if (regs->msr & 0x20000) {
+		/* trap exception */
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+		if (debugger_bpt(regs))
+			return;
+#endif
+#ifdef CONFIG_KDB
+		if (kdb(KDB_REASON_BREAK, 0, regs))
+			return;
+#endif
+		_exception(SIGTRAP, regs);
+	} else {
+		_exception(SIGILL, regs);
+	}
+}
+
+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
+#ifdef CONFIG_KDB
+	if (kdb(KDB_REASON_DEBUG, 0, regs))
+		return;
+#endif
+	_exception(SIGTRAP, regs);	
+}
+
+/* Dummy handler for Performance Monitor */
+
+void
+PerformanceMonitorException(struct pt_regs *regs)
+{
+	_exception(SIGTRAP, regs);
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+	int fixed;
+
+	fixed = fix_alignment(regs);
+	if (fixed == 1) {
+		ifppcdebug(PPCDBG_ALIGNFIXUP)
+			if (!user_mode(regs))
+				PPCDBG(PPCDBG_ALIGNFIXUP, "fix alignment at %lx\n", regs->nip);
+		regs->nip += 4;	/* skip over emulated instruction */
+		return;
+	}
+	if (fixed == -EFAULT) {
+		/* fixed == -EFAULT means the operand address was bad */
+		if (user_mode(regs))
+			force_sig(SIGSEGV, current);
+		else
+			bad_page_fault(regs, regs->dar);
+		return;
+	}
+	_exception(SIGBUS, regs);	
+}
+
+void __init trap_init(void)
+{
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)