aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel')
-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
4 files changed, 247 insertions, 1 deletions
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