aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/relocate_kernel.S
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2005-06-25 14:58:07 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 16:24:51 -0700
commit70765aa4bdb8862a49fcf5b28f3deaf561cf5ae7 (patch)
tree602d7801848e2599f1f3d0d53253e30f85794514 /arch/ppc/kernel/relocate_kernel.S
parent[PATCH] crashdump: x86_64: crashkernel option (diff)
downloadlinux-dev-70765aa4bdb8862a49fcf5b28f3deaf561cf5ae7.tar.xz
linux-dev-70765aa4bdb8862a49fcf5b28f3deaf561cf5ae7.zip
[PATCH] kexec: kexec ppc support
I have tweaked this patch slightly to handle an empty list of pages to relocate passed to relocate_new_kernel. And I have added ppc_md.machine_crash_shutdown. To keep up with the changes in the generic kexec infrastructure. From: Albert Herranz <albert_herranz@yahoo.es> The following patch adds support for kexec on the ppc32 platform. Non-OpenFirmware based platforms are likely to work directly without additional changes on the kernel side. The kexec-tools userland package may need to be slightly updated, though. For OpenFirmware based machines, additional work is still needed on the kernel side before kexec support is ready. Benjamin Herrenschmidt is kindly working on that part. In order for a ppc platform to use the kexec kernel services it must implement some ppc_md hooks. Otherwise, kexec will be explicitly disabled, as suggested by benh. There are 3+1 new ppc_md hooks that a platform supporting kexec may implement. Two of them are mandatory for kexec to work. See include/asm-ppc/machdep.h for details. - machine_kexec_prepare(image) This function is called to make any arrangements to the image before it is loaded. This hook _MUST_ be provided by a platform in order to activate kexec support for that platform. Otherwise, the platform is considered to not support kexec and the kexec_load system call will fail (that makes all existing platforms by default non-kexec'able). - machine_kexec_cleanup(image) This function is called to make any cleanups on image after the loaded image data it is freed. This hook is optional. A platform may or may not provide this hook. - machine_kexec(image) This function is called to perform the _actual_ kexec. This hook _MUST_ be provided by a platform in order to activate kexec support for that platform. If a platform provides machine_kexec_prepare but forgets to provide machine_kexec, a kexec will fall back to a reboot. A ready-to-use machine_kexec_simple() generic function is provided to, hopefully, simplify kexec adoption for embedded platforms. A platform may call this function from its specific machine_kexec hook, like this: void myplatform_kexec(struct kimage *image) { machine_kexec_simple(image); } - machine_shutdown() This function is called to perform any machine specific shutdowns, not already done by drivers. This hook is optional. A platform may or may not provide this hook. An example (trimmed) platform specific module for a platform supporting kexec through the existing machine_kexec_simple follows: /* ... */ #ifdef CONFIG_KEXEC int myplatform_kexec_prepare(struct kimage *image) { /* here, we can place additional preparations */ return 0; /* yes, we support kexec */ } void myplatform_kexec(struct kimage *image) { machine_kexec_simple(image); } #endif /* CONFIG_KEXEC */ /* ... */ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { /* ... */ #ifdef CONFIG_KEXEC ppc_md.machine_kexec_prepare = myplatform_kexec_prepare; ppc_md.machine_kexec = myplatform_kexec; #endif /* CONFIG_KEXEC */ /* ... */ } The kexec ppc kernel support has been heavily tested on the GameCube Linux port, and, as reported in the fastboot mailing list, it has been tested too on a Moto 82xx ppc by Rick Richardson. Signed-off-by: Albert Herranz <albert_herranz@yahoo.es> Signed-off-by: Eric Biederman <ebiederm@xmission.com> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ppc/kernel/relocate_kernel.S')
-rw-r--r--arch/ppc/kernel/relocate_kernel.S123
1 files changed, 123 insertions, 0 deletions
diff --git a/arch/ppc/kernel/relocate_kernel.S b/arch/ppc/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..7ff69c4af920
--- /dev/null
+++ b/arch/ppc/kernel/relocate_kernel.S
@@ -0,0 +1,123 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+#include <asm/kexec.h>
+
+#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
+
+ /*
+ * Must be relocatable PIC code callable as a C function.
+ */
+ .globl relocate_new_kernel
+relocate_new_kernel:
+ /* r3 = page_list */
+ /* r4 = reboot_code_buffer */
+ /* r5 = start_address */
+
+ li r0, 0
+
+ /*
+ * Set Machine Status Register to a known status,
+ * switch the MMU off and jump to 1: in a single step.
+ */
+
+ mr r8, r0
+ ori r8, r8, MSR_RI|MSR_ME
+ mtspr SRR1, r8
+ addi r8, r4, 1f - relocate_new_kernel
+ mtspr SRR0, r8
+ sync
+ rfi
+
+1:
+ /* from this point address translation is turned off */
+ /* and interrupts are disabled */
+
+ /* set a new stack at the bottom of our page... */
+ /* (not really needed now) */
+ addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+ stw r0, 0(r1)
+
+ /* Do the copies */
+ li r6, 0 /* checksum */
+ mr r0, r3
+ b 1f
+
+0: /* top, read another word for the indirection page */
+ lwzu r0, 4(r3)
+
+1:
+ /* is it a destination page? (r8) */
+ rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+ beq 2f
+
+ rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+ b 0b
+
+2: /* is it an indirection page? (r3) */
+ rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+ beq 2f
+
+ rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+ subi r3, r3, 4
+ b 0b
+
+2: /* are we done? */
+ rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+ beq 2f
+ b 3f
+
+2: /* is it a source page? (r9) */
+ rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+ beq 0b
+
+ rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+ li r7, PAGE_SIZE / 4
+ mtctr r7
+ subi r9, r9, 4
+ subi r8, r8, 4
+9:
+ lwzu r0, 4(r9) /* do the copy */
+ xor r6, r6, r0
+ stwu r0, 4(r8)
+ dcbst 0, r8
+ sync
+ icbi 0, r8
+ bdnz 9b
+
+ addi r9, r9, 4
+ addi r8, r8, 4
+ b 0b
+
+3:
+
+ /* To be certain of avoiding problems with self-modifying code
+ * execute a serializing instruction here.
+ */
+ isync
+ sync
+
+ /* jump to the entry point, usually the setup routine */
+ mtlr r5
+ blrl
+
+1: b 1b
+
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long relocate_new_kernel_end - relocate_new_kernel
+