[PATCH 5/12] powerpc: Reroute interrupts from 0 + offset to PHYSICAL_START + offset

Michael Ellerman michael at ellerman.id.au
Tue Nov 8 00:06:57 EST 2005


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

 arch/powerpc/kernel/Makefile   |    3 +-
 arch/powerpc/kernel/crash.c    |   52 +++++++++++++++++++++++++++++++++++++++++
 arch/powerpc/kernel/prom.c     |    6 +++-
 arch/powerpc/kernel/setup_64.c |    5 +++
 include/asm-powerpc/kdump.h    |   13 ++++++++++
 5 files changed, 77 insertions(+), 2 deletions(-)

Index: kexec/arch/powerpc/kernel/setup_64.c
===================================================================
--- kexec.orig/arch/powerpc/kernel/setup_64.c
+++ kexec/arch/powerpc/kernel/setup_64.c
@@ -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>
@@ -274,6 +275,10 @@ void __init early_setup(unsigned long dt
 	}
 	ppc_md = **mach;
 
+#ifdef CONFIG_CRASH_DUMP
+	kdump_setup();
+#endif
+
 	DBG("Found, Initializing memory management...\n");
 
 	/*
Index: kexec/arch/powerpc/kernel/prom.c
===================================================================
--- kexec.orig/arch/powerpc/kernel/prom.c
+++ kexec/arch/powerpc/kernel/prom.c
@@ -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>
@@ -1354,11 +1355,14 @@ void __init early_init_devtree(void *par
 #ifdef CONFIG_PPC64
 	systemcfg->physicalMemorySize = lmb_phys_mem_size();
 #endif
-	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(__pa(KERNELBASE), __pa(klimit) - __pa(KERNELBASE));
+#ifdef CONFIG_CRASH_DUMP
+	lmb_reserve(0, KDUMP_BACKUP_LIMIT);
+#endif
 	early_reserve_mem();
 
 	DBG("Scanning CPUs ...\n");
Index: kexec/include/asm-powerpc/kdump.h
===================================================================
--- /dev/null
+++ kexec/include/asm-powerpc/kdump.h
@@ -0,0 +1,13 @@
+#ifndef _PPC64_KDUMP_H
+#define _PPC64_KDUMP_H
+
+/* How many bytes to backup from zero for kdump. The backup limit should
+ * be greater or equal to the trampoline's end address. */
+#define KDUMP_BACKUP_LIMIT	0x8000
+
+#define KDUMP_TRAMPOLINE_START	0x0100
+#define KDUMP_TRAMPOLINE_END	0x3000
+
+extern void kdump_setup(void);
+
+#endif /* __PPC64_KDUMP_H */
Index: kexec/arch/powerpc/kernel/Makefile
===================================================================
--- kexec.orig/arch/powerpc/kernel/Makefile
+++ kexec/arch/powerpc/kernel/Makefile
@@ -11,7 +11,7 @@ CFLAGS_btext.o		+= -fPIC
 endif
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
-				   signal_32.o pmc.o
+				   signal_32.o pmc.o crash.o
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o systbl.o
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
@@ -22,6 +22,7 @@ obj-$(CONFIG_RTAS_FLASH)	+= rtas_flash.o
 obj-$(CONFIG_RTAS_PROC)		+= rtas-proc.o
 obj-$(CONFIG_IBMVIO)		+= vio.o
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
+obj-$(CONFIG_CRASH_DUMP)	+= crash.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
Index: kexec/arch/powerpc/kernel/crash.c
===================================================================
--- /dev/null
+++ kexec/arch/powerpc/kernel/crash.c
@@ -0,0 +1,52 @@
+/*
+ * 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
+#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");
+}



More information about the Linuxppc64-dev mailing list