[PATCH] powerpc: Reroute interrupts from 0 + offset to PHYSICAL_START + offset
authorMichael Ellerman <michael@ellerman.id.au>
Sun, 4 Dec 2005 07:39:37 +0000 (18:39 +1100)
committerPaul Mackerras <paulus@samba.org>
Mon, 9 Jan 2006 03:52:21 +0000 (14:52 +1100)
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>
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/crash_dump.c [new file with mode: 0644]
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/setup_64.c
include/asm-powerpc/kdump.h [new file with mode: 0644]

index 89714929f444bc93b8eedc9bc3277657cfe78602..5719248d344de37eafd24563ba8f9985f044d636 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_IBMVIO)          += vio.o
 obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)   += smp-tbsync.o
 obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
+obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
new file mode 100644 (file)
index 0000000..63919bc
--- /dev/null
@@ -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");
+}
index 3bf968e740950bf041d65dff2b01c0795e94a153..9aac77ca3167ba9247f1dd218f78d4928f01d5cf 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/kdump.h>
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/mmu.h>
@@ -1335,11 +1336,14 @@ void __init early_init_devtree(void *params)
        of_scan_flat_dt(early_init_dt_scan_memory, NULL);
        lmb_enforce_memory_limit(memory_limit);
        lmb_analyze();
-       lmb_reserve(0, __pa(klimit));
 
        DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
 
        /* Reserve LMB regions used by kernel, initrd, dt, etc... */
+       lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+#ifdef CONFIG_CRASH_DUMP
+       lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+#endif
        early_reserve_mem();
 
        DBG("Scanning CPUs ...\n");
index 6509dd7c2f8f83ae368ceb75cf025d0b774816e6..e67120e34652ca2ca8d163078e54d78871f49437 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <asm/io.h>
+#include <asm/kdump.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
@@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr)
        }
        ppc_md = **mach;
 
+#ifdef CONFIG_CRASH_DUMP
+       kdump_setup();
+#endif
+
        DBG("Found, Initializing memory management...\n");
 
        /*
diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h
new file mode 100644 (file)
index 0000000..a87aed0
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _PPC64_KDUMP_H
+#define _PPC64_KDUMP_H
+
+/* How many bytes to reserve at zero for kdump. The reserve limit should
+ * be greater or equal to the trampoline's end address. */
+#define KDUMP_RESERVE_LIMIT    0x8000
+
+#define KDUMP_TRAMPOLINE_START 0x0100
+#define KDUMP_TRAMPOLINE_END   0x3000
+
+extern void kdump_setup(void);
+
+#endif /* __PPC64_KDUMP_H */