Signed-off-by: Geert Uytterhoeven <ge...@linux-m68k.org>
---
 arch/m68k/Kconfig                  |   17 ++++++++
 arch/m68k/include/asm/kexec.h      |   29 +++++++++++++
 arch/m68k/kernel/Makefile          |    2 +
 arch/m68k/kernel/machine_kexec.c   |   71 ++++++++++++++++++++++++++++++++
 arch/m68k/kernel/relocate_kernel.S |   79 ++++++++++++++++++++++++++++++++++++
 include/uapi/linux/kexec.h         |    1 +
 6 files changed, 199 insertions(+)
 create mode 100644 arch/m68k/include/asm/kexec.h
 create mode 100644 arch/m68k/kernel/machine_kexec.c
 create mode 100644 arch/m68k/kernel/relocate_kernel.S

diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 311a300..d60497f 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -86,6 +86,23 @@ config MMU_SUN3
        bool
        depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE
 
+config KEXEC
+       bool "kexec system call"
+       depends on MMU # FIXME
+       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 independent of the system firmware.   And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         The name comes from the similarity 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.  As of this writing the exact hardware
+         interface is strongly in flux, so no good recommendation can be
+         made.
+
 menu "Platform setup"
 
 source arch/m68k/Kconfig.cpu
diff --git a/arch/m68k/include/asm/kexec.h b/arch/m68k/include/asm/kexec.h
new file mode 100644
index 0000000..3df97ab
--- /dev/null
+++ b/arch/m68k/include/asm/kexec.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_M68K_KEXEC_H
+#define _ASM_M68K_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+
+/* 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)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
+
+#define KEXEC_CONTROL_PAGE_SIZE        4096
+
+#define KEXEC_ARCH KEXEC_ARCH_68K
+
+#ifndef __ASSEMBLY__
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+                                   struct pt_regs *oldregs)
+{
+       /* Dummy implementation for now */
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_KEXEC */
+
+#endif /* _ASM_M68K_KEXEC_H */
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 655347d..7ee5f00 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -22,3 +22,5 @@ obj-$(CONFIG_PCI) += pcibios.o
 
 obj-$(CONFIG_HAS_DMA)  += dma.o
 
+obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
+
diff --git a/arch/m68k/kernel/machine_kexec.c b/arch/m68k/kernel/machine_kexec.c
new file mode 100644
index 0000000..c775da3
--- /dev/null
+++ b/arch/m68k/kernel/machine_kexec.c
@@ -0,0 +1,71 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ */
+#include <linux/compiler.h>
+#include <linux/kexec.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+
+extern const unsigned char relocate_new_kernel[];
+extern const size_t relocate_new_kernel_size;
+
+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)
+{
+}
+
+typedef void (*relocate_kernel_t)(unsigned long ptr,
+                                 unsigned long start) __noreturn;
+
+void machine_kexec(struct kimage *image)
+{
+       void *reboot_code_buffer;
+       unsigned long kexec_indirection_page;
+
+       unsigned long entry;
+       unsigned long *ptr;
+
+       reboot_code_buffer = page_address(image->control_code_page);
+
+       memcpy(reboot_code_buffer, relocate_new_kernel,
+              relocate_new_kernel_size);
+
+       /*
+        * The generic kexec code builds a page list with physical
+        * addresses, while we need virtual addresses
+        */
+       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 = (unsigned long) phys_to_virt(*ptr);
+       }
+
+       kexec_indirection_page = image->head & PAGE_MASK;
+
+       /*
+        * we do not want to be bothered.
+        */
+       local_irq_disable();
+
+       pr_info("Will call new kernel at 0x%08lx. Bye...\n", image->start);
+       __flush_cache_all();
+       ((relocate_kernel_t) reboot_code_buffer)(kexec_indirection_page,
+                                                image->start);
+}
diff --git a/arch/m68k/kernel/relocate_kernel.S 
b/arch/m68k/kernel/relocate_kernel.S
new file mode 100644
index 0000000..8d45d9c
--- /dev/null
+++ b/arch/m68k/kernel/relocate_kernel.S
@@ -0,0 +1,79 @@
+#include <linux/linkage.h>
+
+#include <asm/page.h>
+
+
+.globl relocate_new_kernel
+
+.text
+ENTRY(relocate_new_kernel)
+       moveq #0,%d0
+       .chip 68040     /* FIXME */
+       /* Disable MMU */
+       /* FIXME Keep caches enabled? */
+       movec %d0,%tc
+       movec %d0,%itt0
+       movec %d0,%itt1
+       movec %d0,%dtt0
+       movec %d0,%dtt1
+       .chip 68k
+
+       movel 4(%sp),%a0                /* a0 = ptr */
+       movel 8(%sp),%a1                /* a1 = start */
+       movew #PAGE_MASK,%d2            /* d2 = PAGE_MASK */
+
+1:
+       movel (%a0)+,%d0                /* d0 = entry = *ptr */
+       jeq 5f
+
+       btst #2,%d0                     /* entry & IND_DONE? */
+       jne 5f
+
+       btst #1,%d0                     /* entry & IND_INDIRECTION? */
+       jeq 2f
+       andw %d2,%d0
+       movel %d0,%a0                   /* ptr = entry & PAGE_MASK */
+       bra 1b
+
+2:
+       btst #0,%d0                     /* entry & IND_DESTINATION? */
+       jeq 3f
+       andw %d2,%d0
+       movel %d0,%a2                   /* a2 = dst = entry & PAGE_MASK */
+       bra 1b
+
+3:
+       btst #3,%d0                     /* entry & IND_SOURCE? */
+       jeq 1b
+
+       andw %d2,%d0
+       movel %d0,%a3                   /* a3 = src = entry & PAGE_MASK */
+       movew #PAGE_SIZE/32 - 1,%d0     /* d0 = PAGE_SIZE/32 - 1 */
+4:
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       movel (%a3)+,(%a2)+             /* *dst++ = *src++ */
+       dbf %d0, 4b
+       bra 1b
+
+5:
+       .chip 68040     /* FIXME */
+       /* Flush all caches */
+       nop
+       cpusha %bc
+       nop
+       cinva %bc
+       nop
+       .chip 68k
+
+       jmp (%a1)
+
+relocate_new_kernel_end:
+
+ENTRY(relocate_new_kernel_size)
+       .long relocate_new_kernel_end - relocate_new_kernel
diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
index 104838f..d6629d4 100644
--- a/include/uapi/linux/kexec.h
+++ b/include/uapi/linux/kexec.h
@@ -18,6 +18,7 @@
  */
 #define KEXEC_ARCH_DEFAULT ( 0 << 16)
 #define KEXEC_ARCH_386     ( 3 << 16)
+#define KEXEC_ARCH_68K     ( 4 << 16)
 #define KEXEC_ARCH_X86_64  (62 << 16)
 #define KEXEC_ARCH_PPC     (20 << 16)
 #define KEXEC_ARCH_PPC64   (21 << 16)
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to