aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2005-06-25 17:58:07 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 19:24:51 -0400
commit70765aa4bdb8862a49fcf5b28f3deaf561cf5ae7 (patch)
tree602d7801848e2599f1f3d0d53253e30f85794514 /arch/ppc
parent5f5609df0c943b005847d3b2765d6dd47b624011 (diff)
[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')
-rw-r--r--arch/ppc/Kconfig20
-rw-r--r--arch/ppc/kernel/Makefile1
-rw-r--r--arch/ppc/kernel/machine_kexec.c122
-rw-r--r--arch/ppc/kernel/misc.S2
-rw-r--r--arch/ppc/kernel/relocate_kernel.S123
5 files changed, 267 insertions, 1 deletions
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 979590a9baf9..a7835cd3f51f 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -217,6 +217,26 @@ config MATH_EMULATION
217 here. Saying Y here will not hurt performance (on any machine) but 217 here. Saying Y here will not hurt performance (on any machine) but
218 will increase the size of the kernel. 218 will increase the size of the kernel.
219 219
220config KEXEC
221 bool "kexec system call (EXPERIMENTAL)"
222 depends on EXPERIMENTAL
223 help
224 kexec is a system call that implements the ability to shutdown your
225 current kernel, and to start another kernel. It is like a reboot
226 but it is indepedent of the system firmware. And like a reboot
227 you can start any kernel with it, not just Linux.
228
229 The name comes from the similiarity to the exec system call.
230
231 It is an ongoing process to be certain the hardware in a machine
232 is properly shutdown, so do not be surprised if this code does not
233 initially work for you. It may help to enable device hotplugging
234 support. As of this writing the exact hardware interface is
235 strongly in flux, so no good recommendation can be made.
236
237 In the GameCube implementation, kexec allows you to load and
238 run DOL files, including kernel and homebrew DOLs.
239
220source "drivers/cpufreq/Kconfig" 240source "drivers/cpufreq/Kconfig"
221 241
222config CPU_FREQ_PMAC 242config CPU_FREQ_PMAC
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 8276c0b551d2..b1457a8a9c0f 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
29ifndef CONFIG_E200 29ifndef CONFIG_E200
30obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o 30obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o
31endif 31endif
32obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
32 33
33ifndef CONFIG_MATH_EMULATION 34ifndef CONFIG_MATH_EMULATION
34obj-$(CONFIG_8xx) += softemu8xx.o 35obj-$(CONFIG_8xx) += softemu8xx.o
diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
new file mode 100644
index 000000000000..435ad9ea0a83
--- /dev/null
+++ b/arch/ppc/kernel/machine_kexec.c
@@ -0,0 +1,122 @@
1/*
2 * machine_kexec.c - handle transition of Linux booting another kernel
3 * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
4 *
5 * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
6 *
7 * This source code is licensed under the GNU General Public License,
8 * Version 2. See the file COPYING for more details.
9 */
10
11#include <linux/mm.h>
12#include <linux/kexec.h>
13#include <linux/delay.h>
14#include <linux/reboot.h>
15#include <asm/pgtable.h>
16#include <asm/pgalloc.h>
17#include <asm/mmu_context.h>
18#include <asm/io.h>
19#include <asm/hw_irq.h>
20#include <asm/cacheflush.h>
21#include <asm/machdep.h>
22
23typedef NORET_TYPE void (*relocate_new_kernel_t)(
24 unsigned long indirection_page, unsigned long reboot_code_buffer,
25 unsigned long start_address) ATTRIB_NORET;
26
27const extern unsigned char relocate_new_kernel[];
28const extern unsigned int relocate_new_kernel_size;
29
30void machine_shutdown(void)
31{
32 if (ppc_md.machine_shutdown) {
33 ppc_md.machine_shutdown();
34 }
35}
36
37void machine_crash_shutdown(void)
38{
39 if (ppc_md.machine_crash_shutdown) {
40 ppc_md.machine_crash_shutdown();
41 }
42}
43
44/*
45 * Do what every setup is needed on image and the
46 * reboot code buffer to allow us to avoid allocations
47 * later.
48 */
49int machine_kexec_prepare(struct kimage *image)
50{
51 if (ppc_md.machine_kexec_prepare) {
52 return ppc_md.machine_kexec_prepare(image);
53 }
54 /*
55 * Fail if platform doesn't provide its own machine_kexec_prepare
56 * implementation.
57 */
58 return -ENOSYS;
59}
60
61void machine_kexec_cleanup(struct kimage *image)
62{
63 if (ppc_md.machine_kexec_cleanup) {
64 ppc_md.machine_kexec_cleanup(image);
65 }
66}
67
68/*
69 * Do not allocate memory (or fail in any way) in machine_kexec().
70 * We are past the point of no return, committed to rebooting now.
71 */
72NORET_TYPE void machine_kexec(struct kimage *image)
73{
74 if (ppc_md.machine_kexec) {
75 ppc_md.machine_kexec(image);
76 } else {
77 /*
78 * Fall back to normal restart if platform doesn't provide
79 * its own kexec function, and user insist to kexec...
80 */
81 machine_restart(NULL);
82 }
83 for(;;);
84}
85
86
87/*
88 * This is a generic machine_kexec function suitable at least for
89 * non-OpenFirmware embedded platforms.
90 * It merely copies the image relocation code to the control page and
91 * jumps to it.
92 * A platform specific function may just call this one.
93 */
94void machine_kexec_simple(struct kimage *image)
95{
96 unsigned long page_list;
97 unsigned long reboot_code_buffer, reboot_code_buffer_phys;
98 relocate_new_kernel_t rnk;
99
100 /* Interrupts aren't acceptable while we reboot */
101 local_irq_disable();
102
103 page_list = image->head;
104
105 /* we need both effective and real address here */
106 reboot_code_buffer =
107 (unsigned long)page_address(image->control_code_page);
108 reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
109
110 /* copy our kernel relocation code to the control code page */
111 memcpy((void *)reboot_code_buffer,
112 relocate_new_kernel, relocate_new_kernel_size);
113
114 flush_icache_range(reboot_code_buffer,
115 reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
116 printk(KERN_INFO "Bye!\n");
117
118 /* now call it */
119 rnk = (relocate_new_kernel_t) reboot_code_buffer;
120 (*rnk)(page_list, reboot_code_buffer_phys, image->start);
121}
122
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index a3132f8e799c..b6a63a49a232 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1444,7 +1444,7 @@ _GLOBAL(sys_call_table)
1444 .long sys_mq_timedreceive /* 265 */ 1444 .long sys_mq_timedreceive /* 265 */
1445 .long sys_mq_notify 1445 .long sys_mq_notify
1446 .long sys_mq_getsetattr 1446 .long sys_mq_getsetattr
1447 .long sys_ni_syscall /* 268 reserved for sys_kexec_load */ 1447 .long sys_kexec_load
1448 .long sys_add_key 1448 .long sys_add_key
1449 .long sys_request_key /* 270 */ 1449 .long sys_request_key /* 270 */
1450 .long sys_keyctl 1450 .long sys_keyctl
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 @@
1/*
2 * relocate_kernel.S - put the kernel image in place to boot
3 * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
4 *
5 * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
6 *
7 * This source code is licensed under the GNU General Public License,
8 * Version 2. See the file COPYING for more details.
9 */
10
11#include <asm/reg.h>
12#include <asm/ppc_asm.h>
13#include <asm/processor.h>
14
15#include <asm/kexec.h>
16
17#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
18
19 /*
20 * Must be relocatable PIC code callable as a C function.
21 */
22 .globl relocate_new_kernel
23relocate_new_kernel:
24 /* r3 = page_list */
25 /* r4 = reboot_code_buffer */
26 /* r5 = start_address */
27
28 li r0, 0
29
30 /*
31 * Set Machine Status Register to a known status,
32 * switch the MMU off and jump to 1: in a single step.
33 */
34
35 mr r8, r0
36 ori r8, r8, MSR_RI|MSR_ME
37 mtspr SRR1, r8
38 addi r8, r4, 1f - relocate_new_kernel
39 mtspr SRR0, r8
40 sync
41 rfi
42
431:
44 /* from this point address translation is turned off */
45 /* and interrupts are disabled */
46
47 /* set a new stack at the bottom of our page... */
48 /* (not really needed now) */
49 addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
50 stw r0, 0(r1)
51
52 /* Do the copies */
53 li r6, 0 /* checksum */
54 mr r0, r3
55 b 1f
56
570: /* top, read another word for the indirection page */
58 lwzu r0, 4(r3)
59
601:
61 /* is it a destination page? (r8) */
62 rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
63 beq 2f
64
65 rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
66 b 0b
67
682: /* is it an indirection page? (r3) */
69 rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
70 beq 2f
71
72 rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
73 subi r3, r3, 4
74 b 0b
75
762: /* are we done? */
77 rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
78 beq 2f
79 b 3f
80
812: /* is it a source page? (r9) */
82 rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
83 beq 0b
84
85 rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
86
87 li r7, PAGE_SIZE / 4
88 mtctr r7
89 subi r9, r9, 4
90 subi r8, r8, 4
919:
92 lwzu r0, 4(r9) /* do the copy */
93 xor r6, r6, r0
94 stwu r0, 4(r8)
95 dcbst 0, r8
96 sync
97 icbi 0, r8
98 bdnz 9b
99
100 addi r9, r9, 4
101 addi r8, r8, 4
102 b 0b
103
1043:
105
106 /* To be certain of avoiding problems with self-modifying code
107 * execute a serializing instruction here.
108 */
109 isync
110 sync
111
112 /* jump to the entry point, usually the setup routine */
113 mtlr r5
114 blrl
115
1161: b 1b
117
118relocate_new_kernel_end:
119
120 .globl relocate_new_kernel_size
121relocate_new_kernel_size:
122 .long relocate_new_kernel_end - relocate_new_kernel
123