aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorkogiidena <kogiidena@eggplant.ddo.jp>2006-01-17 01:14:10 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-17 02:15:27 -0500
commit9d44190eae97ad4c9ce30f1084e1b0dabd646df5 (patch)
treed4801a1f62ea7493b34c306a4ee685e0c4fa5f53 /arch
parent0d831770b154a057562236e8cf50905c8f1ae1b0 (diff)
[PATCH] sh: kexec() support
This adds kexec() support for SH. Signed-off-by: kogiidena <kogiidena@eggplant.ddo.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org> Cc: <fastboot@lists.osdl.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/kernel/Makefile4
-rw-r--r--arch/sh/kernel/machine_kexec.c112
-rw-r--r--arch/sh/kernel/process.c10
-rw-r--r--arch/sh/kernel/relocate_kernel.S102
4 files changed, 225 insertions, 3 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 8b819698df14..7a86eeb22655 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -17,6 +17,4 @@ obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o
17obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o 17obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
18obj-$(CONFIG_MODULES) += module.o 18obj-$(CONFIG_MODULES) += module.o
19obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 19obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
20 20obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
21USE_STANDARD_AS_RULE := true
22
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
new file mode 100644
index 000000000000..43546525f28f
--- /dev/null
+++ b/arch/sh/kernel/machine_kexec.c
@@ -0,0 +1,112 @@
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 * LANDISK/sh4 supported by kogiidena
7 *
8 * This source code is licensed under the GNU General Public License,
9 * Version 2. See the file COPYING for more details.
10 */
11
12#include <linux/mm.h>
13#include <linux/kexec.h>
14#include <linux/delay.h>
15#include <linux/reboot.h>
16#include <asm/pgtable.h>
17#include <asm/pgalloc.h>
18#include <asm/mmu_context.h>
19#include <asm/io.h>
20#include <asm/cacheflush.h>
21
22typedef NORET_TYPE void (*relocate_new_kernel_t)(
23 unsigned long indirection_page,
24 unsigned long reboot_code_buffer,
25 unsigned long start_address,
26 unsigned long vbr_reg) ATTRIB_NORET;
27
28const extern unsigned char relocate_new_kernel[];
29const extern unsigned int relocate_new_kernel_size;
30extern void *gdb_vbr_vector;
31
32/*
33 * Provide a dummy crash_notes definition while crash dump arrives to ppc.
34 * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
35 */
36void *crash_notes = NULL;
37
38void machine_shutdown(void)
39{
40}
41
42void machine_crash_shutdown(struct pt_regs *regs)
43{
44}
45
46/*
47 * Do what every setup is needed on image and the
48 * reboot code buffer to allow us to avoid allocations
49 * later.
50 */
51int machine_kexec_prepare(struct kimage *image)
52{
53 return 0;
54}
55
56void machine_kexec_cleanup(struct kimage *image)
57{
58}
59
60static void kexec_info(struct kimage *image)
61{
62 int i;
63 printk("kexec information\n");
64 for (i = 0; i < image->nr_segments; i++) {
65 printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
66 i,
67 (unsigned int)image->segment[i].mem,
68 (unsigned int)image->segment[i].mem + image->segment[i].memsz,
69 (unsigned int)image->segment[i].memsz);
70 }
71 printk(" start : 0x%08x\n\n", (unsigned int)image->start);
72}
73
74
75/*
76 * Do not allocate memory (or fail in any way) in machine_kexec().
77 * We are past the point of no return, committed to rebooting now.
78 */
79NORET_TYPE void machine_kexec(struct kimage *image)
80{
81
82 unsigned long page_list;
83 unsigned long reboot_code_buffer;
84 unsigned long vbr_reg;
85 relocate_new_kernel_t rnk;
86
87#if defined(CONFIG_SH_STANDARD_BIOS)
88 vbr_reg = ((unsigned long )gdb_vbr_vector) - 0x100;
89#else
90 vbr_reg = 0x80000000; // dummy
91#endif
92 /* Interrupts aren't acceptable while we reboot */
93 local_irq_disable();
94
95 page_list = image->head;
96
97 /* we need both effective and real address here */
98 reboot_code_buffer =
99 (unsigned long)page_address(image->control_code_page);
100
101 /* copy our kernel relocation code to the control code page */
102 memcpy((void *)reboot_code_buffer, relocate_new_kernel,
103 relocate_new_kernel_size);
104
105 kexec_info(image);
106 flush_cache_all();
107
108 /* now call it */
109 rnk = (relocate_new_kernel_t) reboot_code_buffer;
110 (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
111}
112
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index aac15e42d03b..a4dc2b532e10 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -71,6 +71,16 @@ void cpu_idle(void)
71 71
72void machine_restart(char * __unused) 72void machine_restart(char * __unused)
73{ 73{
74
75#ifdef CONFIG_KEXEC
76 struct kimage *image;
77 image = xchg(&kexec_image, 0);
78 if (image) {
79 machine_shutdown();
80 machine_kexec(image);
81 }
82#endif
83
74 /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ 84 /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
75 asm volatile("ldc %0, sr\n\t" 85 asm volatile("ldc %0, sr\n\t"
76 "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); 86 "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
diff --git a/arch/sh/kernel/relocate_kernel.S b/arch/sh/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..b0695cffec6e
--- /dev/null
+++ b/arch/sh/kernel/relocate_kernel.S
@@ -0,0 +1,102 @@
1/*
2 * relocate_kernel.S - put the kernel image in place to boot
3 * 2005.9.17 kogiidena@eggplant.ddo.jp
4 *
5 * LANDISK/sh4 is supported. Maybe, SH archtecture works well.
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/config.h>
12#include <linux/linkage.h>
13
14#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
15
16
17 .globl relocate_new_kernel
18relocate_new_kernel:
19 /* r4 = indirection_page */
20 /* r5 = reboot_code_buffer */
21 /* r6 = start_address */
22 /* r7 = vbr_reg */
23
24 mov.l 10f,r8 /* 4096 */
25 mov.l 11f,r9 /* 0xa0000000 */
26
27 /* stack setting */
28 add r8,r5
29 mov r5,r15
30
31 bra 1f
32 mov r4,r0 /* cmd = indirection_page */
330:
34 mov.l @r4+,r0 /* cmd = *ind++ */
35
361: /* addr = (cmd | 0xa0000000) & 0xfffffff0 */
37 mov r0,r2
38 or r9,r2
39 mov #-16,r1
40 and r1,r2
41
42 /* if(cmd & IND_DESTINATION) dst = addr */
43 tst #1,r0
44 bt 2f
45 bra 0b
46 mov r2,r5
47
482: /* else if(cmd & IND_INDIRECTION) ind = addr */
49 tst #2,r0
50 bt 3f
51 bra 0b
52 mov r2,r4
53
543: /* else if(cmd & IND_DONE) goto 6 */
55 tst #4,r0
56 bt 4f
57 bra 6f
58 nop
59
604: /* else if(cmd & IND_SOURCE) memcpy(dst,addr,PAGE_SIZE) */
61 tst #8,r0
62 bt 0b
63
64 mov r8,r3
65 shlr2 r3
66 shlr2 r3
675:
68 dt r3
69 mov.l @r2+,r1 /* 16n+0 */
70 mov.l r1,@r5
71 add #4,r5
72 mov.l @r2+,r1 /* 16n+4 */
73 mov.l r1,@r5
74 add #4,r5
75 mov.l @r2+,r1 /* 16n+8 */
76 mov.l r1,@r5
77 add #4,r5
78 mov.l @r2+,r1 /* 16n+12 */
79 mov.l r1,@r5
80 add #4,r5
81 bf 5b
82
83 bra 0b
84 nop
856:
86#ifdef CONFIG_SH_STANDARD_BIOS
87 ldc r7, vbr
88#endif
89 jmp @r6
90 nop
91
92 .align 2
9310:
94 .long PAGE_SIZE
9511:
96 .long 0xa0000000
97
98relocate_new_kernel_end:
99
100 .globl relocate_new_kernel_size
101relocate_new_kernel_size:
102 .long relocate_new_kernel_end - relocate_new_kernel