forked from Minki/linux
3ab8352137
This patch provides an enhancement to kexec/kdump. It implements the following features: - Backup/restore memory used by the original kernel before/after kexec. - Save/restore CPU state before/after kexec. The features of this patch can be used as a general method to call program in physical mode (paging turning off). This can be used to call BIOS code under Linux. kexec-tools needs to be patched to support kexec jump. The patches and the precompiled kexec can be download from the following URL: source: http://khibernation.sourceforge.net/download/release_v10/kexec-tools/kexec-tools-src_git_kh10.tar.bz2 patches: http://khibernation.sourceforge.net/download/release_v10/kexec-tools/kexec-tools-patches_git_kh10.tar.bz2 binary: http://khibernation.sourceforge.net/download/release_v10/kexec-tools/kexec_git_kh10 Usage example of calling some physical mode code and return: 1. Compile and install patched kernel with following options selected: CONFIG_X86_32=y CONFIG_KEXEC=y CONFIG_PM=y CONFIG_KEXEC_JUMP=y 2. Build patched kexec-tool or download the pre-built one. 3. Build some physical mode executable named such as "phy_mode" 4. Boot kernel compiled in step 1. 5. Load physical mode executable with /sbin/kexec. The shell command line can be as follow: /sbin/kexec --load-preserve-context --args-none phy_mode 6. Call physical mode executable with following shell command line: /sbin/kexec -e Implementation point: To support jumping without reserving memory. One shadow backup page (source page) is allocated for each page used by kexeced code image (destination page). When do kexec_load, the image of kexeced code is loaded into source pages, and before executing, the destination pages and the source pages are swapped, so the contents of destination pages are backupped. Before jumping to the kexeced code image and after jumping back to the original kernel, the destination pages and the source pages are swapped too. C ABI (calling convention) is used as communication protocol between kernel and called code. A flag named KEXEC_PRESERVE_CONTEXT for sys_kexec_load is added to indicate that the loaded kernel image is used for jumping back. Now, only the i386 architecture is supported. Signed-off-by: Huang Ying <ying.huang@intel.com> Acked-by: Vivek Goyal <vgoyal@redhat.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: Nigel Cunningham <nigel@nigel.suspend2.net> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
107 lines
2.7 KiB
C
107 lines
2.7 KiB
C
/*
|
|
* machine_kexec.c - handle transition of Linux booting another kernel
|
|
* Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
|
|
*
|
|
* GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
|
|
* LANDISK/sh4 supported by kogiidena
|
|
*
|
|
* This source code is licensed under the GNU General Public License,
|
|
* Version 2. See the file COPYING for more details.
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/kexec.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/reboot.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/mmu_context.h>
|
|
#include <asm/io.h>
|
|
#include <asm/cacheflush.h>
|
|
|
|
typedef NORET_TYPE void (*relocate_new_kernel_t)(
|
|
unsigned long indirection_page,
|
|
unsigned long reboot_code_buffer,
|
|
unsigned long start_address,
|
|
unsigned long vbr_reg) ATTRIB_NORET;
|
|
|
|
extern const unsigned char relocate_new_kernel[];
|
|
extern const unsigned int relocate_new_kernel_size;
|
|
extern void *gdb_vbr_vector;
|
|
|
|
void machine_shutdown(void)
|
|
{
|
|
}
|
|
|
|
void machine_crash_shutdown(struct pt_regs *regs)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Do what every setup is needed on image and the
|
|
* reboot code buffer to allow us to avoid allocations
|
|
* later.
|
|
*/
|
|
int machine_kexec_prepare(struct kimage *image)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void machine_kexec_cleanup(struct kimage *image)
|
|
{
|
|
}
|
|
|
|
static void kexec_info(struct kimage *image)
|
|
{
|
|
int i;
|
|
printk("kexec information\n");
|
|
for (i = 0; i < image->nr_segments; i++) {
|
|
printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
|
|
i,
|
|
(unsigned int)image->segment[i].mem,
|
|
(unsigned int)image->segment[i].mem +
|
|
image->segment[i].memsz,
|
|
(unsigned int)image->segment[i].memsz);
|
|
}
|
|
printk(" start : 0x%08x\n\n", (unsigned int)image->start);
|
|
}
|
|
|
|
/*
|
|
* Do not allocate memory (or fail in any way) in machine_kexec().
|
|
* We are past the point of no return, committed to rebooting now.
|
|
*/
|
|
void machine_kexec(struct kimage *image)
|
|
{
|
|
|
|
unsigned long page_list;
|
|
unsigned long reboot_code_buffer;
|
|
unsigned long vbr_reg;
|
|
relocate_new_kernel_t rnk;
|
|
|
|
#if defined(CONFIG_SH_STANDARD_BIOS)
|
|
vbr_reg = ((unsigned long )gdb_vbr_vector) - 0x100;
|
|
#else
|
|
vbr_reg = 0x80000000; // dummy
|
|
#endif
|
|
/* Interrupts aren't acceptable while we reboot */
|
|
local_irq_disable();
|
|
|
|
page_list = image->head;
|
|
|
|
/* we need both effective and real address here */
|
|
reboot_code_buffer =
|
|
(unsigned long)page_address(image->control_code_page);
|
|
|
|
/* copy our kernel relocation code to the control code page */
|
|
memcpy((void *)reboot_code_buffer, relocate_new_kernel,
|
|
relocate_new_kernel_size);
|
|
|
|
kexec_info(image);
|
|
flush_cache_all();
|
|
|
|
/* now call it */
|
|
rnk = (relocate_new_kernel_t) reboot_code_buffer;
|
|
(*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
|
|
}
|
|
|