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/machine_kexec.c | |
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/machine_kexec.c')
-rw-r--r-- | arch/sh/kernel/machine_kexec.c | 112 |
1 files changed, 112 insertions, 0 deletions
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 | |||