[MIPS] Add support for kexec
authorNicolas Schichan <nschichan@freebox.fr>
Wed, 18 Oct 2006 13:14:55 +0000 (15:14 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 30 Nov 2006 01:14:44 +0000 (01:14 +0000)
A tiny userland application loading the kernel and invoking kexec_load for
mips is available here:

http://chac.le-poulpe.net/~nico/kexec/kexec-2006-10-18.tar.gz

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/Kconfig
arch/mips/kernel/Makefile
arch/mips/kernel/machine_kexec.c [new file with mode: 0644]
arch/mips/kernel/relocate_kernel.S [new file with mode: 0644]
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
include/asm-mips/kexec.h [new file with mode: 0644]
include/linux/kexec.h

index 1443024b1c7c9ba2c688579d426ce18000584ffc..c0da0ffe8d573586ba8b752fd17977168882d47f 100644 (file)
@@ -766,6 +766,23 @@ config TOSHIBA_RBTX4938
 
 endchoice
 
+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 an ongoing 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.
+
 source "arch/mips/ddb5xxx/Kconfig"
 source "arch/mips/gt64120/ev64120/Kconfig"
 source "arch/mips/jazz/Kconfig"
index 6bfbbed0897e87f15b6f60950788499525750ba0..f35b739d0a123714ceaec378b88d5da334348154 100644 (file)
@@ -67,6 +67,8 @@ obj-$(CONFIG_64BIT)           += cpu-bugs64.o
 
 obj-$(CONFIG_I8253)            += i8253.o
 
+obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
+
 CFLAGS_cpu-bugs64.o    = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
 
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c
new file mode 100644 (file)
index 0000000..e0ad754
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * machine_kexec.c for kexec
+ * Created by <nschichan@corp.free.fr> on Thu Oct 12 15:15:06 2006
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/kexec.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned int relocate_new_kernel_size;
+
+extern unsigned long kexec_start_address;
+extern unsigned long kexec_indirection_page;
+
+int
+machine_kexec_prepare(struct kimage *kimage)
+{
+       return 0;
+}
+
+void
+machine_kexec_cleanup(struct kimage *kimage)
+{
+}
+
+void
+machine_shutdown(void)
+{
+}
+
+void
+machine_crash_shutdown(struct pt_regs *regs)
+{
+}
+
+void
+machine_kexec(struct kimage *image)
+{
+       unsigned long reboot_code_buffer;
+       unsigned long entry;
+       unsigned long *ptr;
+
+       reboot_code_buffer =
+         (unsigned long)page_address(image->control_code_page);
+
+       kexec_start_address = image->start;
+       kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK);
+
+       memcpy((void*)reboot_code_buffer, relocate_new_kernel,
+              relocate_new_kernel_size);
+
+       /*
+        * The generic kexec code builds a page list with physical
+        * addresses. they are directly accessible through KSEG0 (or
+        * CKSEG0 or XPHYS if on 64bit system), hence the
+        * pys_to_virt() call.
+        */
+       for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE);
+            ptr = (entry & IND_INDIRECTION) ?
+              phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
+               if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
+                   *ptr & IND_DESTINATION)
+                       *ptr = phys_to_virt(*ptr);
+       }
+
+       /*
+        * we do not want to be bothered.
+        */
+       local_irq_disable();
+
+       flush_icache_range(reboot_code_buffer,
+                          reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+
+       printk("Will call new kernel at %08x\n", image->start);
+       printk("Bye ...\n");
+       flush_cache_all();
+       ((void (*)(void))reboot_code_buffer)();
+}
diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..a3f0d00
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * relocate_kernel.S for kexec
+ * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/regdef.h>
+#include <asm/page.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+
+       .globl relocate_new_kernel
+relocate_new_kernel:
+
+       PTR_L   s0, kexec_indirection_page
+       PTR_L   s1, kexec_start_address
+
+process_entry:
+       PTR_L   s2, (s0)
+       PTR_ADD s0, s0, SZREG
+
+       /* destination page */
+       and     s3, s2, 0x1
+       beq     s3, zero, 1f
+       and     s4, s2, ~0x1    /* store destination addr in s4 */
+       move    a0, s4
+       b       process_entry
+
+1:
+       /* indirection page, update s0  */
+       and     s3, s2, 0x2
+       beq     s3, zero, 1f
+       and     s0, s2, ~0x2
+       b       process_entry
+
+1:
+       /* done page */
+       and     s3, s2, 0x4
+       beq     s3, zero, 1f
+       b       done
+1:
+       /* source page */
+       and     s3, s2, 0x8
+       beq     s3, zero, process_entry
+       and     s2, s2, ~0x8
+       li      s6, (1 << PAGE_SHIFT) / SZREG
+
+copy_word:
+       /* copy page word by word */
+       REG_L   s5, (s2)
+       REG_S   s5, (s4)
+       INT_ADD s4, s4, SZREG
+       INT_ADD s2, s2, SZREG
+       INT_SUB s6, s6, 1
+       beq     s6, zero, process_entry
+       b       copy_word
+       b       process_entry
+
+done:
+       /* jump to kexec_start_address */
+       j       s1
+
+       .globl kexec_start_address
+kexec_start_address:
+       .long   0x0
+
+       .globl kexec_indirection_page
+kexec_indirection_page:
+       .long   0x0
+
+relocate_new_kernel_end:
+
+       .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+       .long relocate_new_kernel_end - relocate_new_kernel
index a95f37de080eb563b600d0615d7e1cd62003ca07..7c0b3936ba447dbeb159828227ef26a3aa38d1d7 100644 (file)
@@ -653,7 +653,7 @@ einval:     li      v0, -EINVAL
        sys     sys_move_pages          6
        sys     sys_set_robust_list     2
        sys     sys_get_robust_list     3       /* 4310 */
-       sys     sys_ni_syscall          0
+       sys     sys_kexec_load          4
        sys     sys_getcpu              3
        sys     sys_epoll_pwait         6
        .endm
index 8fb0f60f657bfc469c94b35458e339563761c4a8..e569b846e9a380ff96e65507f6e13ec3d5f6e414 100644 (file)
@@ -468,6 +468,6 @@ sys_call_table:
        PTR     sys_move_pages
        PTR     sys_set_robust_list
        PTR     sys_get_robust_list
-       PTR     sys_ni_syscall                  /* 5270 */
+       PTR     sys_kexec_load                  /* 5270 */
        PTR     sys_getcpu
        PTR     sys_epoll_pwait
index 0da5ca2040ff96f0487ca1ce66783e852b50f87b..5b18f265d75b8449f8e7a474d07bdc0d0529ebcd 100644 (file)
@@ -394,6 +394,6 @@ EXPORT(sysn32_call_table)
        PTR     sys_move_pages
        PTR     compat_sys_set_robust_list
        PTR     compat_sys_get_robust_list
-       PTR     sys_ni_syscall
+       PTR     compat_sys_kexec_load
        PTR     sys_getcpu
        PTR     sys_epoll_pwait
index b9d00cae8b5f2f4c4db850f634ccbbc14370338e..e91379c1be1d79826b81ca48182444ec2ad6deca 100644 (file)
@@ -516,7 +516,7 @@ sys_call_table:
        PTR     compat_sys_move_pages
        PTR     compat_sys_set_robust_list
        PTR     compat_sys_get_robust_list      /* 4310 */
-       PTR     sys_ni_syscall
+       PTR     compat_sys_kexec_load
        PTR     sys_getcpu
        PTR     sys_epoll_pwait
        .size   sys_call_table,.-sys_call_table
diff --git a/include/asm-mips/kexec.h b/include/asm-mips/kexec.h
new file mode 100644 (file)
index 0000000..b25267e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * kexec.h for kexec
+ * Created by <nschichan@corp.free.fr> on Thu Oct 12 14:59:34 2006
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#ifndef _MIPS_KEXEC
+# define _MIPS_KEXEC
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000)
+ /* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000)
+
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_MIPS
+
+#define MAX_NOTE_BYTES 1024
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+                                   struct pt_regs *oldregs)
+{
+       /* Dummy implementation for now */
+}
+
+#endif /* !_MIPS_KEXEC */
index 6427949ddf9942fbf45f31a86663ecd6ba34edd1..a4ede62b339d360b7845933b913e11ac6084a157 100644 (file)
@@ -122,6 +122,8 @@ extern struct kimage *kexec_crash_image;
 #define KEXEC_ARCH_IA_64   (50 << 16)
 #define KEXEC_ARCH_S390    (22 << 16)
 #define KEXEC_ARCH_SH      (42 << 16)
+#define KEXEC_ARCH_MIPS_LE (10 << 16)
+#define KEXEC_ARCH_MIPS    ( 8 << 16)
 
 #define KEXEC_FLAGS    (KEXEC_ON_CRASH)  /* List of defined/legal kexec flags */