summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/crash_dump.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2005-12-04 18:39:37 +1100
committerPaul Mackerras <paulus@samba.org>2006-01-09 14:52:21 +1100
commit0cc4746cadda16826a1b3214c042a2f75445b71c (patch)
treeec8decc81a3f9fd09454ff208fd3b82cf5bdb730 /arch/powerpc/kernel/crash_dump.c
parent8c4f1f2958ff9d4a6760f3bdd0cfb7d2b9e12093 (diff)
[PATCH] powerpc: Reroute interrupts from 0 + offset to PHYSICAL_START + offset
Regardless of where the kernel's linked we always get interrupts at low addresses. This patch creates a trampoline in the first 3 pages of memory, where interrupts land, and patches those addresses to jump into the real kernel code at PHYSICAL_START. We also need to reserve the trampoline code and a bit more in prom.c Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/crash_dump.c')
-rw-r--r--arch/powerpc/kernel/crash_dump.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
new file mode 100644
index 000000000000..63919bcfc9fe
--- /dev/null
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -0,0 +1,53 @@
+/*
+ * Routines for doing kexec-based kdump.
+ *
+ * Copyright (C) 2005, IBM Corp.
+ *
+ * Created by: Michael Ellerman
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#undef DEBUG
+
+#include <asm/kdump.h>
+#include <asm/lmb.h>
+#include <asm/firmware.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static void __init create_trampoline(unsigned long addr)
+{
+ /* The maximum range of a single instruction branch, is the current
+ * instruction's address + (32 MB - 4) bytes. For the trampoline we
+ * need to branch to current address + 32 MB. So we insert a nop at
+ * the trampoline address, then the next instruction (+ 4 bytes)
+ * does a branch to (32 MB - 4). The net effect is that when we
+ * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
+ * two instructions it doesn't require any registers.
+ */
+ create_instruction(addr, 0x60000000); /* nop */
+ create_branch(addr + 4, addr + PHYSICAL_START, 0);
+}
+
+void __init kdump_setup(void)
+{
+ unsigned long i;
+
+ DBG(" -> kdump_setup()\n");
+
+ for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
+ create_trampoline(i);
+ }
+
+ create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
+ create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
+
+ DBG(" <- kdump_setup()\n");
+}