Whamcloud - gitweb
land b_smallfix 20040407_1414:
[fs/lustre-release.git] / lustre / kernel_patches / patches / kexec-2.6.0-full.patch
diff --git a/lustre/kernel_patches/patches/kexec-2.6.0-full.patch b/lustre/kernel_patches/patches/kexec-2.6.0-full.patch
deleted file mode 100644 (file)
index d8a1e09..0000000
+++ /dev/null
@@ -1,1406 +0,0 @@
- 0 files changed
-
---- linux-2.6.0-test1/MAINTAINERS~kexec-2.6.0-full     2003-07-23 12:08:43.000000000 +0800
-+++ linux-2.6.0-test1-root/MAINTAINERS 2003-07-23 12:08:54.000000000 +0800
-@@ -1095,6 +1095,17 @@ W:      http://nfs.sourceforge.net/
- W:    http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/
- S:    Maintained
-+KEXEC
-+P:    Eric Biederman
-+M:    ebiederm@xmission.com
-+M:    ebiederman@lnxi.com
-+W:    http://www.xmission.com/~ebiederm/files/kexec/
-+P:    Andy Pfiffer
-+M:    andyp@osdl.org
-+W:    http://www.osdl.org/archive/andyp/bloom/Code/Linux/Kexec/
-+L:    linux-kernel@vger.kernel.org
-+S:    Maintained
-+
- LANMEDIA WAN CARD DRIVER
- P:    Andrew Stanley-Jones
- M:    asj@lanmedia.com
---- linux-2.6.0-test1/arch/i386/Kconfig~kexec-2.6.0-full       2003-07-23 12:08:52.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/Kconfig   2003-07-23 12:08:54.000000000 +0800
-@@ -804,6 +804,23 @@ config BOOT_IOREMAP
-       depends on ((X86_SUMMIT || X86_GENERICARCH) && NUMA)
-       default y
-+config KEXEC
-+      bool "kexec system call (EXPERIMENTAL)"
-+      depends on EXPERIMENTAL
-+      help
-+        kexec is a system call that implements the ability to  shutdown your
-+        current kernel, and to start another kernel.  It is like a reboot
-+        but it is indepedent of the system firmware.   And like a reboot
-+        you can start any kernel with it not just Linux.  
-+      
-+        The name comes from the similiarity to the exec system call. 
-+      
-+        It is on an going process to be certain the hardware in a machine
-+        is properly shutdown, so do not be surprised if this code does not
-+        initially work for you.  It may help to enable device hotplugging
-+        support.  As of this writing the exact hardware interface is
-+        strongly in flux, so no good recommendation can be made.
-+
- endmenu
---- linux-2.6.0-test1/arch/i386/defconfig~kexec-2.6.0-full     2003-07-14 11:35:57.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/defconfig 2003-07-23 12:08:54.000000000 +0800
-@@ -72,6 +72,7 @@ CONFIG_SMP=y
- CONFIG_X86_LOCAL_APIC=y
- CONFIG_X86_IO_APIC=y
- CONFIG_NR_CPUS=32
-+CONFIG_KEXEC=y
- CONFIG_X86_MCE=y
- # CONFIG_X86_MCE_NONFATAL is not set
- CONFIG_X86_MCE_P4THERMAL=y
---- linux-2.6.0-test1/arch/i386/kernel/Makefile~kexec-2.6.0-full       2003-07-23 12:08:31.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/Makefile   2003-07-23 12:08:54.000000000 +0800
-@@ -25,6 +25,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoli
- obj-$(CONFIG_X86_MPPARSE)     += mpparse.o
- obj-$(CONFIG_X86_LOCAL_APIC)  += apic.o nmi.o
- obj-$(CONFIG_X86_IO_APIC)     += io_apic.o
-+obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o
- obj-$(CONFIG_SOFTWARE_SUSPEND)        += suspend.o suspend_asm.o
- obj-$(CONFIG_X86_NUMAQ)               += numaq.o
- obj-$(CONFIG_X86_SUMMIT)      += summit.o
---- linux-2.6.0-test1/arch/i386/kernel/apic.c~kexec-2.6.0-full 2003-07-23 12:08:30.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/apic.c     2003-07-23 12:08:54.000000000 +0800
-@@ -26,6 +26,7 @@
- #include <linux/mc146818rtc.h>
- #include <linux/kernel_stat.h>
- #include <linux/sysdev.h>
-+#include <linux/reboot.h>
- #include <asm/atomic.h>
- #include <asm/smp.h>
-@@ -175,6 +176,39 @@ void disconnect_bsp_APIC(void)
-               outb(0x70, 0x22);
-               outb(0x00, 0x23);
-       }
-+#ifdef        CONFIG_KEXEC
-+      else {
-+              /* Go back to Virtual Wire compatibility mode */
-+              unsigned long value;
-+
-+              /* For the spurious interrupt use vector F, and enable it */
-+              value = apic_read(APIC_SPIV);
-+              value &= ~APIC_VECTOR_MASK; 
-+              value |= APIC_SPIV_APIC_ENABLED;
-+              value |= 0xf;
-+              apic_write_around(APIC_SPIV, value);
-+
-+              /* For LVT0 make it edge triggered, active high, external and enabled */
-+              value = apic_read(APIC_LVT0);
-+              value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | 
-+                      APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | 
-+                      APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
-+              value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-+              value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXINT);
-+              apic_write_around(APIC_LVT0, value);
-+              
-+              /* For LVT1 make it edge triggered, active high, nmi and enabled */
-+              value = apic_read(APIC_LVT1);
-+              value &= ~(
-+                      APIC_MODE_MASK | APIC_SEND_PENDING | 
-+                      APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | 
-+                      APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
-+              value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-+              value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
-+              apic_write_around(APIC_LVT1, value);
-+      }
-+#endif        /* CONFIG_KEXEC */
-+
- }
- void disable_local_APIC(void)
-@@ -1115,6 +1149,26 @@ asmlinkage void smp_error_interrupt(void
-       irq_exit();
- }
-+void stop_apics(void)
-+{
-+      /* By resetting the APIC's we disable the nmi watchdog */
-+#if CONFIG_SMP
-+      /*
-+       * Stop all CPUs and turn off local APICs and the IO-APIC, so
-+       * other OSs see a clean IRQ state.
-+       */
-+      smp_send_stop();
-+#else
-+      disable_local_APIC();
-+#endif
-+#if defined(CONFIG_X86_IO_APIC)
-+      if (smp_found_config) {
-+              disable_IO_APIC();
-+      }
-+#endif
-+      disconnect_bsp_APIC();
-+}
-+
- /*
-  * This initializes the IO-APIC and APIC hardware if this is
-  * a UP kernel.
---- linux-2.6.0-test1/arch/i386/kernel/dmi_scan.c~kexec-2.6.0-full     2003-07-14 11:32:44.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/dmi_scan.c 2003-07-23 12:08:54.000000000 +0800
-@@ -222,31 +222,6 @@ static __init int set_bios_reboot(struct
-       return 0;
- }
--/*
-- * Some machines require the "reboot=s"  commandline option, this quirk makes that automatic.
-- */
--static __init int set_smp_reboot(struct dmi_blacklist *d)
--{
--#ifdef CONFIG_SMP
--      extern int reboot_smp;
--      if (reboot_smp == 0)
--      {
--              reboot_smp = 1;
--              printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
--      }
--#endif
--      return 0;
--}
--
--/*
-- * Some machines require the "reboot=b,s"  commandline option, this quirk makes that automatic.
-- */
--static __init int set_smp_bios_reboot(struct dmi_blacklist *d)
--{
--      set_smp_reboot(d);
--      set_bios_reboot(d);
--      return 0;
--}
- /*
-  * Some bioses have a broken protected mode poweroff and need to use realmode
-@@ -527,7 +502,7 @@ static __initdata struct dmi_blacklist d
-                       MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
-                       MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
-                       } },
--      { set_smp_bios_reboot, "Dell PowerEdge 1300", { /* Handle problems with rebooting on Dell 1300's */
-+      { set_bios_reboot, "Dell PowerEdge 1300", {     /* Handle problems with rebooting on Dell 1300's */
-                       MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
-                       MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
-                       NO_MATCH, NO_MATCH
---- linux-2.6.0-test1/arch/i386/kernel/entry.S~kexec-2.6.0-full        2003-07-23 12:08:30.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/entry.S    2003-07-23 12:08:54.000000000 +0800
-@@ -905,5 +905,6 @@ ENTRY(sys_call_table)
-       .long sys_tgkill        /* 270 */
-       .long sys_utimes
-       .long sys_mknod64
-+        .long sys_kexec_load
- nr_syscalls=(.-sys_call_table)/4
---- linux-2.6.0-test1/arch/i386/kernel/i8259.c~kexec-2.6.0-full        2003-07-14 11:38:03.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/i8259.c    2003-07-23 12:08:54.000000000 +0800
-@@ -244,9 +244,21 @@ static int i8259A_resume(struct sys_devi
-       return 0;
- }
-+static int i8259A_shutdown(struct sys_device *dev)
-+{
-+      /* Put the i8259A into a quiescent state that
-+       * the kernel initialization code can get it
-+       * out of.
-+       */
-+      outb(0xff, 0x21);       /* mask all of 8259A-1 */
-+      outb(0xff, 0xA1);       /* mask all of 8259A-1 */
-+      return 0;
-+}
-+
- static struct sysdev_class i8259_sysdev_class = {
-       set_kset_name("i8259"),
-       .resume = i8259A_resume,
-+      .shutdown = i8259A_shutdown,
- };
- static struct sys_device device_i8259A = {
---- linux-2.6.0-test1/arch/i386/kernel/io_apic.c~kexec-2.6.0-full      2003-07-23 12:08:30.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/io_apic.c  2003-07-23 12:08:54.000000000 +0800
-@@ -1601,8 +1601,6 @@ void disable_IO_APIC(void)
-        * Clear the IO-APIC before rebooting:
-        */
-       clear_IO_APIC();
--
--      disconnect_bsp_APIC();
- }
- /*
---- /dev/null  2002-08-31 07:31:37.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/machine_kexec.c    2003-07-23 12:08:54.000000000 +0800
-@@ -0,0 +1,116 @@
-+#include <linux/config.h>
-+#include <linux/mm.h>
-+#include <linux/kexec.h>
-+#include <linux/delay.h>
-+#include <asm/pgtable.h>
-+#include <asm/pgalloc.h>
-+#include <asm/tlbflush.h>
-+#include <asm/mmu_context.h>
-+#include <asm/io.h>
-+#include <asm/apic.h>
-+
-+
-+/*
-+ * machine_kexec
-+ * =======================
-+ */
-+
-+
-+static void set_idt(void *newidt, __u16 limit)
-+{
-+      unsigned char curidt[6];
-+
-+      /* ia32 supports unaliged loads & stores */
-+      (*(__u16 *)(curidt)) = limit;
-+      (*(__u32 *)(curidt +2)) = (unsigned long)(newidt);
-+
-+      __asm__ __volatile__ (
-+              "lidt %0\n" 
-+              : "=m" (curidt)
-+              );
-+};
-+
-+
-+static void set_gdt(void *newgdt, __u16 limit)
-+{
-+      unsigned char curgdt[6];
-+
-+      /* ia32 supports unaliged loads & stores */
-+      (*(__u16 *)(curgdt)) = limit;
-+      (*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt);
-+
-+      __asm__ __volatile__ (
-+              "lgdt %0\n" 
-+              : "=m" (curgdt)
-+              );
-+};
-+
-+static void load_segments(void)
-+{
-+#define __STR(X) #X
-+#define STR(X) __STR(X)
-+
-+      __asm__ __volatile__ (
-+              "\tljmp $"STR(__KERNEL_CS)",$1f\n"
-+              "\t1:\n"
-+              "\tmovl $"STR(__KERNEL_DS)",%eax\n"
-+              "\tmovl %eax,%ds\n"
-+              "\tmovl %eax,%es\n"
-+              "\tmovl %eax,%fs\n"
-+              "\tmovl %eax,%gs\n"
-+              "\tmovl %eax,%ss\n"
-+              );
-+#undef STR
-+#undef __STR
-+}
-+
-+typedef void (*relocate_new_kernel_t)(
-+      unsigned long indirection_page, unsigned long reboot_code_buffer,
-+      unsigned long start_address);
-+
-+const extern unsigned char relocate_new_kernel[];
-+extern void relocate_new_kernel_end(void);
-+const extern unsigned int relocate_new_kernel_size;
-+extern void use_mm(struct mm_struct *mm);
-+
-+void machine_kexec(struct kimage *image)
-+{
-+      unsigned long indirection_page;
-+      unsigned long reboot_code_buffer;
-+      relocate_new_kernel_t rnk;
-+
-+      /* switch to an mm where the reboot_code_buffer is identity mapped */
-+      use_mm(&init_mm);
-+      stop_apics();
-+
-+      /* Interrupts aren't acceptable while we reboot */
-+      local_irq_disable();
-+      reboot_code_buffer = page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT;
-+      indirection_page = image->head & PAGE_MASK;
-+
-+      /* copy it out */
-+      memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size);
-+
-+      /* The segment registers are funny things, they are
-+       * automatically loaded from a table, in memory wherever you
-+       * set them to a specific selector, but this table is never
-+       * accessed again you set the segment to a different selector.
-+       *
-+       * The more common model is are caches where the behide
-+       * the scenes work is done, but is also dropped at arbitrary
-+       * times.
-+       *
-+       * I take advantage of this here by force loading the
-+       * segments, before I zap the gdt with an invalid value.
-+       */
-+      load_segments();
-+      /* The gdt & idt are now invalid.
-+       * If you want to load them you must set up your own idt & gdt.
-+       */
-+      set_gdt(phys_to_virt(0),0);
-+      set_idt(phys_to_virt(0),0);
-+
-+      /* now call it */
-+      rnk = (relocate_new_kernel_t) reboot_code_buffer;
-+      (*rnk)(indirection_page, reboot_code_buffer, image->start);
-+}
---- linux-2.6.0-test1/arch/i386/kernel/reboot.c~kexec-2.6.0-full       2003-07-23 12:08:31.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/reboot.c   2003-07-23 12:08:54.000000000 +0800
-@@ -8,6 +8,7 @@
- #include <linux/interrupt.h>
- #include <linux/mc146818rtc.h>
- #include <asm/uaccess.h>
-+#include <asm/apic.h>
- #include "mach_reboot.h"
- /*
-@@ -20,8 +21,7 @@ static int reboot_mode;
- int reboot_thru_bios;
- #ifdef CONFIG_SMP
--int reboot_smp = 0;
--static int reboot_cpu = -1;
-+int reboot_cpu = -1;    /* specifies the internal linux cpu id, not the apicid */
- /* shamelessly grabbed from lib/vsprintf.c for readability */
- #define is_digit(c)   ((c) >= '0' && (c) <= '9')
- #endif
-@@ -43,7 +43,6 @@ static int __init reboot_setup(char *str
-                       break;
- #ifdef CONFIG_SMP
-               case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
--                      reboot_smp = 1;
-                       if (is_digit(*(str+1))) {
-                               reboot_cpu = (int) (*(str+1) - '0');
-                               if (is_digit(*(str+2))) 
-@@ -215,42 +214,7 @@ void machine_real_restart(unsigned char 
- void machine_restart(char * __unused)
- {
--#ifdef CONFIG_SMP
--      int cpuid;
--      
--      cpuid = GET_APIC_ID(apic_read(APIC_ID));
--
--      if (reboot_smp) {
--
--              /* check to see if reboot_cpu is valid 
--                 if its not, default to the BSP */
--              if ((reboot_cpu == -1) ||  
--                    (reboot_cpu > (NR_CPUS -1))  || 
--                    !cpu_isset(cpuid, phys_cpu_present_map))
--                      reboot_cpu = boot_cpu_physical_apicid;
--
--              reboot_smp = 0;  /* use this as a flag to only go through this once*/
--              /* re-run this function on the other CPUs
--                 it will fall though this section since we have 
--                 cleared reboot_smp, and do the reboot if it is the
--                 correct CPU, otherwise it halts. */
--              if (reboot_cpu != cpuid)
--                      smp_call_function((void *)machine_restart , NULL, 1, 0);
--      }
--
--      /* if reboot_cpu is still -1, then we want a tradional reboot, 
--         and if we are not running on the reboot_cpu,, halt */
--      if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
--              for (;;)
--              __asm__ __volatile__ ("hlt");
--      }
--      /*
--       * Stop all CPUs and turn off local APICs and the IO-APIC, so
--       * other OSs see a clean IRQ state.
--       */
--      smp_send_stop();
--      disable_IO_APIC();
--#endif
-+        stop_apics();
-       if(!reboot_thru_bios) {
-               /* rebooting needs to touch the page at absolute addr 0 */
-@@ -268,10 +232,12 @@ void machine_restart(char * __unused)
- void machine_halt(void)
- {
-+      stop_apics();
- }
- void machine_power_off(void)
- {
-+      stop_apics();
-       if (pm_power_off)
-               pm_power_off();
- }
---- /dev/null  2002-08-31 07:31:37.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/relocate_kernel.S  2003-07-23 12:08:54.000000000 +0800
-@@ -0,0 +1,107 @@
-+#include <linux/config.h>
-+#include <linux/linkage.h>
-+
-+      /* Must be relocatable PIC code callable as a C function, that once
-+       * it starts can not use the previous processes stack.
-+       *
-+       */
-+      .globl relocate_new_kernel
-+relocate_new_kernel:
-+      /* read the arguments and say goodbye to the stack */
-+      movl  4(%esp), %ebx /* indirection_page */
-+      movl  8(%esp), %ebp /* reboot_code_buffer */
-+      movl  12(%esp), %edx /* start address */
-+
-+      /* zero out flags, and disable interrupts */
-+      pushl $0
-+      popfl
-+
-+      /* set a new stack at the bottom of our page... */
-+      lea   4096(%ebp), %esp
-+
-+      /* store the parameters back on the stack */
-+      pushl   %edx /* store the start address */
-+
-+      /* Set cr0 to a known state:
-+       * 31 0 == Paging disabled
-+       * 18 0 == Alignment check disabled
-+       * 16 0 == Write protect disabled
-+       * 3  0 == No task switch
-+       * 2  0 == Don't do FP software emulation.
-+       * 0  1 == Proctected mode enabled
-+       */
-+      movl    %cr0, %eax
-+      andl    $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
-+      orl     $(1<<0), %eax
-+      movl    %eax, %cr0
-+      
-+      /* Set cr4 to a known state:
-+       * Setting everything to zero seems safe.
-+       */
-+      movl    %cr4, %eax
-+      andl    $0, %eax
-+      movl    %eax, %cr4
-+      
-+      jmp 1f
-+1:    
-+
-+      /* Flush the TLB (needed?) */
-+      xorl    %eax, %eax
-+      movl    %eax, %cr3
-+
-+      /* Do the copies */
-+      cld
-+0:    /* top, read another word for the indirection page */
-+      movl    %ebx, %ecx
-+      movl    (%ebx), %ecx
-+      addl    $4, %ebx
-+      testl   $0x1,   %ecx  /* is it a destination page */
-+      jz      1f
-+      movl    %ecx,   %edi
-+      andl    $0xfffff000, %edi
-+      jmp     0b
-+1:
-+      testl   $0x2,   %ecx  /* is it an indirection page */
-+      jz      1f
-+      movl    %ecx,   %ebx
-+      andl    $0xfffff000, %ebx
-+      jmp     0b
-+1:
-+      testl   $0x4,   %ecx /* is it the done indicator */
-+      jz      1f
-+      jmp     2f
-+1:
-+      testl   $0x8,   %ecx /* is it the source indicator */
-+      jz      0b           /* Ignore it otherwise */
-+      movl    %ecx,   %esi /* For every source page do a copy */
-+      andl    $0xfffff000, %esi
-+
-+      movl    $1024, %ecx
-+      rep ; movsl
-+      jmp     0b
-+
-+2:
-+
-+      /* To be certain of avoiding problems with self modifying code
-+       * I need to execute a serializing instruction here.
-+       * So I flush the TLB, it's handy, and not processor dependent.
-+       */
-+      xorl    %eax, %eax
-+      movl    %eax, %cr3
-+      
-+      /* set all of the registers to known values */
-+      /* leave %esp alone */
-+      
-+      xorl    %eax, %eax
-+      xorl    %ebx, %ebx
-+      xorl    %ecx, %ecx
-+      xorl    %edx, %edx
-+      xorl    %esi, %esi
-+      xorl    %edi, %edi
-+      xorl    %ebp, %ebp
-+      ret
-+relocate_new_kernel_end:
-+
-+      .globl relocate_new_kernel_size
-+relocate_new_kernel_size:     
-+      .long relocate_new_kernel_end - relocate_new_kernel
---- linux-2.6.0-test1/arch/i386/kernel/smp.c~kexec-2.6.0-full  2003-07-23 12:08:52.000000000 +0800
-+++ linux-2.6.0-test1-root/arch/i386/kernel/smp.c      2003-07-23 12:53:45.000000000 +0800
-@@ -587,6 +587,30 @@ void stop_this_cpu (void * dummy)
- void smp_send_stop(void)
- {
-+      extern int reboot_cpu;
-+      int reboot_cpu_id;
-+      
-+      /* The boot cpu is always logical cpu 0 */
-+      reboot_cpu_id = 0;
-+
-+      /* See if there has been give a command line override .
-+       */
-+      if ((reboot_cpu != -1) && !(reboot_cpu >= NR_CPUS) && 
-+              test_bit(reboot_cpu, &cpu_online_map)) {
-+              reboot_cpu_id = reboot_cpu;
-+      }
-+       
-+      /* Make certain the the cpu I'm rebooting on is online */
-+      if (!test_bit(reboot_cpu_id, &cpu_online_map)) {
-+              reboot_cpu_id = smp_processor_id();
-+      }
-+
-+      /* Make certain I only run on the appropriate processor */
-+      set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
-+
-+      /* O.k. Now that I'm on the appropriate processor stop
-+       * all of the others.
-+       */
-       smp_call_function(stop_this_cpu, NULL, 1, 0);
-       local_irq_disable();
---- linux-2.6.0-test1/include/asm-i386/apic.h~kexec-2.6.0-full 2003-07-14 11:38:53.000000000 +0800
-+++ linux-2.6.0-test1-root/include/asm-i386/apic.h     2003-07-23 12:08:54.000000000 +0800
-@@ -97,6 +97,9 @@ extern unsigned int nmi_watchdog;
- #define NMI_LOCAL_APIC        2
- #define NMI_INVALID   3
-+extern void stop_apics(void);
-+#else
-+static inline void stop_apics(void) { }
- #endif /* CONFIG_X86_LOCAL_APIC */
- #endif /* __ASM_APIC_H */
---- linux-2.6.0-test1/include/asm-i386/apicdef.h~kexec-2.6.0-full      2003-07-14 11:34:40.000000000 +0800
-+++ linux-2.6.0-test1-root/include/asm-i386/apicdef.h  2003-07-23 12:08:54.000000000 +0800
-@@ -86,6 +86,7 @@
- #define                       APIC_LVT_REMOTE_IRR             (1<<14)
- #define                       APIC_INPUT_POLARITY             (1<<13)
- #define                       APIC_SEND_PENDING               (1<<12)
-+#define                       APIC_MODE_MASK                  0x700
- #define                       GET_APIC_DELIVERY_MODE(x)       (((x)>>8)&0x7)
- #define                       SET_APIC_DELIVERY_MODE(x,y)     (((x)&~0x700)|((y)<<8))
- #define                               APIC_MODE_FIXED         0x0
---- /dev/null  2002-08-31 07:31:37.000000000 +0800
-+++ linux-2.6.0-test1-root/include/asm-i386/kexec.h    2003-07-23 12:08:54.000000000 +0800
-@@ -0,0 +1,23 @@
-+#ifndef _I386_KEXEC_H
-+#define _I386_KEXEC_H
-+
-+#include <asm/fixmap.h>
-+
-+/*
-+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
-+ * I.e. Maximum page that is mapped directly into kernel memory,
-+ * and kmap is not required.
-+ *
-+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
-+ * calculation for the amount of memory directly mappable into the
-+ * kernel memory space.
-+ */
-+
-+/* Maximum physical address we can use pages from */
-+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
-+/* Maximum address we can reach in physical address mode */
-+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
-+
-+#define KEXEC_REBOOT_CODE_SIZE        4096
-+
-+#endif /* _I386_KEXEC_H */
---- linux-2.6.0-test1/include/asm-i386/unistd.h~kexec-2.6.0-full       2003-07-23 12:08:42.000000000 +0800
-+++ linux-2.6.0-test1-root/include/asm-i386/unistd.h   2003-07-23 12:08:54.000000000 +0800
-@@ -278,8 +278,9 @@
- #define __NR_tgkill           270
- #define __NR_utimes           271
- #define __NR_mknod64          272
--
--#define NR_syscalls 273
-+#define __NR_sys_kexec_load   273
-+  
-+#define NR_syscalls 274
- /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
---- /dev/null  2002-08-31 07:31:37.000000000 +0800
-+++ linux-2.6.0-test1-root/include/linux/kexec.h       2003-07-23 12:08:54.000000000 +0800
-@@ -0,0 +1,54 @@
-+#ifndef LINUX_KEXEC_H
-+#define LINUX_KEXEC_H
-+
-+#if CONFIG_KEXEC
-+#include <linux/types.h>
-+#include <linux/list.h>
-+#include <asm/kexec.h>
-+
-+/* 
-+ * This structure is used to hold the arguments that are used when loading
-+ * kernel binaries.
-+ */
-+
-+typedef unsigned long kimage_entry_t;
-+#define IND_DESTINATION  0x1
-+#define IND_INDIRECTION  0x2
-+#define IND_DONE         0x4
-+#define IND_SOURCE       0x8
-+
-+#define KEXEC_SEGMENT_MAX 8
-+struct kexec_segment {
-+      void *buf;
-+      size_t bufsz;
-+      void *mem;
-+      size_t memsz;
-+};
-+
-+struct kimage {
-+      kimage_entry_t head;
-+      kimage_entry_t *entry;
-+      kimage_entry_t *last_entry;
-+
-+      unsigned long destination;
-+      unsigned long offset;
-+
-+      unsigned long start;
-+      struct page *reboot_code_pages;
-+
-+      unsigned long nr_segments;
-+      struct kexec_segment segment[KEXEC_SEGMENT_MAX+1];
-+
-+      struct list_head dest_pages;
-+      struct list_head unuseable_pages;
-+};
-+
-+
-+/* kexec interface functions */
-+extern void machine_kexec(struct kimage *image);
-+extern asmlinkage long sys_kexec(unsigned long entry, long nr_segments, 
-+      struct kexec_segment *segments);
-+extern struct kimage *kexec_image;
-+#endif
-+#endif /* LINUX_KEXEC_H */
-+
---- linux-2.6.0-test1/include/linux/reboot.h~kexec-2.6.0-full  2003-07-14 11:39:35.000000000 +0800
-+++ linux-2.6.0-test1-root/include/linux/reboot.h      2003-07-23 12:08:54.000000000 +0800
-@@ -22,6 +22,7 @@
-  * POWER_OFF   Stop OS and remove all power from system, if possible.
-  * RESTART2    Restart system using given command string.
-  * SW_SUSPEND  Suspend system using Software Suspend if compiled in
-+ * KEXEC       Restart the system using a different kernel.
-  */
- #define       LINUX_REBOOT_CMD_RESTART        0x01234567
-@@ -31,6 +32,7 @@
- #define       LINUX_REBOOT_CMD_POWER_OFF      0x4321FEDC
- #define       LINUX_REBOOT_CMD_RESTART2       0xA1B2C3D4
- #define       LINUX_REBOOT_CMD_SW_SUSPEND     0xD000FCE2
-+#define LINUX_REBOOT_CMD_KEXEC                0x45584543
- #ifdef __KERNEL__
---- linux-2.6.0-test1/kernel/Makefile~kexec-2.6.0-full 2003-07-23 12:08:43.000000000 +0800
-+++ linux-2.6.0-test1-root/kernel/Makefile     2003-07-23 12:08:54.000000000 +0800
-@@ -19,6 +19,7 @@ obj-$(CONFIG_PM) += pm.o
- obj-$(CONFIG_CPU_FREQ) += cpufreq.o
- obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
- obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
-+obj-$(CONFIG_KEXEC) += kexec.o
- obj-$(CONFIG_COMPAT) += compat.o
- ifneq ($(CONFIG_IA64),y)
---- /dev/null  2002-08-31 07:31:37.000000000 +0800
-+++ linux-2.6.0-test1-root/kernel/kexec.c      2003-07-23 12:08:54.000000000 +0800
-@@ -0,0 +1,629 @@
-+#include <linux/mm.h>
-+#include <linux/file.h>
-+#include <linux/slab.h>
-+#include <linux/fs.h>
-+#include <linux/version.h>
-+#include <linux/compile.h>
-+#include <linux/kexec.h>
-+#include <linux/spinlock.h>
-+#include <linux/list.h>
-+#include <linux/highmem.h>
-+#include <net/checksum.h>
-+#include <asm/page.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
-+/* When kexec transitions to the new kernel there is a one to one
-+ * mapping between physical and virtual addresses.  On processors
-+ * where you can disable the MMU this is trivial, and easy.  For
-+ * others it is still a simple predictable page table to setup.
-+ *
-+ * In that environment kexec copies the new kernel to it's final
-+ * resting place.  This means I can only support memory whose
-+ * physical address can fit in an unsigned long.  In particular
-+ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled.
-+ * If the assembly stub has more restrictive requirements
-+ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be
-+ * defined more restrictively in <asm/kexec.h>.
-+ *
-+ * The code for the transition from the current kernel to the 
-+ * the new kernel is placed in the reboot_code_buffer, whose size
-+ * is given by KEXEC_REBOOT_CODE_SIZE.  In the best case only a single
-+ * page of memory is necessary, but some architectures require more.
-+ * Because this memory must be identity mapped in the transition from
-+ * virtual to physical addresses it must live in the range
-+ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily
-+ * modifyable.
-+ *
-+ * The assembly stub in the reboot code buffer is passed a linked list
-+ * of descriptor pages detailing the source pages of the new kernel,
-+ * and the destination addresses of those source pages.  As this data
-+ * structure is not used in the context of the current OS, it must
-+ * be self contained.
-+ *
-+ * The code has been made to work with highmem pages and will use a
-+ * destination page in it's final resting place (if it happens 
-+ * to allocate it).  The end product of this is that most of the
-+ * physical address space, and most of ram can be used.
-+ *
-+ * Future directions include:
-+ *  - allocating a page table with the reboot code buffer identity
-+ *    mapped, to simplify machine_kexec and make kexec_on_panic, more
-+ *    reliable.  
-+ *  - allocating the pages for a page table for machines that cannot
-+ *    disable their MMUs.  (Hammer, Alpha...)
-+ */
-+
-+/* KIMAGE_NO_DEST is an impossible destination address..., for
-+ * allocating pages whose destination address we do not care about.
-+ */
-+#define KIMAGE_NO_DEST (-1UL)
-+
-+static int kimage_is_destination_range(
-+      struct kimage *image, unsigned long start, unsigned long end);
-+static struct page *kimage_alloc_reboot_code_pages(struct kimage *image);
-+static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long dest);
-+
-+
-+static int kimage_alloc(struct kimage **rimage, 
-+      unsigned long nr_segments, struct kexec_segment *segments)
-+{
-+      int result;
-+      struct kimage *image;
-+      size_t segment_bytes;
-+      struct page *reboot_pages;
-+      unsigned long i;
-+
-+      /* Allocate a controlling structure */
-+      result = -ENOMEM;
-+      image = kmalloc(sizeof(*image), GFP_KERNEL);
-+      if (!image) {
-+              goto out;
-+      }
-+      memset(image, 0, sizeof(*image));
-+      image->head = 0;
-+      image->entry = &image->head;
-+      image->last_entry = &image->head;
-+
-+      /* Initialize the list of destination pages */
-+      INIT_LIST_HEAD(&image->dest_pages);
-+
-+      /* Initialize the list of unuseable pages */
-+      INIT_LIST_HEAD(&image->unuseable_pages);
-+
-+      /* Read in the segments */
-+      image->nr_segments = nr_segments;
-+      segment_bytes = nr_segments * sizeof*segments;
-+      result = copy_from_user(image->segment, segments, segment_bytes);
-+      if (result) 
-+              goto out;
-+
-+      /* Verify we have good destination addresses.  The caller is
-+       * responsible for making certain we don't attempt to load
-+       * the new image into invalid or reserved areas of RAM.  This
-+       * just verifies it is an address we can use. 
-+       */
-+      result = -EADDRNOTAVAIL;
-+      for(i = 0; i < nr_segments; i++) {
-+              unsigned long mend;
-+              mend = ((unsigned long)(image->segment[i].mem)) + 
-+                      image->segment[i].memsz;
-+              if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
-+                      goto out;
-+      }
-+
-+      /* Find a location for the reboot code buffer, and add it
-+       * the vector of segments so that it's pages will also be
-+       * counted as destination pages.  
-+       */
-+      result = -ENOMEM;
-+      reboot_pages = kimage_alloc_reboot_code_pages(image);
-+      if (!reboot_pages) {
-+              printk(KERN_ERR "Could not allocate reboot_code_buffer\n");
-+              goto out;
-+      }
-+      image->reboot_code_pages = reboot_pages;
-+      image->segment[nr_segments].buf = 0;
-+      image->segment[nr_segments].bufsz = 0;
-+      image->segment[nr_segments].mem = (void *)(page_to_pfn(reboot_pages) << PAGE_SHIFT);
-+      image->segment[nr_segments].memsz = KEXEC_REBOOT_CODE_SIZE;
-+      image->nr_segments++;
-+
-+      result = 0;
-+ out:
-+      if (result == 0) {
-+              *rimage = image;
-+      } else {
-+              kfree(image);
-+      }
-+      return result;
-+}
-+
-+static int kimage_is_destination_range(
-+      struct kimage *image, unsigned long start, unsigned long end)
-+{
-+      unsigned long i;
-+      for(i = 0; i < image->nr_segments; i++) {
-+              unsigned long mstart, mend;
-+              mstart = (unsigned long)image->segment[i].mem;
-+              mend   = mstart + image->segment[i].memsz;
-+              if ((end > mstart) && (start < mend)) {
-+                      return 1;
-+              }
-+      }
-+      return 0;
-+}
-+
-+#ifdef CONFIG_MMU
-+static int identity_map_pages(struct page *pages, int order)
-+{
-+      struct mm_struct *mm;
-+      struct vm_area_struct *vma;
-+      int error;
-+      mm = &init_mm;
-+      vma = 0;
-+
-+      down_write(&mm->mmap_sem);
-+      error = -ENOMEM;
-+      vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-+      if (!vma) {
-+              goto out;
-+      }
-+
-+      memset(vma, 0, sizeof(vma));
-+      vma->vm_mm = mm;
-+      vma->vm_start = page_to_pfn(pages) << PAGE_SHIFT;
-+      vma->vm_end = vma->vm_start + (1 << (order + PAGE_SHIFT));
-+      vma->vm_ops = 0;
-+      vma->vm_flags = VM_SHARED \
-+              | VM_READ | VM_WRITE | VM_EXEC \
-+              | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC \
-+              | VM_DONTCOPY | VM_RESERVED;
-+      vma->vm_page_prot = protection_map[vma->vm_flags & 0xf];
-+      vma->vm_file = NULL;
-+      vma->vm_private_data = NULL;
-+      INIT_LIST_HEAD(&vma->shared);
-+      insert_vm_struct(mm, vma);
-+      
-+      error = remap_page_range(vma, vma->vm_start, vma->vm_start,
-+              vma->vm_end - vma->vm_start, vma->vm_page_prot);
-+      if (error) {
-+              goto out;
-+      }
-+
-+      error = 0;
-+ out:
-+      if (error && vma) {
-+              kmem_cache_free(vm_area_cachep, vma);
-+              vma = 0;
-+      }
-+      up_write(&mm->mmap_sem);
-+
-+      return error;
-+}
-+#else
-+#define identity_map_pages(pages, order) 0
-+#endif
-+
-+struct page *kimage_alloc_reboot_code_pages(struct kimage *image)
-+{
-+      /* The reboot code buffer is special.  It is the only set of
-+       * pages that must be allocated in their final resting place,
-+       * and the only set of pages whose final resting place we can
-+       * pick. 
-+       *
-+       * At worst this runs in O(N) of the image size.
-+       */
-+      struct list_head extra_pages, *pos, *next;
-+      struct page *pages;
-+      unsigned long addr;
-+      int order, count;
-+      order = get_order(KEXEC_REBOOT_CODE_SIZE);
-+      count = 1 << order;
-+      INIT_LIST_HEAD(&extra_pages);
-+      do {
-+              int i;
-+              pages = alloc_pages(GFP_HIGHUSER, order);
-+              if (!pages)
-+                      break;
-+              for(i = 0; i < count; i++) {
-+                      SetPageReserved(pages +i);
-+              }
-+              addr = page_to_pfn(pages) << PAGE_SHIFT;
-+              if ((page_to_pfn(pages) >= (TASK_SIZE >> PAGE_SHIFT)) ||
-+                      kimage_is_destination_range(image, addr, addr + KEXEC_REBOOT_CODE_SIZE)) {
-+                      list_add(&pages->list, &extra_pages);
-+                      pages = 0;
-+              }
-+      } while(!pages);
-+      if (pages) {
-+              int result;
-+              result = identity_map_pages(pages, order);
-+              if (result < 0) {
-+                      list_add(&pages->list, &extra_pages);
-+                      pages = 0;
-+              }
-+      }
-+      /* If I could convert a multi page allocation into a buch of
-+       * single page allocations I could add these pages to
-+       * image->dest_pages.  For now it is simpler to just free the
-+       * pages again.
-+       */
-+      list_for_each_safe(pos, next, &extra_pages) {
-+              struct page *page;
-+              int i;
-+              page = list_entry(pos, struct page, list);
-+              for(i = 0; i < count; i++) {
-+                      ClearPageReserved(pages +i);
-+              }
-+              list_del(&extra_pages);
-+              __free_pages(page, order);
-+      }
-+      return pages;
-+}
-+
-+static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
-+{
-+      if (image->offset != 0) {
-+              image->entry++;
-+      }
-+      if (image->entry == image->last_entry) {
-+              kimage_entry_t *ind_page;
-+              struct page *page;
-+              page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST);
-+              if (!page) {
-+                      return -ENOMEM;
-+              }
-+              ind_page = page_address(page);
-+              *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
-+              image->entry = ind_page;
-+              image->last_entry = 
-+                      ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
-+      }
-+      *image->entry = entry;
-+      image->entry++;
-+      image->offset = 0;
-+      return 0;
-+}
-+
-+static int kimage_set_destination(
-+      struct kimage *image, unsigned long destination) 
-+{
-+      int result;
-+      destination &= PAGE_MASK;
-+      result = kimage_add_entry(image, destination | IND_DESTINATION);
-+      if (result == 0) {
-+              image->destination = destination;
-+      }
-+      return result;
-+}
-+
-+
-+static int kimage_add_page(struct kimage *image, unsigned long page)
-+{
-+      int result;
-+      page &= PAGE_MASK;
-+      result = kimage_add_entry(image, page | IND_SOURCE);
-+      if (result == 0) {
-+              image->destination += PAGE_SIZE;
-+      }
-+      return result;
-+}
-+
-+
-+static void kimage_free_extra_pages(struct kimage *image)
-+{
-+      /* Walk through and free any extra destination pages I may have */
-+      struct list_head *pos, *next;
-+      list_for_each_safe(pos, next, &image->dest_pages) {
-+              struct page *page;
-+              page = list_entry(pos, struct page, list);
-+              list_del(&page->list);
-+              ClearPageReserved(page);
-+              __free_page(page);
-+      }
-+      /* Walk through and free any unuseable pages I have cached */
-+      list_for_each_safe(pos, next, &image->unuseable_pages) {
-+              struct page *page;
-+              page = list_entry(pos, struct page, list);
-+              list_del(&page->list);
-+              ClearPageReserved(page);
-+              __free_page(page);
-+      }
-+
-+}
-+static int kimage_terminate(struct kimage *image)
-+{
-+      int result;
-+      result = kimage_add_entry(image, IND_DONE);
-+      if (result == 0) {
-+              /* Point at the terminating element */
-+              image->entry--;
-+              kimage_free_extra_pages(image);
-+      }
-+      return result;
-+}
-+
-+#define for_each_kimage_entry(image, ptr, entry) \
-+      for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
-+              ptr = (entry & IND_INDIRECTION)? \
-+                      phys_to_virt((entry & PAGE_MASK)): ptr +1)
-+
-+static void kimage_free(struct kimage *image)
-+{
-+      kimage_entry_t *ptr, entry;
-+      kimage_entry_t ind = 0;
-+      int i, count, order;
-+      if (!image)
-+              return;
-+      kimage_free_extra_pages(image);
-+      for_each_kimage_entry(image, ptr, entry) {
-+              if (entry & IND_INDIRECTION) {
-+                      /* Free the previous indirection page */
-+                      if (ind & IND_INDIRECTION) {
-+                              free_page((unsigned long)phys_to_virt(ind & PAGE_MASK));
-+                      }
-+                      /* Save this indirection page until we are
-+                       * done with it.
-+                       */
-+                      ind = entry;
-+              }
-+              else if (entry & IND_SOURCE) {
-+                      free_page((unsigned long)phys_to_virt(entry & PAGE_MASK));
-+              }
-+      }
-+      order = get_order(KEXEC_REBOOT_CODE_SIZE);
-+      count = 1 << order;
-+      do_munmap(&init_mm, 
-+              page_to_pfn(image->reboot_code_pages) << PAGE_SHIFT, 
-+              count << PAGE_SHIFT);
-+      for(i = 0; i < count; i++) {
-+              ClearPageReserved(image->reboot_code_pages + i);
-+      }
-+      __free_pages(image->reboot_code_pages, order);
-+      kfree(image);
-+}
-+
-+static kimage_entry_t *kimage_dst_used(struct kimage *image, unsigned long page)
-+{
-+      kimage_entry_t *ptr, entry;
-+      unsigned long destination = 0;
-+      for_each_kimage_entry(image, ptr, entry) {
-+              if (entry & IND_DESTINATION) {
-+                      destination = entry & PAGE_MASK;
-+              }
-+              else if (entry & IND_SOURCE) {
-+                      if (page == destination) {
-+                              return ptr;
-+                      }
-+                      destination += PAGE_SIZE;
-+              }
-+      }
-+      return 0;
-+}
-+
-+static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long destination)
-+{
-+      /* Here we implment safe guards to ensure that a source page
-+       * is not copied to it's destination page before the data on
-+       * the destination page is no longer useful.
-+       *
-+       * To do this we maintain the invariant that a source page is
-+       * either it's own destination page, or it is not a
-+       * destination page at all.  
-+       *
-+       * That is slightly stronger than required, but the proof
-+       * that no problems will not occur is trivial, and the
-+       * implemenation is simply to verify.
-+       *
-+       * When allocating all pages normally this algorithm will run
-+       * in O(N) time, but in the worst case it will run in O(N^2)
-+       * time.   If the runtime is a problem the data structures can
-+       * be fixed.
-+       */
-+      struct page *page;
-+      unsigned long addr;
-+
-+      /* Walk through the list of destination pages, and see if I
-+       * have a match.
-+       */
-+      list_for_each_entry(page, &image->dest_pages, list) {
-+              addr = page_to_pfn(page) << PAGE_SHIFT;
-+              if (addr == destination) {
-+                      list_del(&page->list);
-+                      return page;
-+              }
-+      }
-+      page = 0;
-+      while(1) {
-+              kimage_entry_t *old;
-+              /* Allocate a page, if we run out of memory give up */
-+              page = alloc_page(gfp_mask);
-+              if (!page) {
-+                      return 0;
-+              }
-+              SetPageReserved(page);
-+              /* If the page cannot be used file it away */
-+              if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
-+                      list_add(&page->list, &image->unuseable_pages);
-+                      continue;
-+              }
-+              addr = page_to_pfn(page) << PAGE_SHIFT;
-+
-+              /* If it is the destination page we want use it */
-+              if (addr == destination)
-+                      break;
-+
-+              /* If the page is not a destination page use it */
-+              if (!kimage_is_destination_range(image, addr, addr + PAGE_SIZE))
-+                      break;
-+
-+              /* I know that the page is someones destination page.
-+               * See if there is already a source page for this
-+               * destination page.  And if so swap the source pages.
-+               */
-+              old = kimage_dst_used(image, addr);
-+              if (old) {
-+                      /* If so move it */
-+                      unsigned long old_addr;
-+                      struct page *old_page;
-+                      
-+                      old_addr = *old & PAGE_MASK;
-+                      old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
-+                      copy_highpage(page, old_page);
-+                      *old = addr | (*old & ~PAGE_MASK);
-+
-+                      /* The old page I have found cannot be a
-+                       * destination page, so return it.
-+                       */
-+                      addr = old_addr;
-+                      page = old_page;
-+                      break;
-+              }
-+              else {
-+                      /* Place the page on the destination list I
-+                       * will use it later.
-+                       */
-+                      list_add(&page->list, &image->dest_pages);
-+              }
-+      }
-+      return page;
-+}
-+
-+static int kimage_load_segment(struct kimage *image,
-+      struct kexec_segment *segment)
-+{     
-+      unsigned long mstart;
-+      int result;
-+      unsigned long offset;
-+      unsigned long offset_end;
-+      unsigned char *buf;
-+
-+      result = 0;
-+      buf = segment->buf;
-+      mstart = (unsigned long)segment->mem;
-+
-+      offset_end = segment->memsz;
-+
-+      result = kimage_set_destination(image, mstart);
-+      if (result < 0) {
-+              goto out;
-+      }
-+      for(offset = 0;  offset < segment->memsz; offset += PAGE_SIZE) {
-+              struct page *page;
-+              char *ptr;
-+              size_t size, leader;
-+              page = kimage_alloc_page(image, GFP_HIGHUSER, mstart + offset);
-+              if (page == 0) {
-+                      result  = -ENOMEM;
-+                      goto out;
-+              }
-+              result = kimage_add_page(image, page_to_pfn(page) << PAGE_SHIFT);
-+              if (result < 0) {
-+                      goto out;
-+              }
-+              ptr = kmap(page);
-+              if (segment->bufsz < offset) {
-+                      /* We are past the end zero the whole page */
-+                      memset(ptr, 0, PAGE_SIZE);
-+                      kunmap(page);
-+                      continue;
-+              }
-+              size = PAGE_SIZE;
-+              leader = 0;
-+              if ((offset == 0)) {
-+                      leader = mstart & ~PAGE_MASK;
-+              }
-+              if (leader) {
-+                      /* We are on the first page zero the unused portion */
-+                      memset(ptr, 0, leader);
-+                      size -= leader;
-+                      ptr += leader;
-+              }
-+              if (size > (segment->bufsz - offset)) {
-+                      size = segment->bufsz - offset;
-+              }
-+              if (size < (PAGE_SIZE - leader)) {
-+                      /* zero the trailing part of the page */
-+                      memset(ptr + size, 0, (PAGE_SIZE - leader) - size);
-+              }
-+              result = copy_from_user(ptr, buf + offset, size);
-+              kunmap(page);
-+              if (result) {
-+                      result = (result < 0)?result : -EIO;
-+                      goto out;
-+              }
-+      }
-+ out:
-+      return result;
-+}
-+
-+/*
-+ * Exec Kernel system call: for obvious reasons only root may call it.
-+ * 
-+ * This call breaks up into three pieces.  
-+ * - A generic part which loads the new kernel from the current
-+ *   address space, and very carefully places the data in the
-+ *   allocated pages.
-+ *
-+ * - A generic part that interacts with the kernel and tells all of
-+ *   the devices to shut down.  Preventing on-going dmas, and placing
-+ *   the devices in a consistent state so a later kernel can
-+ *   reinitialize them.
-+ *
-+ * - A machine specific part that includes the syscall number
-+ *   and the copies the image to it's final destination.  And
-+ *   jumps into the image at entry.
-+ *
-+ * kexec does not sync, or unmount filesystems so if you need
-+ * that to happen you need to do that yourself.
-+ */
-+struct kimage *kexec_image = 0;
-+
-+asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, 
-+      struct kexec_segment *segments, unsigned long flags)
-+{
-+      struct kimage *image;
-+      int result;
-+              
-+      /* We only trust the superuser with rebooting the system. */
-+      if (!capable(CAP_SYS_ADMIN))
-+              return -EPERM;
-+
-+      /* In case we need just a little bit of special behavior for
-+       * reboot on panic 
-+       */
-+      if (flags != 0)
-+              return -EINVAL;
-+
-+      if (nr_segments > KEXEC_SEGMENT_MAX)
-+              return -EINVAL;
-+      image = 0;
-+
-+      result = 0;
-+      if (nr_segments > 0) {
-+              unsigned long i;
-+              result = kimage_alloc(&image, nr_segments, segments);
-+              if (result) {
-+                      goto out;
-+              }
-+              image->start = entry;
-+              for(i = 0; i < nr_segments; i++) {
-+                      result = kimage_load_segment(image, &segments[i]);
-+                      if (result) {
-+                              goto out;
-+                      }
-+              }
-+              result = kimage_terminate(image);
-+              if (result) {
-+                      goto out;
-+              }
-+      }
-+
-+      image = xchg(&kexec_image, image);
-+
-+ out:
-+      kimage_free(image);
-+      return result;
-+}
---- linux-2.6.0-test1/kernel/sys.c~kexec-2.6.0-full    2003-07-23 12:08:43.000000000 +0800
-+++ linux-2.6.0-test1-root/kernel/sys.c        2003-07-23 12:08:54.000000000 +0800
-@@ -17,6 +17,7 @@
- #include <linux/init.h>
- #include <linux/highuid.h>
- #include <linux/fs.h>
-+#include <linux/kexec.h>
- #include <linux/workqueue.h>
- #include <linux/device.h>
- #include <linux/times.h>
-@@ -208,6 +209,7 @@ cond_syscall(sys_acct)
- cond_syscall(sys_lookup_dcookie)
- cond_syscall(sys_swapon)
- cond_syscall(sys_swapoff)
-+cond_syscall(sys_kexec_load)
- cond_syscall(sys_init_module)
- cond_syscall(sys_delete_module)
- cond_syscall(sys_socketpair)
-@@ -454,6 +456,27 @@ asmlinkage long sys_reboot(int magic1, i
-               machine_restart(buffer);
-               break;
-+#ifdef CONFIG_KEXEC
-+      case LINUX_REBOOT_CMD_KEXEC:
-+      {
-+              struct kimage *image;
-+              if (arg) {
-+                      unlock_kernel();
-+                      return -EINVAL;
-+              }
-+              image = xchg(&kexec_image, 0);
-+              if (!image) {
-+                      unlock_kernel();
-+                      return -EINVAL;
-+              }
-+              notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
-+              system_running = 0;
-+              device_shutdown();
-+              printk(KERN_EMERG "Starting new kernel\n");
-+              machine_kexec(image);
-+              break;
-+      }
-+#endif
- #ifdef CONFIG_SOFTWARE_SUSPEND
-       case LINUX_REBOOT_CMD_SW_SUSPEND:
-               if (!software_suspend_enabled) {
-
-_