aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2008-07-25 22:45:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-26 15:00:04 -0400
commit3ab83521378268044a448113c6aa9a9e245f4d2f (patch)
treee9e8496577e4b2e994edf204e9a8ae7c026eec95 /kernel
parent7fccf0326536c1b245b98740d489abb9aab69a12 (diff)
kexec jump
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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kexec.c57
-rw-r--r--kernel/sys.c31
2 files changed, 65 insertions, 23 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 6db42ff8d520..a0d920915b38 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -24,6 +24,8 @@
24#include <linux/utsrelease.h> 24#include <linux/utsrelease.h>
25#include <linux/utsname.h> 25#include <linux/utsname.h>
26#include <linux/numa.h> 26#include <linux/numa.h>
27#include <linux/suspend.h>
28#include <linux/device.h>
27 29
28#include <asm/page.h> 30#include <asm/page.h>
29#include <asm/uaccess.h> 31#include <asm/uaccess.h>
@@ -242,6 +244,12 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry,
242 goto out; 244 goto out;
243 } 245 }
244 246
247 image->swap_page = kimage_alloc_control_pages(image, 0);
248 if (!image->swap_page) {
249 printk(KERN_ERR "Could not allocate swap buffer\n");
250 goto out;
251 }
252
245 result = 0; 253 result = 0;
246 out: 254 out:
247 if (result == 0) 255 if (result == 0)
@@ -986,6 +994,8 @@ asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
986 if (result) 994 if (result)
987 goto out; 995 goto out;
988 996
997 if (flags & KEXEC_PRESERVE_CONTEXT)
998 image->preserve_context = 1;
989 result = machine_kexec_prepare(image); 999 result = machine_kexec_prepare(image);
990 if (result) 1000 if (result)
991 goto out; 1001 goto out;
@@ -1411,3 +1421,50 @@ static int __init crash_save_vmcoreinfo_init(void)
1411} 1421}
1412 1422
1413module_init(crash_save_vmcoreinfo_init) 1423module_init(crash_save_vmcoreinfo_init)
1424
1425/**
1426 * kernel_kexec - reboot the system
1427 *
1428 * Move into place and start executing a preloaded standalone
1429 * executable. If nothing was preloaded return an error.
1430 */
1431int kernel_kexec(void)
1432{
1433 int error = 0;
1434
1435 if (xchg(&kexec_lock, 1))
1436 return -EBUSY;
1437 if (!kexec_image) {
1438 error = -EINVAL;
1439 goto Unlock;
1440 }
1441
1442 if (kexec_image->preserve_context) {
1443#ifdef CONFIG_KEXEC_JUMP
1444 local_irq_disable();
1445 save_processor_state();
1446#endif
1447 } else {
1448 blocking_notifier_call_chain(&reboot_notifier_list,
1449 SYS_RESTART, NULL);
1450 system_state = SYSTEM_RESTART;
1451 device_shutdown();
1452 sysdev_shutdown();
1453 printk(KERN_EMERG "Starting new kernel\n");
1454 machine_shutdown();
1455 }
1456
1457 machine_kexec(kexec_image);
1458
1459 if (kexec_image->preserve_context) {
1460#ifdef CONFIG_KEXEC_JUMP
1461 restore_processor_state();
1462 local_irq_enable();
1463#endif
1464 }
1465
1466 Unlock:
1467 xchg(&kexec_lock, 0);
1468
1469 return error;
1470}
diff --git a/kernel/sys.c b/kernel/sys.c
index 0c9d3fa1f5ff..c01858090a98 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -301,26 +301,6 @@ void kernel_restart(char *cmd)
301} 301}
302EXPORT_SYMBOL_GPL(kernel_restart); 302EXPORT_SYMBOL_GPL(kernel_restart);
303 303
304/**
305 * kernel_kexec - reboot the system
306 *
307 * Move into place and start executing a preloaded standalone
308 * executable. If nothing was preloaded return an error.
309 */
310static void kernel_kexec(void)
311{
312#ifdef CONFIG_KEXEC
313 struct kimage *image;
314 image = xchg(&kexec_image, NULL);
315 if (!image)
316 return;
317 kernel_restart_prepare(NULL);
318 printk(KERN_EMERG "Starting new kernel\n");
319 machine_shutdown();
320 machine_kexec(image);
321#endif
322}
323
324static void kernel_shutdown_prepare(enum system_states state) 304static void kernel_shutdown_prepare(enum system_states state)
325{ 305{
326 blocking_notifier_call_chain(&reboot_notifier_list, 306 blocking_notifier_call_chain(&reboot_notifier_list,
@@ -425,10 +405,15 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
425 kernel_restart(buffer); 405 kernel_restart(buffer);
426 break; 406 break;
427 407
408#ifdef CONFIG_KEXEC
428 case LINUX_REBOOT_CMD_KEXEC: 409 case LINUX_REBOOT_CMD_KEXEC:
429 kernel_kexec(); 410 {
430 unlock_kernel(); 411 int ret;
431 return -EINVAL; 412 ret = kernel_kexec();
413 unlock_kernel();
414 return ret;
415 }
416#endif
432 417
433#ifdef CONFIG_HIBERNATION 418#ifdef CONFIG_HIBERNATION
434 case LINUX_REBOOT_CMD_SW_SUSPEND: 419 case LINUX_REBOOT_CMD_SW_SUSPEND: