2 * machine_kexec.c - handle transition of Linux booting another kernel
3 * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
5 * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
6 * LANDISK/sh4 supported by kogiidena
8 * This source code is licensed under the GNU General Public License,
9 * Version 2. See the file COPYING for more details.
12 #include <linux/kexec.h>
13 #include <linux/delay.h>
14 #include <linux/reboot.h>
15 #include <linux/numa.h>
16 #include <linux/ftrace.h>
17 #include <linux/suspend.h>
18 #include <linux/memblock.h>
19 #include <asm/pgtable.h>
20 #include <asm/pgalloc.h>
21 #include <asm/mmu_context.h>
23 #include <asm/cacheflush.h>
24 #include <asm/sh_bios.h>
25 #include <asm/reboot.h>
27 typedef void (*relocate_new_kernel_t
)(unsigned long indirection_page
,
28 unsigned long reboot_code_buffer
,
29 unsigned long start_address
);
31 extern const unsigned char relocate_new_kernel
[];
32 extern const unsigned int relocate_new_kernel_size
;
33 extern void *vbr_base
;
35 void native_machine_crash_shutdown(struct pt_regs
*regs
)
37 /* Nothing to do for UP, but definitely broken for SMP.. */
41 * Do what every setup is needed on image and the
42 * reboot code buffer to allow us to avoid allocations
45 int machine_kexec_prepare(struct kimage
*image
)
50 void machine_kexec_cleanup(struct kimage
*image
)
54 static void kexec_info(struct kimage
*image
)
57 printk("kexec information\n");
58 for (i
= 0; i
< image
->nr_segments
; i
++) {
59 printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
61 (unsigned int)image
->segment
[i
].mem
,
62 (unsigned int)image
->segment
[i
].mem
+
63 image
->segment
[i
].memsz
,
64 (unsigned int)image
->segment
[i
].memsz
);
66 printk(" start : 0x%08x\n\n", (unsigned int)image
->start
);
70 * Do not allocate memory (or fail in any way) in machine_kexec().
71 * We are past the point of no return, committed to rebooting now.
73 void machine_kexec(struct kimage
*image
)
75 unsigned long page_list
;
76 unsigned long reboot_code_buffer
;
77 relocate_new_kernel_t rnk
;
80 int save_ftrace_enabled
;
83 * Nicked from the mips version of machine_kexec():
84 * The generic kexec code builds a page list with physical
85 * addresses. Use phys_to_virt() to convert them to virtual.
87 for (ptr
= &image
->head
; (entry
= *ptr
) && !(entry
& IND_DONE
);
88 ptr
= (entry
& IND_INDIRECTION
) ?
89 phys_to_virt(entry
& PAGE_MASK
) : ptr
+ 1) {
90 if (*ptr
& IND_SOURCE
|| *ptr
& IND_INDIRECTION
||
91 *ptr
& IND_DESTINATION
)
92 *ptr
= (unsigned long) phys_to_virt(*ptr
);
95 #ifdef CONFIG_KEXEC_JUMP
96 if (image
->preserve_context
)
97 save_processor_state();
100 save_ftrace_enabled
= __ftrace_enabled_save();
102 /* Interrupts aren't acceptable while we reboot */
105 page_list
= image
->head
;
107 /* we need both effective and real address here */
109 (unsigned long)page_address(image
->control_code_page
);
111 /* copy our kernel relocation code to the control code page */
112 memcpy((void *)reboot_code_buffer
, relocate_new_kernel
,
113 relocate_new_kernel_size
);
118 sh_bios_vbr_reload();
121 rnk
= (relocate_new_kernel_t
) reboot_code_buffer
;
122 (*rnk
)(page_list
, reboot_code_buffer
,
123 (unsigned long)phys_to_virt(image
->start
));
125 #ifdef CONFIG_KEXEC_JUMP
126 asm volatile("ldc %0, vbr" : : "r" (&vbr_base
) : "memory");
128 if (image
->preserve_context
)
129 restore_processor_state();
131 /* Convert page list back to physical addresses, what a mess. */
132 for (ptr
= &image
->head
; (entry
= *ptr
) && !(entry
& IND_DONE
);
133 ptr
= (*ptr
& IND_INDIRECTION
) ?
134 phys_to_virt(*ptr
& PAGE_MASK
) : ptr
+ 1) {
135 if (*ptr
& IND_SOURCE
|| *ptr
& IND_INDIRECTION
||
136 *ptr
& IND_DESTINATION
)
137 *ptr
= virt_to_phys(*ptr
);
141 __ftrace_enabled_restore(save_ftrace_enabled
);
144 void arch_crash_save_vmcoreinfo(void)
147 VMCOREINFO_SYMBOL(node_data
);
148 VMCOREINFO_LENGTH(node_data
, MAX_NUMNODES
);
151 VMCOREINFO_CONFIG(X2TLB
);
155 void __init
reserve_crashkernel(void)
157 unsigned long long crash_size
, crash_base
;
160 ret
= parse_crashkernel(boot_command_line
, memblock_phys_mem_size(),
161 &crash_size
, &crash_base
);
162 if (ret
== 0 && crash_size
> 0) {
163 crashk_res
.start
= crash_base
;
164 crashk_res
.end
= crash_base
+ crash_size
- 1;
167 if (crashk_res
.end
== crashk_res
.start
)
170 crash_size
= PAGE_ALIGN(resource_size(&crashk_res
));
171 if (!crashk_res
.start
) {
172 unsigned long max
= memblock_end_of_DRAM() - memory_limit
;
173 crashk_res
.start
= __memblock_alloc_base(crash_size
, PAGE_SIZE
, max
);
174 if (!crashk_res
.start
) {
175 pr_err("crashkernel allocation failed\n");
179 ret
= memblock_reserve(crashk_res
.start
, crash_size
);
180 if (unlikely(ret
< 0)) {
181 pr_err("crashkernel reservation failed - "
182 "memory is in use\n");
187 crashk_res
.end
= crashk_res
.start
+ crash_size
- 1;
190 * Crash kernel trumps memory limit
192 if ((memblock_end_of_DRAM() - memory_limit
) <= crashk_res
.end
) {
194 pr_info("Disabled memory limit for crashkernel\n");
197 pr_info("Reserving %ldMB of memory at 0x%08lx "
198 "for crashkernel (System RAM: %ldMB)\n",
199 (unsigned long)(crash_size
>> 20),
200 (unsigned long)(crashk_res
.start
),
201 (unsigned long)(memblock_phys_mem_size() >> 20));
206 crashk_res
.start
= crashk_res
.end
= 0;