From: Geoff Levand <geoff@infradead.org>
To: Catalin Marinas <catalin.marinas@arm.com>
Cc: marc.zyngier@arm.com, Will Deacon <will.deacon@arm.com>,
kexec@lists.infradead.org, Vivek Goyal <vgoyal@redhat.com>,
christoffer.dall@linaro.org,
linux-arm-kernel@lists.infradead.org
Subject: [PATCH V2 6/7] arm64/kexec: Add core kexec support
Date: Tue, 30 Sep 2014 16:59:25 -0700 [thread overview]
Message-ID: <1412121565.6630.64.camel@smoke> (raw)
In-Reply-To: <471af24b7de659a30a5941e793634bffec380cb9.1411604443.git.geoff@infradead.org>
Add three new files, kexec.h, machine_kexec.c and relocate_kernel.S to the
arm64 architecture that add support for the kexec re-boot mechanism
(CONFIG_KEXEC) on arm64 platforms.
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
V2:
o Add comment about soft_restart().
o Fold kexec_list_walk() and flush callback into kexec_list_flush().
o Add arm64_ prefix to global variables.
arch/arm64/Kconfig | 9 ++
arch/arm64/include/asm/kexec.h | 47 +++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/machine_kexec.c | 171 +++++++++++++++++++++++++++++++++
arch/arm64/kernel/relocate_kernel.S | 184 ++++++++++++++++++++++++++++++++++++
include/uapi/linux/kexec.h | 1 +
6 files changed, 413 insertions(+)
create mode 100644 arch/arm64/include/asm/kexec.h
create mode 100644 arch/arm64/kernel/machine_kexec.c
create mode 100644 arch/arm64/kernel/relocate_kernel.S
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f0d3a2d..af03449 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -313,6 +313,15 @@ config ARCH_HAS_CACHE_LINE_SIZE
source "mm/Kconfig"
+config KEXEC
+ depends on (!SMP || PM_SLEEP_SMP)
+ bool "kexec system call"
+ ---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.
+
config XEN_DOM0
def_bool y
depends on XEN
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
new file mode 100644
index 0000000..e7bd7ab
--- /dev/null
+++ b/arch/arm64/include/asm/kexec.h
@@ -0,0 +1,47 @@
+/*
+ * kexec for arm64
+ *
+ * Copyright (C) Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#if !defined(_ARM64_KEXEC_H)
+#define _ARM64_KEXEC_H
+
+/* 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_ARM64
+
+#if !defined(__ASSEMBLY__)
+
+/**
+ * crash_setup_regs() - save registers for the panic kernel
+ *
+ * @newregs: registers are saved here
+ * @oldregs: registers to be saved (may be %NULL)
+ */
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+ struct pt_regs *oldregs)
+{
+ /* Empty routine needed to avoid build errors. */
+}
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 6e9538c..77a7351 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -30,6 +30,7 @@ arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
+arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
new file mode 100644
index 0000000..8924bb0
--- /dev/null
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -0,0 +1,171 @@
+/*
+ * kexec for arm64
+ *
+ * Copyright (C) Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kexec.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
+#include <asm/system_misc.h>
+
+/* Global variables for the relocate_kernel routine. */
+
+extern const unsigned char relocate_new_kernel[];
+extern const unsigned long relocate_new_kernel_size;
+extern unsigned long arm64_kexec_dtb_addr;
+extern unsigned long arm64_kexec_kimage_head;
+extern unsigned long arm64_kexec_kimage_start;
+
+/**
+ * kexec_is_dtb - Helper routine to check the device tree header signature.
+ */
+
+static bool kexec_is_dtb(const void *dtb)
+{
+ __be32 magic;
+
+ return get_user(magic, (__be32 *)dtb) ? false :
+ (be32_to_cpu(magic) == OF_DT_HEADER);
+}
+
+/**
+ * kexec_find_dtb_seg - Helper routine to find the dtb segment.
+ */
+
+static const struct kexec_segment *kexec_find_dtb_seg(
+ const struct kimage *image)
+{
+ int i;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ if (kexec_is_dtb(image->segment[i].buf))
+ return &image->segment[i];
+ }
+
+ return NULL;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ /* Empty routine needed to avoid build errors. */
+}
+
+/**
+ * machine_kexec_prepare - Prepare for a kexec reboot.
+ *
+ * Called from the core kexec code when a kernel image is loaded.
+ */
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ const struct kexec_segment *dtb_seg;
+
+ dtb_seg = kexec_find_dtb_seg(image);
+
+ if (!dtb_seg)
+ return -EINVAL;
+
+ arm64_kexec_dtb_addr = dtb_seg->mem;
+ arm64_kexec_kimage_start = image->start;
+
+ return 0;
+}
+
+/**
+ * kexec_list_flush - Helper to flush the kimage list to PoC.
+ */
+
+static void kexec_list_flush(unsigned long kimage_head)
+{
+ void *dest;
+ unsigned long *entry;
+
+ for (entry = &kimage_head, dest = NULL; ; entry++) {
+ unsigned int flag = *entry &
+ (IND_DESTINATION | IND_INDIRECTION | IND_DONE |
+ IND_SOURCE);
+ void *addr = phys_to_virt(*entry & PAGE_MASK);
+
+ switch (flag) {
+ case IND_INDIRECTION:
+ entry = (unsigned long *)addr - 1;
+ __flush_dcache_area(addr, PAGE_SIZE);
+ break;
+ case IND_DESTINATION:
+ dest = addr;
+ break;
+ case IND_SOURCE:
+ __flush_dcache_area(addr, PAGE_SIZE);
+ dest += PAGE_SIZE;
+ break;
+ case IND_DONE:
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * machine_kexec - Do the kexec reboot.
+ *
+ * Called from the core kexec code for a sys_reboot with LINUX_REBOOT_CMD_KEXEC.
+ */
+
+void machine_kexec(struct kimage *image)
+{
+ phys_addr_t reboot_code_buffer_phys;
+ void *reboot_code_buffer;
+
+ BUG_ON(num_online_cpus() > 1);
+
+ arm64_kexec_kimage_head = image->head;
+
+ reboot_code_buffer_phys = page_to_phys(image->control_code_page);
+ reboot_code_buffer = phys_to_virt(reboot_code_buffer_phys);
+
+ /*
+ * Copy relocate_new_kernel to the reboot_code_buffer for use
+ * after the kernel is shut down.
+ */
+
+ memcpy(reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ /* Flush the reboot_code_buffer in preparation for its execution. */
+
+ __flush_dcache_area(reboot_code_buffer, relocate_new_kernel_size);
+
+ /* Flush the kimage list. */
+
+ kexec_list_flush(image->head);
+
+ pr_info("Bye!\n");
+
+ /* Disable all DAIF exceptions. */
+
+ asm volatile ("msr daifset, #0xf" : : : "memory");
+
+ /*
+ * soft_restart() will shutdown the MMU, disable data caches, then
+ * transfer control to the reboot_code_buffer which contains a copy of
+ * the relocate_new_kernel routine. relocate_new_kernel will use
+ * physical addressing to relocate the new kernel to its final position
+ * and then will transfer control to the entry point of the new kernel.
+ */
+
+ soft_restart(reboot_code_buffer_phys);
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /* Empty routine needed to avoid build errors. */
+}
diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
new file mode 100644
index 0000000..ac68322
--- /dev/null
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -0,0 +1,184 @@
+/*
+ * kexec for arm64
+ *
+ * Copyright (C) Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/assembler.h>
+#include <asm/kexec.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+#include <asm/proc-macros.S>
+
+/* The list entry flags. */
+
+#define IND_DESTINATION_BIT 0
+#define IND_INDIRECTION_BIT 1
+#define IND_DONE_BIT 2
+#define IND_SOURCE_BIT 3
+
+/*
+ * relocate_new_kernel - Put the 2nd stage kernel image in place and boot it.
+ *
+ * The memory that the old kernel occupies may be overwritten when coping the
+ * new kernel to its final location. To assure that the relocate_new_kernel
+ * routine which does that copy is not overwritten all code and data needed
+ * by relocate_new_kernel must be between the symbols relocate_new_kernel and
+ * relocate_new_kernel_end. The machine_kexec() routine will copy
+ * relocate_new_kernel to the kexec control_code_page, a special page which
+ * has been set up to be preserved during the kernel copy operation.
+ */
+
+.globl relocate_new_kernel
+relocate_new_kernel:
+
+ /* Setup the list loop variables. */
+
+ ldr x18, arm64_kexec_kimage_head /* x18 = list entry */
+ dcache_line_size x17, x0 /* x17 = dcache line size */
+ mov x16, xzr /* x16 = segment start */
+ mov x15, xzr /* x15 = entry ptr */
+ mov x14, xzr /* x14 = copy dest */
+
+ /* Check if the new kernel needs relocation. */
+
+ cbz x18, .Ldone
+ tbnz x18, IND_DONE_BIT, .Ldone
+
+.Lloop:
+ and x13, x18, PAGE_MASK /* x13 = addr */
+
+ /* Test the entry flags. */
+
+.Ltest_source:
+ tbz x18, IND_SOURCE_BIT, .Ltest_indirection
+
+ /* copy_page(x20 = dest, x21 = src) */
+
+ mov x20, x14
+ mov x21, x13
+
+1: ldp x22, x23, [x21]
+ ldp x24, x25, [x21, #16]
+ ldp x26, x27, [x21, #32]
+ ldp x28, x29, [x21, #48]
+ add x21, x21, #64
+ stnp x22, x23, [x20]
+ stnp x24, x25, [x20, #16]
+ stnp x26, x27, [x20, #32]
+ stnp x28, x29, [x20, #48]
+ add x20, x20, #64
+ tst x21, #(PAGE_SIZE - 1)
+ b.ne 1b
+
+ /* dest += PAGE_SIZE */
+
+ add x14, x14, PAGE_SIZE
+ b .Lnext
+
+.Ltest_indirection:
+ tbz x18, IND_INDIRECTION_BIT, .Ltest_destination
+
+ /* ptr = addr */
+
+ mov x15, x13
+ b .Lnext
+
+.Ltest_destination:
+ tbz x18, IND_DESTINATION_BIT, .Lnext
+
+ /* flush segment */
+
+ bl .Lflush
+ mov x16, x13
+
+ /* dest = addr */
+
+ mov x14, x13
+
+.Lnext:
+ /* entry = *ptr++ */
+
+ ldr x18, [x15], #8
+
+ /* while (!(entry & DONE)) */
+
+ tbz x18, IND_DONE_BIT, .Lloop
+
+.Ldone:
+ /* flush last segment */
+
+ bl .Lflush
+
+ dsb sy
+ isb
+ ic ialluis
+ dsb sy
+ isb
+
+ /* start_new_kernel */
+
+ ldr x4, arm64_kexec_kimage_start
+ ldr x0, arm64_kexec_dtb_addr
+ mov x1, xzr
+ mov x2, xzr
+ mov x3, xzr
+ br x4
+
+/* flush - x17 = line size, x16 = start addr, x14 = end addr. */
+
+.Lflush:
+ cbz x16, 2f
+ mov x0, x16
+ sub x1, x17, #1
+ bic x0, x0, x1
+1: dc civac, x0
+ add x0, x0, x17
+ cmp x0, x14
+ b.lo 1b
+2: ret
+
+.align 3 /* To keep the 64-bit values below naturally aligned. */
+
+/* The machine_kexec routines set these variables. */
+
+/*
+ * arm64_kexec_dtb_addr - Physical address of the new kernel's device tree.
+ */
+
+.globl arm64_kexec_dtb_addr
+arm64_kexec_dtb_addr:
+ .quad 0x0
+
+/*
+ * arm64_kexec_kimage_head - Copy of image->head, the list of kimage entries.
+ */
+
+.globl arm64_kexec_kimage_head
+arm64_kexec_kimage_head:
+ .quad 0x0
+
+/*
+ * arm64_kexec_kimage_start - Copy of image->start, the entry point of the new
+ * kernel.
+ */
+
+.globl arm64_kexec_kimage_start
+arm64_kexec_kimage_start:
+ .quad 0x0
+
+.Lrelocate_new_kernel_end:
+
+/*
+ * relocate_new_kernel_size - Number of bytes to copy to the control_code_page.
+ */
+
+.globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .quad .Lrelocate_new_kernel_end - relocate_new_kernel
+
+.org KEXEC_CONTROL_PAGE_SIZE
diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
index 6925f5b..04626b9 100644
--- a/include/uapi/linux/kexec.h
+++ b/include/uapi/linux/kexec.h
@@ -39,6 +39,7 @@
#define KEXEC_ARCH_SH (42 << 16)
#define KEXEC_ARCH_MIPS_LE (10 << 16)
#define KEXEC_ARCH_MIPS ( 8 << 16)
+#define KEXEC_ARCH_ARM64 (183 << 16)
/* The artificial cap on the number of segments passed to kexec_load. */
#define KEXEC_SEGMENT_MAX 16
--
1.9.1
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
WARNING: multiple messages have this Message-ID (diff)
From: geoff@infradead.org (Geoff Levand)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH V2 6/7] arm64/kexec: Add core kexec support
Date: Tue, 30 Sep 2014 16:59:25 -0700 [thread overview]
Message-ID: <1412121565.6630.64.camel@smoke> (raw)
In-Reply-To: <471af24b7de659a30a5941e793634bffec380cb9.1411604443.git.geoff@infradead.org>
Add three new files, kexec.h, machine_kexec.c and relocate_kernel.S to the
arm64 architecture that add support for the kexec re-boot mechanism
(CONFIG_KEXEC) on arm64 platforms.
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
V2:
o Add comment about soft_restart().
o Fold kexec_list_walk() and flush callback into kexec_list_flush().
o Add arm64_ prefix to global variables.
arch/arm64/Kconfig | 9 ++
arch/arm64/include/asm/kexec.h | 47 +++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/machine_kexec.c | 171 +++++++++++++++++++++++++++++++++
arch/arm64/kernel/relocate_kernel.S | 184 ++++++++++++++++++++++++++++++++++++
include/uapi/linux/kexec.h | 1 +
6 files changed, 413 insertions(+)
create mode 100644 arch/arm64/include/asm/kexec.h
create mode 100644 arch/arm64/kernel/machine_kexec.c
create mode 100644 arch/arm64/kernel/relocate_kernel.S
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f0d3a2d..af03449 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -313,6 +313,15 @@ config ARCH_HAS_CACHE_LINE_SIZE
source "mm/Kconfig"
+config KEXEC
+ depends on (!SMP || PM_SLEEP_SMP)
+ bool "kexec system call"
+ ---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.
+
config XEN_DOM0
def_bool y
depends on XEN
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
new file mode 100644
index 0000000..e7bd7ab
--- /dev/null
+++ b/arch/arm64/include/asm/kexec.h
@@ -0,0 +1,47 @@
+/*
+ * kexec for arm64
+ *
+ * Copyright (C) Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#if !defined(_ARM64_KEXEC_H)
+#define _ARM64_KEXEC_H
+
+/* 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_ARM64
+
+#if !defined(__ASSEMBLY__)
+
+/**
+ * crash_setup_regs() - save registers for the panic kernel
+ *
+ * @newregs: registers are saved here
+ * @oldregs: registers to be saved (may be %NULL)
+ */
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+ struct pt_regs *oldregs)
+{
+ /* Empty routine needed to avoid build errors. */
+}
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 6e9538c..77a7351 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -30,6 +30,7 @@ arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
+arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
new file mode 100644
index 0000000..8924bb0
--- /dev/null
+++ b/arch/arm64/kernel/machine_kexec.c
@@ -0,0 +1,171 @@
+/*
+ * kexec for arm64
+ *
+ * Copyright (C) Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kexec.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
+#include <asm/system_misc.h>
+
+/* Global variables for the relocate_kernel routine. */
+
+extern const unsigned char relocate_new_kernel[];
+extern const unsigned long relocate_new_kernel_size;
+extern unsigned long arm64_kexec_dtb_addr;
+extern unsigned long arm64_kexec_kimage_head;
+extern unsigned long arm64_kexec_kimage_start;
+
+/**
+ * kexec_is_dtb - Helper routine to check the device tree header signature.
+ */
+
+static bool kexec_is_dtb(const void *dtb)
+{
+ __be32 magic;
+
+ return get_user(magic, (__be32 *)dtb) ? false :
+ (be32_to_cpu(magic) == OF_DT_HEADER);
+}
+
+/**
+ * kexec_find_dtb_seg - Helper routine to find the dtb segment.
+ */
+
+static const struct kexec_segment *kexec_find_dtb_seg(
+ const struct kimage *image)
+{
+ int i;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ if (kexec_is_dtb(image->segment[i].buf))
+ return &image->segment[i];
+ }
+
+ return NULL;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ /* Empty routine needed to avoid build errors. */
+}
+
+/**
+ * machine_kexec_prepare - Prepare for a kexec reboot.
+ *
+ * Called from the core kexec code when a kernel image is loaded.
+ */
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ const struct kexec_segment *dtb_seg;
+
+ dtb_seg = kexec_find_dtb_seg(image);
+
+ if (!dtb_seg)
+ return -EINVAL;
+
+ arm64_kexec_dtb_addr = dtb_seg->mem;
+ arm64_kexec_kimage_start = image->start;
+
+ return 0;
+}
+
+/**
+ * kexec_list_flush - Helper to flush the kimage list to PoC.
+ */
+
+static void kexec_list_flush(unsigned long kimage_head)
+{
+ void *dest;
+ unsigned long *entry;
+
+ for (entry = &kimage_head, dest = NULL; ; entry++) {
+ unsigned int flag = *entry &
+ (IND_DESTINATION | IND_INDIRECTION | IND_DONE |
+ IND_SOURCE);
+ void *addr = phys_to_virt(*entry & PAGE_MASK);
+
+ switch (flag) {
+ case IND_INDIRECTION:
+ entry = (unsigned long *)addr - 1;
+ __flush_dcache_area(addr, PAGE_SIZE);
+ break;
+ case IND_DESTINATION:
+ dest = addr;
+ break;
+ case IND_SOURCE:
+ __flush_dcache_area(addr, PAGE_SIZE);
+ dest += PAGE_SIZE;
+ break;
+ case IND_DONE:
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * machine_kexec - Do the kexec reboot.
+ *
+ * Called from the core kexec code for a sys_reboot with LINUX_REBOOT_CMD_KEXEC.
+ */
+
+void machine_kexec(struct kimage *image)
+{
+ phys_addr_t reboot_code_buffer_phys;
+ void *reboot_code_buffer;
+
+ BUG_ON(num_online_cpus() > 1);
+
+ arm64_kexec_kimage_head = image->head;
+
+ reboot_code_buffer_phys = page_to_phys(image->control_code_page);
+ reboot_code_buffer = phys_to_virt(reboot_code_buffer_phys);
+
+ /*
+ * Copy relocate_new_kernel to the reboot_code_buffer for use
+ * after the kernel is shut down.
+ */
+
+ memcpy(reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ /* Flush the reboot_code_buffer in preparation for its execution. */
+
+ __flush_dcache_area(reboot_code_buffer, relocate_new_kernel_size);
+
+ /* Flush the kimage list. */
+
+ kexec_list_flush(image->head);
+
+ pr_info("Bye!\n");
+
+ /* Disable all DAIF exceptions. */
+
+ asm volatile ("msr daifset, #0xf" : : : "memory");
+
+ /*
+ * soft_restart() will shutdown the MMU, disable data caches, then
+ * transfer control to the reboot_code_buffer which contains a copy of
+ * the relocate_new_kernel routine. relocate_new_kernel will use
+ * physical addressing to relocate the new kernel to its final position
+ * and then will transfer control to the entry point of the new kernel.
+ */
+
+ soft_restart(reboot_code_buffer_phys);
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /* Empty routine needed to avoid build errors. */
+}
diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
new file mode 100644
index 0000000..ac68322
--- /dev/null
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -0,0 +1,184 @@
+/*
+ * kexec for arm64
+ *
+ * Copyright (C) Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/assembler.h>
+#include <asm/kexec.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+#include <asm/proc-macros.S>
+
+/* The list entry flags. */
+
+#define IND_DESTINATION_BIT 0
+#define IND_INDIRECTION_BIT 1
+#define IND_DONE_BIT 2
+#define IND_SOURCE_BIT 3
+
+/*
+ * relocate_new_kernel - Put the 2nd stage kernel image in place and boot it.
+ *
+ * The memory that the old kernel occupies may be overwritten when coping the
+ * new kernel to its final location. To assure that the relocate_new_kernel
+ * routine which does that copy is not overwritten all code and data needed
+ * by relocate_new_kernel must be between the symbols relocate_new_kernel and
+ * relocate_new_kernel_end. The machine_kexec() routine will copy
+ * relocate_new_kernel to the kexec control_code_page, a special page which
+ * has been set up to be preserved during the kernel copy operation.
+ */
+
+.globl relocate_new_kernel
+relocate_new_kernel:
+
+ /* Setup the list loop variables. */
+
+ ldr x18, arm64_kexec_kimage_head /* x18 = list entry */
+ dcache_line_size x17, x0 /* x17 = dcache line size */
+ mov x16, xzr /* x16 = segment start */
+ mov x15, xzr /* x15 = entry ptr */
+ mov x14, xzr /* x14 = copy dest */
+
+ /* Check if the new kernel needs relocation. */
+
+ cbz x18, .Ldone
+ tbnz x18, IND_DONE_BIT, .Ldone
+
+.Lloop:
+ and x13, x18, PAGE_MASK /* x13 = addr */
+
+ /* Test the entry flags. */
+
+.Ltest_source:
+ tbz x18, IND_SOURCE_BIT, .Ltest_indirection
+
+ /* copy_page(x20 = dest, x21 = src) */
+
+ mov x20, x14
+ mov x21, x13
+
+1: ldp x22, x23, [x21]
+ ldp x24, x25, [x21, #16]
+ ldp x26, x27, [x21, #32]
+ ldp x28, x29, [x21, #48]
+ add x21, x21, #64
+ stnp x22, x23, [x20]
+ stnp x24, x25, [x20, #16]
+ stnp x26, x27, [x20, #32]
+ stnp x28, x29, [x20, #48]
+ add x20, x20, #64
+ tst x21, #(PAGE_SIZE - 1)
+ b.ne 1b
+
+ /* dest += PAGE_SIZE */
+
+ add x14, x14, PAGE_SIZE
+ b .Lnext
+
+.Ltest_indirection:
+ tbz x18, IND_INDIRECTION_BIT, .Ltest_destination
+
+ /* ptr = addr */
+
+ mov x15, x13
+ b .Lnext
+
+.Ltest_destination:
+ tbz x18, IND_DESTINATION_BIT, .Lnext
+
+ /* flush segment */
+
+ bl .Lflush
+ mov x16, x13
+
+ /* dest = addr */
+
+ mov x14, x13
+
+.Lnext:
+ /* entry = *ptr++ */
+
+ ldr x18, [x15], #8
+
+ /* while (!(entry & DONE)) */
+
+ tbz x18, IND_DONE_BIT, .Lloop
+
+.Ldone:
+ /* flush last segment */
+
+ bl .Lflush
+
+ dsb sy
+ isb
+ ic ialluis
+ dsb sy
+ isb
+
+ /* start_new_kernel */
+
+ ldr x4, arm64_kexec_kimage_start
+ ldr x0, arm64_kexec_dtb_addr
+ mov x1, xzr
+ mov x2, xzr
+ mov x3, xzr
+ br x4
+
+/* flush - x17 = line size, x16 = start addr, x14 = end addr. */
+
+.Lflush:
+ cbz x16, 2f
+ mov x0, x16
+ sub x1, x17, #1
+ bic x0, x0, x1
+1: dc civac, x0
+ add x0, x0, x17
+ cmp x0, x14
+ b.lo 1b
+2: ret
+
+.align 3 /* To keep the 64-bit values below naturally aligned. */
+
+/* The machine_kexec routines set these variables. */
+
+/*
+ * arm64_kexec_dtb_addr - Physical address of the new kernel's device tree.
+ */
+
+.globl arm64_kexec_dtb_addr
+arm64_kexec_dtb_addr:
+ .quad 0x0
+
+/*
+ * arm64_kexec_kimage_head - Copy of image->head, the list of kimage entries.
+ */
+
+.globl arm64_kexec_kimage_head
+arm64_kexec_kimage_head:
+ .quad 0x0
+
+/*
+ * arm64_kexec_kimage_start - Copy of image->start, the entry point of the new
+ * kernel.
+ */
+
+.globl arm64_kexec_kimage_start
+arm64_kexec_kimage_start:
+ .quad 0x0
+
+.Lrelocate_new_kernel_end:
+
+/*
+ * relocate_new_kernel_size - Number of bytes to copy to the control_code_page.
+ */
+
+.globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .quad .Lrelocate_new_kernel_end - relocate_new_kernel
+
+.org KEXEC_CONTROL_PAGE_SIZE
diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
index 6925f5b..04626b9 100644
--- a/include/uapi/linux/kexec.h
+++ b/include/uapi/linux/kexec.h
@@ -39,6 +39,7 @@
#define KEXEC_ARCH_SH (42 << 16)
#define KEXEC_ARCH_MIPS_LE (10 << 16)
#define KEXEC_ARCH_MIPS ( 8 << 16)
+#define KEXEC_ARCH_ARM64 (183 << 16)
/* The artificial cap on the number of segments passed to kexec_load. */
#define KEXEC_SEGMENT_MAX 16
--
1.9.1
next prev parent reply other threads:[~2014-09-30 23:59 UTC|newest]
Thread overview: 130+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-25 0:23 [PATCH 0/7] arm64 kexec kernel patches V3 Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-25 0:23 ` [PATCH 1/7] arm64/kvm: Fix assembler compatibility of macros Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-10-03 10:26 ` Mark Rutland
2014-10-03 10:26 ` Mark Rutland
2014-10-03 22:27 ` Geoff Levand
2014-10-03 22:27 ` Geoff Levand
2014-10-06 10:10 ` Mark Rutland
2014-10-06 10:10 ` Mark Rutland
2014-09-25 0:23 ` [PATCH 3/7] arm64: Add new hcall HVC_CALL_FUNC Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-25 0:23 ` [PATCH 4/7] arm64: Add EL2 switch to soft_restart Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-25 0:23 ` [PATCH 2/7] arm64: Convert hcalls to use ISS field Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-10-03 10:51 ` Mark Rutland
2014-10-03 10:51 ` Mark Rutland
2014-10-03 21:56 ` Geoff Levand
2014-10-03 21:56 ` Geoff Levand
2014-10-06 10:13 ` Mark Rutland
2014-10-06 10:13 ` Mark Rutland
2014-09-25 0:23 ` [PATCH 5/7] arm64: Move proc-macros.S to include/asm Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-25 0:23 ` [PATCH 6/7] arm64/kexec: Add core kexec support Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-25 18:28 ` Vivek Goyal
2014-09-25 18:28 ` Vivek Goyal
2014-09-25 19:02 ` Geoff Levand
2014-09-25 19:02 ` Geoff Levand
2014-09-25 19:08 ` Vivek Goyal
2014-09-25 19:08 ` Vivek Goyal
2014-09-30 18:18 ` Vivek Goyal
2014-09-30 18:18 ` Vivek Goyal
2014-09-30 19:54 ` Geoff Levand
2014-09-30 19:54 ` Geoff Levand
2014-10-01 14:56 ` Vivek Goyal
2014-10-01 14:56 ` Vivek Goyal
2014-10-03 18:35 ` Geoff Levand
2014-10-03 18:35 ` Geoff Levand
2014-10-07 13:44 ` Vivek Goyal
2014-10-07 13:44 ` Vivek Goyal
2014-10-07 18:42 ` Geoff Levand
2014-10-07 18:42 ` Geoff Levand
2014-10-07 18:45 ` Vivek Goyal
2014-10-07 18:45 ` Vivek Goyal
2014-10-07 20:12 ` Geoff Levand
2014-10-07 20:12 ` Geoff Levand
2014-10-07 20:22 ` Vivek Goyal
2014-10-07 20:22 ` Vivek Goyal
2014-10-09 22:26 ` Geoff Levand
2014-10-09 22:26 ` Geoff Levand
2014-10-23 23:08 ` Geoff Levand
2014-10-23 23:08 ` Geoff Levand
2014-10-08 9:28 ` Mark Rutland
2014-10-08 9:28 ` Mark Rutland
2014-10-07 18:48 ` Vivek Goyal
2014-10-07 18:48 ` Vivek Goyal
2014-10-01 16:16 ` Mark Rutland
2014-10-01 16:16 ` Mark Rutland
2014-10-01 17:36 ` Vivek Goyal
2014-10-01 17:36 ` Vivek Goyal
2014-10-01 17:56 ` Mark Rutland
2014-10-01 17:56 ` Mark Rutland
2014-10-01 17:47 ` Vivek Goyal
2014-10-01 17:47 ` Vivek Goyal
2014-10-01 18:03 ` Mark Rutland
2014-10-01 18:03 ` Mark Rutland
2014-10-01 18:09 ` Vivek Goyal
2014-10-01 18:09 ` Vivek Goyal
2014-10-01 18:19 ` Mark Rutland
2014-10-01 18:19 ` Mark Rutland
2014-10-01 18:31 ` Vivek Goyal
2014-10-01 18:31 ` Vivek Goyal
2014-10-01 19:22 ` Vivek Goyal
2014-10-01 19:22 ` Vivek Goyal
2014-10-02 10:26 ` Mark Rutland
2014-10-02 10:26 ` Mark Rutland
2014-10-02 13:54 ` Vivek Goyal
2014-10-02 13:54 ` Vivek Goyal
2014-10-02 16:53 ` Mark Rutland
2014-10-02 16:53 ` Mark Rutland
2014-09-30 23:59 ` Geoff Levand [this message]
2014-09-30 23:59 ` [PATCH V2 " Geoff Levand
2014-09-25 0:23 ` [PATCH 7/7] arm64/kexec: Enable kexec in the arm64 defconfig Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-30 20:29 ` [PATCH 0/7] arm64 kexec kernel patches V3 Vivek Goyal
2014-09-30 20:29 ` Vivek Goyal
2014-09-30 21:27 ` Geoff Levand
2014-09-30 21:27 ` Geoff Levand
2014-10-02 19:08 ` Vivek Goyal
2014-10-02 19:08 ` Vivek Goyal
2014-10-02 22:59 ` Geoff Levand
2014-10-02 22:59 ` Geoff Levand
2014-10-07 13:43 ` Vivek Goyal
2014-10-07 13:43 ` Vivek Goyal
2014-10-07 14:06 ` Mark Rutland
2014-10-07 14:06 ` Mark Rutland
2014-10-01 15:19 ` Vivek Goyal
2014-10-01 15:19 ` Vivek Goyal
2014-10-03 21:16 ` Geoff Levand
2014-10-03 21:16 ` Geoff Levand
2014-10-07 13:40 ` Vivek Goyal
2014-10-07 13:40 ` Vivek Goyal
2014-10-07 18:29 ` Geoff Levand
2014-10-07 18:29 ` Geoff Levand
2014-10-08 9:42 ` Mark Rutland
2014-10-08 9:42 ` Mark Rutland
2014-10-09 3:21 ` Dave Young
2014-10-09 3:21 ` Dave Young
2014-10-09 10:09 ` Mark Rutland
2014-10-09 10:09 ` Mark Rutland
2014-10-09 10:19 ` Ard Biesheuvel
2014-10-09 10:19 ` Ard Biesheuvel
2014-10-10 5:30 ` Dave Young
2014-10-10 5:30 ` Dave Young
2014-10-07 15:22 ` Mark Rutland
2014-10-07 15:22 ` Mark Rutland
2014-10-07 18:28 ` Geoff Levand
2014-10-07 18:28 ` Geoff Levand
2014-10-07 18:09 ` Vivek Goyal
2014-10-07 18:09 ` Vivek Goyal
2014-10-07 20:07 ` Geoff Levand
2014-10-07 20:07 ` Geoff Levand
2014-10-08 9:52 ` Leif Lindholm
2014-10-08 9:52 ` Leif Lindholm
2014-10-08 10:07 ` Mark Rutland
2014-10-08 10:07 ` Mark Rutland
2014-10-09 9:22 ` Will Deacon
2014-10-09 9:22 ` Will Deacon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1412121565.6630.64.camel@smoke \
--to=geoff@infradead.org \
--cc=catalin.marinas@arm.com \
--cc=christoffer.dall@linaro.org \
--cc=kexec@lists.infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=marc.zyngier@arm.com \
--cc=vgoyal@redhat.com \
--cc=will.deacon@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.