diff options
author | kogiidena <kogiidena@eggplant.ddo.jp> | 2006-01-17 01:14:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-17 02:15:27 -0500 |
commit | 9d44190eae97ad4c9ce30f1084e1b0dabd646df5 (patch) | |
tree | d4801a1f62ea7493b34c306a4ee685e0c4fa5f53 /arch/sh/kernel | |
parent | 0d831770b154a057562236e8cf50905c8f1ae1b0 (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/sh/kernel')
-rw-r--r-- | arch/sh/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/sh/kernel/machine_kexec.c | 112 | ||||
-rw-r--r-- | arch/sh/kernel/process.c | 10 | ||||
-rw-r--r-- | arch/sh/kernel/relocate_kernel.S | 102 |
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 | |||
17 | obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o | 17 | obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o |
18 | obj-$(CONFIG_MODULES) += module.o | 18 | obj-$(CONFIG_MODULES) += module.o |
19 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 19 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
20 | 20 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | |
21 | USE_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 | |||
22 | typedef 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 | |||
28 | const extern unsigned char relocate_new_kernel[]; | ||
29 | const extern unsigned int relocate_new_kernel_size; | ||
30 | extern 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 | */ | ||
36 | void *crash_notes = NULL; | ||
37 | |||
38 | void machine_shutdown(void) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | void 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 | */ | ||
51 | int machine_kexec_prepare(struct kimage *image) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | void machine_kexec_cleanup(struct kimage *image) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | static 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 | */ | ||
79 | NORET_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 | ||
72 | void machine_restart(char * __unused) | 72 | void 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 | ||
18 | relocate_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 */ | ||
33 | 0: | ||
34 | mov.l @r4+,r0 /* cmd = *ind++ */ | ||
35 | |||
36 | 1: /* 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 | |||
48 | 2: /* else if(cmd & IND_INDIRECTION) ind = addr */ | ||
49 | tst #2,r0 | ||
50 | bt 3f | ||
51 | bra 0b | ||
52 | mov r2,r4 | ||
53 | |||
54 | 3: /* else if(cmd & IND_DONE) goto 6 */ | ||
55 | tst #4,r0 | ||
56 | bt 4f | ||
57 | bra 6f | ||
58 | nop | ||
59 | |||
60 | 4: /* 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 | ||
67 | 5: | ||
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 | ||
85 | 6: | ||
86 | #ifdef CONFIG_SH_STANDARD_BIOS | ||
87 | ldc r7, vbr | ||
88 | #endif | ||
89 | jmp @r6 | ||
90 | nop | ||
91 | |||
92 | .align 2 | ||
93 | 10: | ||
94 | .long PAGE_SIZE | ||
95 | 11: | ||
96 | .long 0xa0000000 | ||
97 | |||
98 | relocate_new_kernel_end: | ||
99 | |||
100 | .globl relocate_new_kernel_size | ||
101 | relocate_new_kernel_size: | ||
102 | .long relocate_new_kernel_end - relocate_new_kernel | ||