Hi Pingfan,
On Tuesday 25 October 2016 03:17 PM, Pingfan Liu wrote:
From: Pingfan Liu piliu@redhat.com
Fix Bug 925630 - kexec-tools: support for arm64 https://bugzilla.redhat.com/show_bug.cgi?id=925630 involves two things:
- back porting upstream code to enable the function of kexec-tools on arm64 patchset backported from upstream: commit abdfe97736f89d9bc73662b9134604b0229a599e commit 522df5f7217fda01ece3f6ac3e9987b0320c2bb0 commit 217bcc00c9309416a6c6cd0584196559d28a9259
- fix the arm related building issue by using autoreconf in spec file
Thanks for the update.
I noticed that koji build introduced new relocation and `kexec -l` failed with following error:
machine_apply_elf_rel: ERROR Unknown type: 275
I used following patch(also attached here) which resolved above error
https://patchwork.kernel.org/patch/9386541/
However, there was further relocation error for 261.
Fix for that is here(also attached) https://github.com/pratyushanand/kexec-tools/commit/3a3c61cb7f129936e5752d1c...
So, I think you should also add attached patches in this commit.
@pbrobinson: How can I know the gcc version used by koji build. I need to mention that in the commit log of my patch which I would send upstream. Moreover, with above additional two patches kexec-tools seems fine, but still fedora-kernel-arm64/devel (with fh_defconfig+kexec enabled) did not reboot on a seattle platform (Nothing after "Bye"). Will debug and come back on it.
~Pratyush
Signed-off-by: Pingfan Liu piliu@redhat.com
0001-kexec-Add-common-device-tree-routines.patch | 208 +++ 0002-arm64-Add-arm64-kexec-support.patch | 1407 ++++++++++++++++++++ ...-arm64-Add-support-for-binary-image-files.patch | 96 ++ kexec-tools.spec | 20 +- 4 files changed, 1726 insertions(+), 5 deletions(-) create mode 100644 0001-kexec-Add-common-device-tree-routines.patch create mode 100644 0002-arm64-Add-arm64-kexec-support.patch create mode 100644 0003-arm64-Add-support-for-binary-image-files.patch
diff --git a/0001-kexec-Add-common-device-tree-routines.patch b/0001-kexec-Add-common-device-tree-routines.patch new file mode 100644 index 0000000..87897f0 --- /dev/null +++ b/0001-kexec-Add-common-device-tree-routines.patch @@ -0,0 +1,208 @@ +From 217bcc00c9309416a6c6cd0584196559d28a9259 Mon Sep 17 00:00:00 2001 +From: Geoff Levand geoff@infradead.org +Date: Wed, 21 Sep 2016 18:14:25 +0000 +Subject: [PATCH 1/3] kexec: Add common device tree routines
+Common device tree routines that can be shared between all arches +that have device tree support.
+Signed-off-by: Geoff Levand geoff@infradead.org +Tested-By: Pratyush Anand panand@redhat.com +Tested-By: Matthias Brugger mbrugger@suse.com +Signed-off-by: Simon Horman horms@verge.net.au +---
- kexec/Makefile | 4 ++
- kexec/dt-ops.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- kexec/dt-ops.h | 13 ++++++
- 3 files changed, 162 insertions(+)
- create mode 100644 kexec/dt-ops.c
- create mode 100644 kexec/dt-ops.h
+diff --git a/kexec/Makefile b/kexec/Makefile +index e2aee84..cc3f08b 100644 +--- a/kexec/Makefile ++++ b/kexec/Makefile +@@ -73,6 +73,10 @@ dist += kexec/mem_regions.c kexec/mem_regions.h
- $(ARCH)_MEM_REGIONS =
- KEXEC_SRCS += $($(ARCH)_MEM_REGIONS)
++dist += kexec/dt-ops.c kexec/dt-ops.h ++$(ARCH)_DT_OPS = ++KEXEC_SRCS += $($(ARCH)_DT_OPS) ++
- include $(srcdir)/kexec/arch/alpha/Makefile
- include $(srcdir)/kexec/arch/arm/Makefile
- include $(srcdir)/kexec/arch/i386/Makefile
+diff --git a/kexec/dt-ops.c b/kexec/dt-ops.c +new file mode 100644 +index 0000000..915dbf5 +--- /dev/null ++++ b/kexec/dt-ops.c +@@ -0,0 +1,145 @@ ++#include <assert.h> ++#include <errno.h> ++#include <inttypes.h> ++#include <libfdt.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++#include "kexec.h" ++#include "dt-ops.h" ++ ++static const char n_chosen[] = "/chosen"; ++ ++static const char p_bootargs[] = "bootargs"; ++static const char p_initrd_start[] = "linux,initrd-start"; ++static const char p_initrd_end[] = "linux,initrd-end"; ++ ++int dtb_set_initrd(char **dtb, off_t *dtb_size, off_t start, off_t end) ++{ ++ int result; ++ uint64_t value; ++ ++ dbgprintf("%s: start %jd, end %jd, size %jd (%jd KiB)\n", ++ __func__, (intmax_t)start, (intmax_t)end, ++ (intmax_t)(end - start), ++ (intmax_t)(end - start) / 1024); ++ ++ value = cpu_to_fdt64(start); ++ ++ result = dtb_set_property(dtb, dtb_size, n_chosen, p_initrd_start, ++ &value, sizeof(value)); ++ ++ if (result) ++ return result; ++ ++ value = cpu_to_fdt64(end); ++ ++ result = dtb_set_property(dtb, dtb_size, n_chosen, p_initrd_end, ++ &value, sizeof(value)); ++ ++ if (result) { ++ dtb_delete_property(*dtb, n_chosen, p_initrd_start); ++ return result; ++ } ++ ++ return 0; ++} ++ ++int dtb_set_bootargs(char **dtb, off_t *dtb_size, const char *command_line) ++{ ++ return dtb_set_property(dtb, dtb_size, n_chosen, p_bootargs, ++ command_line, strlen(command_line) + 1); ++} ++ ++int dtb_set_property(char **dtb, off_t *dtb_size, const char *node, ++ const char *prop, const void *value, int value_len) ++{ ++ int result; ++ int nodeoffset; ++ void *new_dtb; ++ int new_size; ++ ++ value_len = FDT_TAGALIGN(value_len); ++ ++ new_size = FDT_TAGALIGN(*dtb_size + fdt_node_len(node) ++ + fdt_prop_len(prop, value_len)); ++ ++ new_dtb = malloc(new_size); ++ ++ if (!new_dtb) { ++ dbgprintf("%s: malloc failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ result = fdt_open_into(*dtb, new_dtb, new_size); ++ ++ if (result) { ++ dbgprintf("%s: fdt_open_into failed: %s\n", __func__, ++ fdt_strerror(result)); ++ goto on_error; ++ } ++ ++ nodeoffset = fdt_path_offset(new_dtb, node); ++ ++ if (nodeoffset == -FDT_ERR_NOTFOUND) { ++ result = fdt_add_subnode(new_dtb, nodeoffset, node); ++ ++ if (result) { ++ dbgprintf("%s: fdt_add_subnode failed: %s\n", __func__, ++ fdt_strerror(result)); ++ goto on_error; ++ } ++ } else if (nodeoffset < 0) { ++ dbgprintf("%s: fdt_path_offset failed: %s\n", __func__, ++ fdt_strerror(nodeoffset)); ++ goto on_error; ++ } ++ ++ result = fdt_setprop(new_dtb, nodeoffset, prop, value, value_len); ++ ++ if (result) { ++ dbgprintf("%s: fdt_setprop failed: %s\n", __func__, ++ fdt_strerror(result)); ++ goto on_error; ++ } ++ ++ /* ++ * Can't call free on dtb since dtb may have been mmaped by ++ * slurp_file(). ++ */ ++ ++ result = fdt_pack(new_dtb); ++ ++ if (result) ++ dbgprintf("%s: Unable to pack device tree: %s\n", __func__, ++ fdt_strerror(result)); ++ ++ *dtb = new_dtb; ++ *dtb_size = fdt_totalsize(*dtb); ++ ++ return 0; ++ ++on_error: ++ free(new_dtb); ++ return result; ++} ++ ++int dtb_delete_property(char *dtb, const char *node, const char *prop) ++{ ++ int result; ++ int nodeoffset = fdt_path_offset(dtb, node); ++ ++ if (nodeoffset < 0) { ++ dbgprintf("%s: fdt_path_offset failed: %s\n", __func__, ++ fdt_strerror(nodeoffset)); ++ return nodeoffset; ++ } ++ ++ result = fdt_delprop(dtb, nodeoffset, prop); ++ ++ if (result) ++ dbgprintf("%s: fdt_delprop failed: %s\n", __func__, ++ fdt_strerror(nodeoffset)); ++ ++ return result; ++} +diff --git a/kexec/dt-ops.h b/kexec/dt-ops.h +new file mode 100644 +index 0000000..e70d15d +--- /dev/null ++++ b/kexec/dt-ops.h +@@ -0,0 +1,13 @@ ++#if !defined(KEXEC_DT_OPS_H) ++#define KEXEC_DT_OPS_H ++ ++#include <sys/types.h> ++ ++int dtb_set_initrd(char **dtb, off_t *dtb_size, off_t start, off_t end); ++int dtb_set_bootargs(char **dtb, off_t *dtb_size, const char *command_line); ++int dtb_set_property(char **dtb, off_t *dtb_size, const char *node, ++ const char *prop, const void *value, int value_len); ++ ++int dtb_delete_property(char *dtb, const char *node, const char *prop); ++ ++#endif +-- +2.9.3
diff --git a/0002-arm64-Add-arm64-kexec-support.patch b/0002-arm64-Add-arm64-kexec-support.patch new file mode 100644 index 0000000..0c14b1b --- /dev/null +++ b/0002-arm64-Add-arm64-kexec-support.patch @@ -0,0 +1,1407 @@ +From 522df5f7217fda01ece3f6ac3e9987b0320c2bb0 Mon Sep 17 00:00:00 2001 +From: Geoff Levand geoff@infradead.org +Date: Wed, 21 Sep 2016 18:14:25 +0000 +Subject: [PATCH 2/3] arm64: Add arm64 kexec support
+Add kexec reboot support for ARM64 platforms.
+Signed-off-by: Geoff Levand geoff@infradead.org +Tested-By: Pratyush Anand panand@redhat.com +Tested-By: Matthias Brugger mbrugger@suse.com +Signed-off-by: Simon Horman horms@verge.net.au +---
- configure.ac | 3 +
- kexec/Makefile | 1 +
- kexec/arch/arm64/Makefile | 40 +++
- kexec/arch/arm64/crashdump-arm64.c | 21 ++
- kexec/arch/arm64/crashdump-arm64.h | 12 +
- kexec/arch/arm64/image-header.h | 146 ++++++++
- kexec/arch/arm64/include/arch/options.h | 39 ++
- kexec/arch/arm64/kexec-arm64.c | 615 ++++++++++++++++++++++++++++++++
- kexec/arch/arm64/kexec-arm64.h | 71 ++++
- kexec/arch/arm64/kexec-elf-arm64.c | 146 ++++++++
- kexec/arch/arm64/kexec-image-arm64.c | 41 +++
- kexec/kexec-syscall.h | 8 +-
- purgatory/Makefile | 1 +
- purgatory/arch/arm64/Makefile | 18 +
- purgatory/arch/arm64/entry.S | 51 +++
- purgatory/arch/arm64/purgatory-arm64.c | 19 +
- 16 files changed, 1230 insertions(+), 2 deletions(-)
- create mode 100644 kexec/arch/arm64/Makefile
- create mode 100644 kexec/arch/arm64/crashdump-arm64.c
- create mode 100644 kexec/arch/arm64/crashdump-arm64.h
- create mode 100644 kexec/arch/arm64/image-header.h
- create mode 100644 kexec/arch/arm64/include/arch/options.h
- create mode 100644 kexec/arch/arm64/kexec-arm64.c
- create mode 100644 kexec/arch/arm64/kexec-arm64.h
- create mode 100644 kexec/arch/arm64/kexec-elf-arm64.c
- create mode 100644 kexec/arch/arm64/kexec-image-arm64.c
- create mode 100644 purgatory/arch/arm64/Makefile
- create mode 100644 purgatory/arch/arm64/entry.S
- create mode 100644 purgatory/arch/arm64/purgatory-arm64.c
+diff --git a/configure.ac b/configure.ac +index 2bc5767..252b048 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -34,6 +34,9 @@ case $target_cpu in
ARCH="ppc64"SUBARCH="LE";;++ aarch64* ) ++ ARCH="arm64" ++ ;;
- arm* )
ARCH="arm";;+diff --git a/kexec/Makefile b/kexec/Makefile +index cc3f08b..39f365f 100644 +--- a/kexec/Makefile ++++ b/kexec/Makefile +@@ -79,6 +79,7 @@ KEXEC_SRCS += $($(ARCH)_DT_OPS)
- include $(srcdir)/kexec/arch/alpha/Makefile
- include $(srcdir)/kexec/arch/arm/Makefile
++include $(srcdir)/kexec/arch/arm64/Makefile
- include $(srcdir)/kexec/arch/i386/Makefile
- include $(srcdir)/kexec/arch/ia64/Makefile
- include $(srcdir)/kexec/arch/m68k/Makefile
+diff --git a/kexec/arch/arm64/Makefile b/kexec/arch/arm64/Makefile +new file mode 100644 +index 0000000..37414dc +--- /dev/null ++++ b/kexec/arch/arm64/Makefile +@@ -0,0 +1,40 @@ ++ ++arm64_FS2DT += kexec/fs2dt.c ++arm64_FS2DT_INCLUDE += -include $(srcdir)/kexec/arch/arm64/kexec-arm64.h \ ++ -include $(srcdir)/kexec/arch/arm64/crashdump-arm64.h ++ ++arm64_DT_OPS += kexec/dt-ops.c ++ ++arm64_CPPFLAGS += -I $(srcdir)/kexec/ ++ ++arm64_KEXEC_SRCS += \ ++ kexec/arch/arm64/kexec-arm64.c \ ++ kexec/arch/arm64/kexec-image-arm64.c \ ++ kexec/arch/arm64/kexec-elf-arm64.c \ ++ kexec/arch/arm64/crashdump-arm64.c ++ ++arm64_ARCH_REUSE_INITRD = ++arm64_ADD_SEGMENT = ++arm64_VIRT_TO_PHYS = ++arm64_PHYS_TO_VIRT = ++ ++dist += $(arm64_KEXEC_SRCS) \ ++ kexec/arch/arm64/Makefile \ ++ kexec/arch/arm64/kexec-arm64.h \ ++ kexec/arch/arm64/crashdump-arm64.h ++ ++ifdef HAVE_LIBFDT ++ ++LIBS += -lfdt ++ ++else ++ ++include $(srcdir)/kexec/libfdt/Makefile.libfdt ++ ++libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) ++ ++arm64_CPPFLAGS += -I$(srcdir)/kexec/libfdt ++ ++arm64_KEXEC_SRCS += $(libfdt_SRCS) ++ ++endif +diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c +new file mode 100644 +index 0000000..d2272c8 +--- /dev/null ++++ b/kexec/arch/arm64/crashdump-arm64.c +@@ -0,0 +1,21 @@ ++/* ++ * ARM64 crashdump. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include <errno.h> ++#include <linux/elf.h> ++ ++#include "kexec.h" ++#include "crashdump.h" ++#include "crashdump-arm64.h" ++#include "kexec-arm64.h" ++#include "kexec-elf.h" ++ ++struct memory_ranges usablemem_rgns = {}; ++ ++int is_crashkernel_mem_reserved(void) ++{ ++ return 0; ++} +diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h +new file mode 100644 +index 0000000..f33c7a2 +--- /dev/null ++++ b/kexec/arch/arm64/crashdump-arm64.h +@@ -0,0 +1,12 @@ ++/* ++ * ARM64 crashdump. ++ */ ++ ++#if !defined(CRASHDUMP_ARM64_H) ++#define CRASHDUMP_ARM64_H ++ ++#include "kexec.h" ++ ++extern struct memory_ranges usablemem_rgns; ++ ++#endif +diff --git a/kexec/arch/arm64/image-header.h b/kexec/arch/arm64/image-header.h +new file mode 100644 +index 0000000..158d411 +--- /dev/null ++++ b/kexec/arch/arm64/image-header.h +@@ -0,0 +1,146 @@ ++/* ++ * ARM64 binary image header. ++ */ ++ ++#if !defined(__ARM64_IMAGE_HEADER_H) ++#define __ARM64_IMAGE_HEADER_H ++ ++#include <endian.h> ++#include <stdint.h> ++ ++/** ++ * struct arm64_image_header - arm64 kernel image header. ++ * ++ * @pe_sig: Optional PE format 'MZ' signature. ++ * @branch_code: Reserved for instructions to branch to stext. ++ * @text_offset: The image load offset in LSB byte order. ++ * @image_size: An estimated size of the memory image size in LSB byte order. ++ * @flags: Bit flags in LSB byte order: ++ * Bit 0: Image byte order: 1=MSB. ++ * Bit 1-2: Kernel page size: 1=4K, 2=16K, 3=64K. ++ * Bit 3: Image placement: 0=low. ++ * @reserved_1: Reserved. ++ * @magic: Magic number, "ARM\x64". ++ * @pe_header: Optional offset to a PE format header. ++ **/ ++ ++struct arm64_image_header { ++ uint8_t pe_sig[2]; ++ uint16_t branch_code[3]; ++ uint64_t text_offset; ++ uint64_t image_size; ++ uint64_t flags; ++ uint64_t reserved_1[3]; ++ uint8_t magic[4]; ++ uint32_t pe_header; ++}; ++ ++static const uint8_t arm64_image_magic[4] = {'A', 'R', 'M', 0x64U}; ++static const uint8_t arm64_image_pe_sig[2] = {'M', 'Z'}; ++static const uint64_t arm64_image_flag_be = (1UL << 0); ++static const uint64_t arm64_image_flag_page_size = (3UL << 1); ++static const uint64_t arm64_image_flag_placement = (1UL << 3); ++ ++/** ++ * enum arm64_header_page_size ++ */ ++ ++enum arm64_header_page_size { ++ arm64_header_page_size_invalid = 0, ++ arm64_header_page_size_4k, ++ arm64_header_page_size_16k, ++ arm64_header_page_size_64k ++}; ++ ++/** ++ * arm64_header_check_magic - Helper to check the arm64 image header. ++ * ++ * Returns non-zero if header is OK. ++ */ ++ ++static inline int arm64_header_check_magic(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return (h->magic[0] == arm64_image_magic[0] ++ && h->magic[1] == arm64_image_magic[1] ++ && h->magic[2] == arm64_image_magic[2] ++ && h->magic[3] == arm64_image_magic[3]); ++} ++ ++/** ++ * arm64_header_check_pe_sig - Helper to check the arm64 image header. ++ * ++ * Returns non-zero if 'MZ' signature is found. ++ */ ++ ++static inline int arm64_header_check_pe_sig(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return (h->pe_sig[0] == arm64_image_pe_sig[0] ++ && h->pe_sig[1] == arm64_image_pe_sig[1]); ++} ++ ++/** ++ * arm64_header_check_msb - Helper to check the arm64 image header. ++ * ++ * Returns non-zero if the image was built as big endian. ++ */ ++ ++static inline int arm64_header_check_msb(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return (le64toh(h->flags) & arm64_image_flag_be) >> 0; ++} ++ ++/** ++ * arm64_header_page_size ++ */ ++ ++static inline enum arm64_header_page_size arm64_header_page_size( ++ const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return (le64toh(h->flags) & arm64_image_flag_page_size) >> 1; ++} ++ ++/** ++ * arm64_header_placement ++ * ++ * Returns non-zero if the image has no physical placement restrictions. ++ */ ++ ++static inline int arm64_header_placement(const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return (le64toh(h->flags) & arm64_image_flag_placement) >> 3; ++} ++ ++static inline uint64_t arm64_header_text_offset( ++ const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return le64toh(h->text_offset); ++} ++ ++static inline uint64_t arm64_header_image_size( ++ const struct arm64_image_header *h) ++{ ++ if (!h) ++ return 0; ++ ++ return le64toh(h->image_size); ++} ++ ++#endif +diff --git a/kexec/arch/arm64/include/arch/options.h b/kexec/arch/arm64/include/arch/options.h +new file mode 100644 +index 0000000..a17d933 +--- /dev/null ++++ b/kexec/arch/arm64/include/arch/options.h +@@ -0,0 +1,39 @@ ++#if !defined(KEXEC_ARCH_ARM64_OPTIONS_H) ++#define KEXEC_ARCH_ARM64_OPTIONS_H ++ ++#define OPT_APPEND ((OPT_MAX)+0) ++#define OPT_DTB ((OPT_MAX)+1) ++#define OPT_INITRD ((OPT_MAX)+2) ++#define OPT_REUSE_CMDLINE ((OPT_MAX)+3) ++#define OPT_ARCH_MAX ((OPT_MAX)+4) ++ ++#define KEXEC_ARCH_OPTIONS \ ++ KEXEC_OPTIONS \ ++ { "append", 1, NULL, OPT_APPEND }, \ ++ { "command-line", 1, NULL, OPT_APPEND }, \ ++ { "dtb", 1, NULL, OPT_DTB }, \ ++ { "initrd", 1, NULL, OPT_INITRD }, \ ++ { "ramdisk", 1, NULL, OPT_INITRD }, \ ++ { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ ++ ++#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR /* Only accept long arch options. */ ++#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS ++#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR ++ ++static const char arm64_opts_usage[] __attribute__ ((unused)) = ++" --append=STRING Set the kernel command line to STRING.\n" ++" --command-line=STRING Set the kernel command line to STRING.\n" ++" --dtb=FILE Use FILE as the device tree blob.\n" ++" --initrd=FILE Use FILE as the kernel initial ramdisk.\n" ++" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" ++" --reuse-cmdline Use kernel command line from running system.\n"; ++ ++struct arm64_opts { ++ const char *command_line; ++ const char *dtb; ++ const char *initrd; ++}; ++ ++extern struct arm64_opts arm64_opts; ++ ++#endif +diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c +new file mode 100644 +index 0000000..2e8839a +--- /dev/null ++++ b/kexec/arch/arm64/kexec-arm64.c +@@ -0,0 +1,615 @@ ++/* ++ * ARM64 kexec. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include <assert.h> ++#include <errno.h> ++#include <getopt.h> ++#include <inttypes.h> ++#include <libfdt.h> ++#include <limits.h> ++#include <stdlib.h> ++#include <sys/stat.h> ++#include <linux/elf-em.h> ++#include <elf.h> ++ ++#include "kexec.h" ++#include "kexec-arm64.h" ++#include "crashdump.h" ++#include "crashdump-arm64.h" ++#include "dt-ops.h" ++#include "fs2dt.h" ++#include "kexec-syscall.h" ++#include "arch/options.h" ++ ++/* Global varables the core kexec routines expect. */ ++ ++unsigned char reuse_initrd; ++ ++off_t initrd_base; ++off_t initrd_size; ++ ++const struct arch_map_entry arches[] = { ++ { "aarch64", KEXEC_ARCH_ARM64 }, ++ { "aarch64_be", KEXEC_ARCH_ARM64 }, ++ { NULL, 0 }, ++}; ++ ++struct file_type file_type[] = { ++ {"vmlinux", elf_arm64_probe, elf_arm64_load, elf_arm64_usage}, ++ {"Image", image_arm64_probe, image_arm64_load, image_arm64_usage}, ++}; ++ ++int file_types = sizeof(file_type) / sizeof(file_type[0]); ++ ++/* arm64 global varables. */ ++ ++struct arm64_opts arm64_opts; ++struct arm64_mem arm64_mem = { ++ .phys_offset = arm64_mem_ngv, ++ .vp_offset = arm64_mem_ngv, ++}; ++ ++uint64_t get_phys_offset(void) ++{ ++ assert(arm64_mem.phys_offset != arm64_mem_ngv); ++ return arm64_mem.phys_offset; ++} ++ ++uint64_t get_vp_offset(void) ++{ ++ assert(arm64_mem.vp_offset != arm64_mem_ngv); ++ return arm64_mem.vp_offset; ++} ++ ++/** ++ * arm64_process_image_header - Process the arm64 image header. ++ * ++ * Make a guess that KERNEL_IMAGE_SIZE will be enough for older kernels. ++ */ ++ ++int arm64_process_image_header(const struct arm64_image_header *h) ++{ ++#if !defined(KERNEL_IMAGE_SIZE) ++# define KERNEL_IMAGE_SIZE MiB(16) ++#endif ++ ++ if (!arm64_header_check_magic(h)) ++ return -EFAILED; ++ ++ if (h->image_size) { ++ arm64_mem.text_offset = arm64_header_text_offset(h); ++ arm64_mem.image_size = arm64_header_image_size(h); ++ } else { ++ /* For 3.16 and older kernels. */ ++ arm64_mem.text_offset = 0x80000; ++ arm64_mem.image_size = KERNEL_IMAGE_SIZE; ++ fprintf(stderr, ++ "kexec: %s: Warning: Kernel image size set to %lu MiB.\n" ++ " Please verify compatability with lodaed kernel.\n", ++ __func__, KERNEL_IMAGE_SIZE / 1024UL / 1024UL); ++ } ++ ++ return 0; ++} ++ ++void arch_usage(void) ++{ ++ printf(arm64_opts_usage); ++} ++ ++int arch_process_options(int argc, char **argv) ++{ ++ static const char short_options[] = KEXEC_OPT_STR ""; ++ static const struct option options[] = { ++ KEXEC_ARCH_OPTIONS ++ { 0 } ++ }; ++ int opt; ++ char *cmdline = NULL; ++ const char *append = NULL; ++ ++ for (opt = 0; opt != -1; ) { ++ opt = getopt_long(argc, argv, short_options, options, 0); ++ ++ switch (opt) { ++ case OPT_APPEND: ++ append = optarg; ++ break; ++ case OPT_REUSE_CMDLINE: ++ cmdline = get_command_line(); ++ break; ++ case OPT_DTB: ++ arm64_opts.dtb = optarg; ++ break; ++ case OPT_INITRD: ++ arm64_opts.initrd = optarg; ++ break; ++ case OPT_PANIC: ++ die("load-panic (-p) not supported"); ++ break; ++ default: ++ break; /* Ignore core and unknown options. */ ++ } ++ } ++ ++ arm64_opts.command_line = concat_cmdline(cmdline, append); ++ ++ dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, ++ arm64_opts.command_line); ++ dbgprintf("%s:%d: initrd: %s\n", __func__, __LINE__, ++ arm64_opts.initrd); ++ dbgprintf("%s:%d: dtb: %s\n", __func__, __LINE__, arm64_opts.dtb); ++ ++ return 0; ++} ++ ++/** ++ * struct dtb - Info about a binary device tree. ++ * ++ * @buf: Device tree data. ++ * @size: Device tree data size. ++ * @name: Shorthand name of this dtb for messages. ++ * @path: Filesystem path. ++ */ ++ ++struct dtb { ++ char *buf; ++ off_t size; ++ const char *name; ++ const char *path; ++}; ++ ++/** ++ * dump_reservemap - Dump the dtb's reservemap. ++ */ ++ ++static void dump_reservemap(const struct dtb *dtb) ++{ ++ int i; ++ ++ for (i = 0; ; i++) { ++ uint64_t address; ++ uint64_t size; ++ ++ fdt_get_mem_rsv(dtb->buf, i, &address, &size); ++ ++ if (!size) ++ break; ++ ++ dbgprintf("%s: %s {%" PRIx64 ", %" PRIx64 "}\n", __func__, ++ dtb->name, address, size); ++ } ++} ++ ++/** ++ * set_bootargs - Set the dtb's bootargs. ++ */ ++ ++static int set_bootargs(struct dtb *dtb, const char *command_line) ++{ ++ int result; ++ ++ if (!command_line || !command_line[0]) ++ return 0; ++ ++ result = dtb_set_bootargs(&dtb->buf, &dtb->size, command_line); ++ ++ if (result) { ++ fprintf(stderr, ++ "kexec: Set device tree bootargs failed.\n"); ++ return -EFAILED; ++ } ++ ++ return 0; ++} ++ ++/** ++ * read_proc_dtb - Read /proc/device-tree. ++ */ ++ ++static int read_proc_dtb(struct dtb *dtb) ++{ ++ int result; ++ struct stat s; ++ static const char path[] = "/proc/device-tree"; ++ ++ result = stat(path, &s); ++ ++ if (result) { ++ dbgprintf("%s: %s\n", __func__, strerror(errno)); ++ return -EFAILED; ++ } ++ ++ dtb->path = path; ++ create_flatten_tree((char **)&dtb->buf, &dtb->size, NULL); ++ ++ return 0; ++} ++ ++/** ++ * read_sys_dtb - Read /sys/firmware/fdt. ++ */ ++ ++static int read_sys_dtb(struct dtb *dtb) ++{ ++ int result; ++ struct stat s; ++ static const char path[] = "/sys/firmware/fdt"; ++ ++ result = stat(path, &s); ++ ++ if (result) { ++ dbgprintf("%s: %s\n", __func__, strerror(errno)); ++ return -EFAILED; ++ } ++ ++ dtb->path = path; ++ dtb->buf = slurp_file(path, &dtb->size); ++ ++ return 0; ++} ++ ++/** ++ * read_1st_dtb - Read the 1st stage kernel's dtb. ++ */ ++ ++static int read_1st_dtb(struct dtb *dtb) ++{ ++ int result; ++ ++ dtb->name = "dtb_sys"; ++ result = read_sys_dtb(dtb); ++ ++ if (!result) ++ goto on_success; ++ ++ dtb->name = "dtb_proc"; ++ result = read_proc_dtb(dtb); ++ ++ if (!result) ++ goto on_success; ++ ++ dbgprintf("%s: not found\n", __func__); ++ return -EFAILED; ++ ++on_success: ++ dbgprintf("%s: found %s\n", __func__, dtb->path); ++ return 0; ++} ++ ++/** ++ * setup_2nd_dtb - Setup the 2nd stage kernel's dtb. ++ */ ++ ++static int setup_2nd_dtb(struct dtb *dtb, char *command_line) ++{ ++ int result; ++ ++ result = fdt_check_header(dtb->buf); ++ ++ if (result) { ++ fprintf(stderr, "kexec: Invalid 2nd device tree.\n"); ++ return -EFAILED; ++ } ++ ++ result = set_bootargs(dtb, command_line); ++ ++ dump_reservemap(dtb); ++ ++ return result; ++} ++ ++unsigned long arm64_locate_kernel_segment(struct kexec_info *info) ++{ ++ unsigned long hole; ++ ++ hole = locate_hole(info, ++ arm64_mem.text_offset + arm64_mem.image_size, ++ MiB(2), 0, ULONG_MAX, 1); ++ ++ if (hole == ULONG_MAX) ++ dbgprintf("%s: locate_hole failed\n", __func__); ++ ++ return hole; ++} ++ ++/** ++ * arm64_load_other_segments - Prepare the dtb, initrd and purgatory segments. ++ */ ++ ++int arm64_load_other_segments(struct kexec_info *info, ++ unsigned long image_base) ++{ ++ int result; ++ unsigned long dtb_base; ++ unsigned long hole_min; ++ unsigned long hole_max; ++ char *initrd_buf = NULL; ++ struct dtb dtb; ++ char command_line[COMMAND_LINE_SIZE] = ""; ++ ++ if (arm64_opts.command_line) { ++ strncpy(command_line, arm64_opts.command_line, ++ sizeof(command_line)); ++ command_line[sizeof(command_line) - 1] = 0; ++ } ++ ++ if (arm64_opts.dtb) { ++ dtb.name = "dtb_user"; ++ dtb.buf = slurp_file(arm64_opts.dtb, &dtb.size); ++ } else { ++ result = read_1st_dtb(&dtb); ++ ++ if (result) { ++ fprintf(stderr, ++ "kexec: Error: No device tree available.\n"); ++ return -EFAILED; ++ } ++ } ++ ++ result = setup_2nd_dtb(&dtb, command_line); ++ ++ if (result) ++ return -EFAILED; ++ ++ /* Put the other segments after the image. */ ++ ++ hole_min = image_base + arm64_mem.image_size; ++ hole_max = ULONG_MAX; ++ ++ if (arm64_opts.initrd) { ++ initrd_buf = slurp_file(arm64_opts.initrd, &initrd_size); ++ ++ if (!initrd_buf) ++ fprintf(stderr, "kexec: Empty ramdisk file.\n"); ++ else { ++ /* ++ * Put the initrd after the kernel. As specified in ++ * booting.txt, align to 1 GiB. ++ */ ++ ++ initrd_base = add_buffer_phys_virt(info, initrd_buf, ++ initrd_size, initrd_size, GiB(1), ++ hole_min, hole_max, 1, 0); ++ ++ /* initrd_base is valid if we got here. */ ++ ++ dbgprintf("initrd: base %lx, size %lxh (%ld)\n", ++ initrd_base, initrd_size, initrd_size); ++ ++ /* Check size limit as specified in booting.txt. */ ++ ++ if (initrd_base - image_base + initrd_size > GiB(32)) { ++ fprintf(stderr, "kexec: Error: image + initrd too big.\n"); ++ return -EFAILED; ++ } ++ ++ result = dtb_set_initrd((char **)&dtb.buf, ++ &dtb.size, initrd_base, ++ initrd_base + initrd_size); ++ ++ if (result) ++ return -EFAILED; ++ } ++ } ++ ++ /* Check size limit as specified in booting.txt. */ ++ ++ if (dtb.size > MiB(2)) { ++ fprintf(stderr, "kexec: Error: dtb too big.\n"); ++ return -EFAILED; ++ } ++ ++ dtb_base = add_buffer_phys_virt(info, dtb.buf, dtb.size, dtb.size, ++ 0, hole_min, hole_max, 1, 0); ++ ++ /* dtb_base is valid if we got here. */ ++ ++ dbgprintf("dtb: base %lx, size %lxh (%ld)\n", dtb_base, dtb.size, ++ dtb.size); ++ ++ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, ++ hole_min, hole_max, 1, 0); ++ ++ info->entry = (void *)elf_rel_get_addr(&info->rhdr, "purgatory_start"); ++ ++ elf_rel_set_symbol(&info->rhdr, "arm64_kernel_entry", &image_base, ++ sizeof(image_base)); ++ ++ elf_rel_set_symbol(&info->rhdr, "arm64_dtb_addr", &dtb_base, ++ sizeof(dtb_base)); ++ ++ return 0; ++} ++ ++/** ++ * virt_to_phys - For processing elf file values. ++ */ ++ ++unsigned long virt_to_phys(unsigned long v) ++{ ++ unsigned long p; ++ ++ p = v - get_vp_offset() + get_phys_offset(); ++ ++ return p; ++} ++ ++/** ++ * phys_to_virt - For crashdump setup. ++ */ ++ ++unsigned long phys_to_virt(struct crash_elf_info *elf_info, ++ unsigned long long p) ++{ ++ unsigned long v; ++ ++ v = p - get_phys_offset() + elf_info->page_offset; ++ ++ return v; ++} ++ ++/** ++ * add_segment - Use virt_to_phys when loading elf files. ++ */ ++ ++void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, ++ unsigned long base, size_t memsz) ++{ ++ add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); ++} ++ ++/** ++ * get_memory_ranges_iomem_cb - Helper for get_memory_ranges_iomem. ++ */ ++ ++static int get_memory_ranges_iomem_cb(void *data, int nr, char *str, ++ unsigned long long base, unsigned long long length) ++{ ++ struct memory_range *r; ++ ++ if (nr >= KEXEC_SEGMENT_MAX) ++ return -1; ++ ++ r = (struct memory_range *)data + nr; ++ r->type = RANGE_RAM; ++ r->start = base; ++ r->end = base + length - 1; ++ ++ set_phys_offset(r->start); ++ ++ dbgprintf("%s: %016llx - %016llx : %s", __func__, r->start, ++ r->end, str); ++ ++ return 0; ++} ++ ++/** ++ * get_memory_ranges_iomem - Try to get the memory ranges from /proc/iomem. ++ */ ++ ++static int get_memory_ranges_iomem(struct memory_range *array, ++ unsigned int *count) ++{ ++ *count = kexec_iomem_for_each_line("System RAM\n", ++ get_memory_ranges_iomem_cb, array); ++ ++ if (!*count) { ++ dbgprintf("%s: failed: No RAM found.\n", __func__); ++ return -EFAILED; ++ } ++ ++ return 0; ++} ++ ++/** ++ * get_memory_ranges - Try to get the memory ranges some how. ++ */ ++ ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) ++{ ++ static struct memory_range array[KEXEC_SEGMENT_MAX]; ++ unsigned int count; ++ int result; ++ ++ result = get_memory_ranges_iomem(array, &count); ++ ++ *range = result ? NULL : array; ++ *ranges = result ? 0 : count; ++ ++ return result; ++} ++ ++int arch_compat_trampoline(struct kexec_info *info) ++{ ++ return 0; ++} ++ ++int machine_verify_elf_rel(struct mem_ehdr *ehdr) ++{ ++ return (ehdr->e_machine == EM_AARCH64); ++} ++ ++void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym), ++ unsigned long r_type, void *ptr, unsigned long address, ++ unsigned long value) ++{ ++#if !defined(R_AARCH64_ABS64) ++# define R_AARCH64_ABS64 257 ++#endif ++ ++#if !defined(R_AARCH64_LD_PREL_LO19) ++# define R_AARCH64_LD_PREL_LO19 273 ++#endif ++ ++#if !defined(R_AARCH64_ADR_PREL_LO21) ++# define R_AARCH64_ADR_PREL_LO21 274 ++#endif ++ ++#if !defined(R_AARCH64_JUMP26) ++# define R_AARCH64_JUMP26 282 ++#endif ++ ++#if !defined(R_AARCH64_CALL26) ++# define R_AARCH64_CALL26 283 ++#endif ++ ++ uint64_t *loc64; ++ uint32_t *loc32; ++ uint64_t *location = (uint64_t *)ptr; ++ uint64_t data = *location; ++ const char *type = NULL; ++ ++ switch(r_type) { ++ case R_AARCH64_ABS64: ++ type = "ABS64"; ++ loc64 = ptr; ++ *loc64 = cpu_to_elf64(ehdr, elf64_to_cpu(ehdr, *loc64) + value); ++ break; ++ case R_AARCH64_LD_PREL_LO19: ++ type = "LD_PREL_LO19"; ++ loc32 = ptr; ++ *loc32 = cpu_to_le32(le32_to_cpu(*loc32) ++ + (((value - address) << 3) & 0xffffe0)); ++ break; ++ case R_AARCH64_ADR_PREL_LO21: ++ if (value & 3) ++ die("%s: ERROR Unaligned value: %lx\n", __func__, ++ value); ++ type = "ADR_PREL_LO21"; ++ loc32 = ptr; ++ *loc32 = cpu_to_le32(le32_to_cpu(*loc32) ++ + (((value - address) << 3) & 0xffffe0)); ++ break; ++ case R_AARCH64_JUMP26: ++ type = "JUMP26"; ++ loc32 = ptr; ++ *loc32 = cpu_to_le32(le32_to_cpu(*loc32) ++ + (((value - address) >> 2) & 0x3ffffff)); ++ break; ++ case R_AARCH64_CALL26: ++ type = "CALL26"; ++ loc32 = ptr; ++ *loc32 = cpu_to_le32(le32_to_cpu(*loc32) ++ + (((value - address) >> 2) & 0x3ffffff)); ++ break; ++ default: ++ die("%s: ERROR Unknown type: %lu\n", __func__, r_type); ++ break; ++ } ++ ++ dbgprintf("%s: %s %016lx->%016lx\n", __func__, type, data, *location); ++} ++ ++void arch_reuse_initrd(void) ++{ ++ reuse_initrd = 1; ++} ++ ++void arch_update_purgatory(struct kexec_info *UNUSED(info)) ++{ ++} +diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h +new file mode 100644 +index 0000000..bac62f8 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-arm64.h +@@ -0,0 +1,71 @@ ++/* ++ * ARM64 kexec. ++ */ ++ ++#if !defined(KEXEC_ARM64_H) ++#define KEXEC_ARM64_H ++ ++#include <stdbool.h> ++#include <sys/types.h> ++ ++#include "image-header.h" ++#include "kexec.h" ++ ++#define KEXEC_SEGMENT_MAX 16 ++ ++#define BOOT_BLOCK_VERSION 17 ++#define BOOT_BLOCK_LAST_COMP_VERSION 16 ++#define COMMAND_LINE_SIZE 512 ++ ++#define KiB(x) ((x) * 1024UL) ++#define MiB(x) (KiB(x) * 1024UL) ++#define GiB(x) (MiB(x) * 1024UL) ++ ++int elf_arm64_probe(const char *kernel_buf, off_t kernel_size); ++int elf_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info); ++void elf_arm64_usage(void); ++ ++int image_arm64_probe(const char *kernel_buf, off_t kernel_size); ++int image_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info); ++void image_arm64_usage(void); ++ ++off_t initrd_base; ++off_t initrd_size; ++ ++/** ++ * struct arm64_mem - Memory layout info. ++ */ ++ ++struct arm64_mem { ++ uint64_t phys_offset; ++ uint64_t text_offset; ++ uint64_t image_size; ++ uint64_t vp_offset; ++}; ++ ++#define arm64_mem_ngv UINT64_MAX ++struct arm64_mem arm64_mem; ++ ++uint64_t get_phys_offset(void); ++uint64_t get_vp_offset(void); ++ ++static inline void reset_vp_offset(void) ++{ ++ arm64_mem.vp_offset = arm64_mem_ngv; ++} ++ ++static inline void set_phys_offset(uint64_t v) ++{ ++ if (arm64_mem.phys_offset == arm64_mem_ngv ++ || v < arm64_mem.phys_offset) ++ arm64_mem.phys_offset = v; ++} ++ ++int arm64_process_image_header(const struct arm64_image_header *h); ++unsigned long arm64_locate_kernel_segment(struct kexec_info *info); ++int arm64_load_other_segments(struct kexec_info *info, ++ unsigned long image_base); ++ ++#endif +diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c +new file mode 100644 +index 0000000..daf8bf0 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-elf-arm64.c +@@ -0,0 +1,146 @@ ++/* ++ * ARM64 kexec elf support. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include <errno.h> ++#include <limits.h> ++#include <stdlib.h> ++#include <linux/elf.h> ++ ++#include "kexec-arm64.h" ++#include "kexec-elf.h" ++#include "kexec-syscall.h" ++ ++int elf_arm64_probe(const char *kernel_buf, off_t kernel_size) ++{ ++ struct mem_ehdr ehdr; ++ int result; ++ ++ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); ++ ++ if (result < 0) { ++ dbgprintf("%s: Not an ELF executable.\n", __func__); ++ goto on_exit; ++ } ++ ++ if (ehdr.e_machine != EM_AARCH64) { ++ dbgprintf("%s: Not an AARCH64 ELF executable.\n", __func__); ++ result = -1; ++ goto on_exit; ++ } ++ ++ result = 0; ++on_exit: ++ free_elf_info(&ehdr); ++ return result; ++} ++ ++int elf_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info) ++{ ++ const struct arm64_image_header *header = NULL; ++ unsigned long kernel_segment; ++ struct mem_ehdr ehdr; ++ int result; ++ int i; ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ fprintf(stderr, "kexec: kdump not yet supported on arm64\n"); ++ return -EFAILED; ++ } ++ ++ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); ++ ++ if (result < 0) { ++ dbgprintf("%s: build_elf_exec_info failed\n", __func__); ++ goto exit; ++ } ++ ++ /* Find and process the arm64 image header. */ ++ ++ for (i = 0; i < ehdr.e_phnum; i++) { ++ struct mem_phdr *phdr = &ehdr.e_phdr[i]; ++ unsigned long header_offset; ++ ++ if (phdr->p_type != PT_LOAD) ++ continue; ++ ++ /* ++ * When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image header ++ * could be offset in the elf segment. The linker script sets ++ * ehdr.e_entry to the start of text. ++ */ ++ ++ header_offset = ehdr.e_entry - phdr->p_vaddr; ++ ++ header = (const struct arm64_image_header *)( ++ kernel_buf + phdr->p_offset + header_offset); ++ ++ if (!arm64_process_image_header(header)) { ++ dbgprintf("%s: e_entry: %016llx\n", __func__, ++ ehdr.e_entry); ++ dbgprintf("%s: p_vaddr: %016llx\n", __func__, ++ phdr->p_vaddr); ++ dbgprintf("%s: header_offset: %016lx\n", __func__, ++ header_offset); ++ ++ break; ++ } ++ } ++ ++ if (i == ehdr.e_phnum) { ++ dbgprintf("%s: Valid arm64 header not found\n", __func__); ++ result = -EFAILED; ++ goto exit; ++ } ++ ++ kernel_segment = arm64_locate_kernel_segment(info); ++ ++ if (kernel_segment == ULONG_MAX) { ++ dbgprintf("%s: Kernel segment is not allocated\n", __func__); ++ result = -EFAILED; ++ goto exit; ++ } ++ ++ arm64_mem.vp_offset = _ALIGN_DOWN(ehdr.e_entry, MiB(2)); ++ arm64_mem.vp_offset -= kernel_segment - get_phys_offset(); ++ ++ dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); ++ dbgprintf("%s: text_offset: %016lx\n", __func__, ++ arm64_mem.text_offset); ++ dbgprintf("%s: image_size: %016lx\n", __func__, ++ arm64_mem.image_size); ++ dbgprintf("%s: phys_offset: %016lx\n", __func__, ++ arm64_mem.phys_offset); ++ dbgprintf("%s: vp_offset: %016lx\n", __func__, ++ arm64_mem.vp_offset); ++ dbgprintf("%s: PE format: %s\n", __func__, ++ (arm64_header_check_pe_sig(header) ? "yes" : "no")); ++ ++ /* load the kernel */ ++ result = elf_exec_load(&ehdr, info); ++ ++ if (result) { ++ dbgprintf("%s: elf_exec_load failed\n", __func__); ++ goto exit; ++ } ++ ++ result = arm64_load_other_segments(info, kernel_segment ++ + arm64_mem.text_offset); ++ ++exit: ++ reset_vp_offset(); ++ free_elf_info(&ehdr); ++ if (result) ++ fprintf(stderr, "kexec: Bad elf image file, load failed.\n"); ++ return result; ++} ++ ++void elf_arm64_usage(void) ++{ ++ printf( ++" An ARM64 ELF image, big or little endian.\n" ++" Typically vmlinux or a stripped version of vmlinux.\n\n"); ++} +diff --git a/kexec/arch/arm64/kexec-image-arm64.c b/kexec/arch/arm64/kexec-image-arm64.c +new file mode 100644 +index 0000000..42d2ea7 +--- /dev/null ++++ b/kexec/arch/arm64/kexec-image-arm64.c +@@ -0,0 +1,41 @@ ++/* ++ * ARM64 kexec binary image support. ++ */ ++ ++#define _GNU_SOURCE ++#include "kexec-arm64.h" ++ ++int image_arm64_probe(const char *kernel_buf, off_t kernel_size) ++{ ++ const struct arm64_image_header *h; ++ ++ if (kernel_size < sizeof(struct arm64_image_header)) { ++ dbgprintf("%s: No arm64 image header.\n", __func__); ++ return -1; ++ } ++ ++ h = (const struct arm64_image_header *)(kernel_buf); ++ ++ if (!arm64_header_check_magic(h)) { ++ dbgprintf("%s: Bad arm64 image header.\n", __func__); ++ return -1; ++ } ++ ++ fprintf(stderr, "kexec: ARM64 binary image files are currently NOT SUPPORTED.\n"); ++ return -1; ++} ++ ++int image_arm64_load(int argc, char **argv, const char *kernel_buf, ++ off_t kernel_size, struct kexec_info *info) ++{ ++ return -1; ++} ++ ++void image_arm64_usage(void) ++{ ++ printf( ++" An ARM64 binary image, compressed or not, big or little endian.\n" ++" Typically an Image, Image.gz or Image.lzma file.\n\n"); ++ printf( ++" ARM64 binary image files are currently NOT SUPPORTED.\n\n"); ++} +diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h +index ce2e20b..c0d0bea 100644 +--- a/kexec/kexec-syscall.h ++++ b/kexec/kexec-syscall.h +@@ -39,8 +39,8 @@
- #ifdef __s390__
- #define __NR_kexec_load 277
- #endif
+-#ifdef __arm__ +-#define __NR_kexec_load __NR_SYSCALL_BASE + 347 ++#if defined(__arm__) || defined(__arm64__) ++#define __NR_kexec_load __NR_SYSCALL_BASE + 347
- #endif
- #if defined(__mips__)
- #define __NR_kexec_load 4311
+@@ -108,6 +108,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
- #define KEXEC_ARCH_PPC64 (21 << 16)
- #define KEXEC_ARCH_IA_64 (50 << 16)
- #define KEXEC_ARCH_ARM (40 << 16)
++#define KEXEC_ARCH_ARM64 (183 << 16)
- #define KEXEC_ARCH_S390 (22 << 16)
- #define KEXEC_ARCH_SH (42 << 16)
- #define KEXEC_ARCH_MIPS_LE (10 << 16)
+@@ -153,5 +154,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
- #ifdef __m68k__
- #define KEXEC_ARCH_NATIVE KEXEC_ARCH_68K
- #endif
++#if defined(__arm64__) ++#define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 ++#endif
- #endif /* KEXEC_SYSCALL_H */
+diff --git a/purgatory/Makefile b/purgatory/Makefile +index 2b5c061..ca0443c 100644 +--- a/purgatory/Makefile ++++ b/purgatory/Makefile +@@ -19,6 +19,7 @@ dist += purgatory/Makefile $(PURGATORY_SRCS) \
- include $(srcdir)/purgatory/arch/alpha/Makefile
- include $(srcdir)/purgatory/arch/arm/Makefile
++include $(srcdir)/purgatory/arch/arm64/Makefile
- include $(srcdir)/purgatory/arch/i386/Makefile
- include $(srcdir)/purgatory/arch/ia64/Makefile
- include $(srcdir)/purgatory/arch/mips/Makefile
+diff --git a/purgatory/arch/arm64/Makefile b/purgatory/arch/arm64/Makefile +new file mode 100644 +index 0000000..636abea +--- /dev/null ++++ b/purgatory/arch/arm64/Makefile +@@ -0,0 +1,18 @@ ++ ++arm64_PURGATORY_EXTRA_CFLAGS = \ ++ -mcmodel=large \ ++ -fno-stack-protector \ ++ -fno-asynchronous-unwind-tables \ ++ -Wundef \ ++ -Werror-implicit-function-declaration \ ++ -Wdeclaration-after-statement \ ++ -Werror=implicit-int \ ++ -Werror=strict-prototypes ++ ++arm64_PURGATORY_SRCS += \ ++ purgatory/arch/arm64/entry.S \ ++ purgatory/arch/arm64/purgatory-arm64.c ++ ++dist += \ ++ $(arm64_PURGATORY_SRCS) \ ++ purgatory/arch/arm64/Makefile +diff --git a/purgatory/arch/arm64/entry.S b/purgatory/arch/arm64/entry.S +new file mode 100644 +index 0000000..adf16f4 +--- /dev/null ++++ b/purgatory/arch/arm64/entry.S +@@ -0,0 +1,51 @@ ++/* ++ * ARM64 purgatory. ++ */ ++ ++.macro size, sym:req ++ .size \sym, . - \sym ++.endm ++ ++.text ++ ++.globl purgatory_start ++purgatory_start: ++ ++ adr x19, .Lstack ++ mov sp, x19 ++ ++ bl purgatory ++ ++ /* Start new image. */ ++ ldr x17, arm64_kernel_entry ++ ldr x0, arm64_dtb_addr ++ mov x1, xzr ++ mov x2, xzr ++ mov x3, xzr ++ br x17 ++ ++size purgatory_start ++ ++.ltorg ++ ++.align 4 ++ .rept 256 ++ .quad 0 ++ .endr ++.Lstack: ++ ++.data ++ ++.align 3 ++ ++.globl arm64_kernel_entry ++arm64_kernel_entry: ++ .quad 0 ++size arm64_kernel_entry ++ ++.globl arm64_dtb_addr ++arm64_dtb_addr: ++ .quad 0 ++size arm64_dtb_addr ++ ++.end +\ No newline at end of file +diff --git a/purgatory/arch/arm64/purgatory-arm64.c b/purgatory/arch/arm64/purgatory-arm64.c +new file mode 100644 +index 0000000..fe50fcf +--- /dev/null ++++ b/purgatory/arch/arm64/purgatory-arm64.c +@@ -0,0 +1,19 @@ ++/* ++ * ARM64 purgatory. ++ */ ++ ++#include <stdint.h> ++#include <purgatory.h> ++ ++void putchar(int ch) ++{ ++ /* Nothing for now */ ++} ++ ++void post_verification_setup_arch(void) ++{ ++} ++ ++void setup_arch(void) ++{ ++} +-- +2.9.3
diff --git a/0003-arm64-Add-support-for-binary-image-files.patch b/0003-arm64-Add-support-for-binary-image-files.patch new file mode 100644 index 0000000..8e8dde0 --- /dev/null +++ b/0003-arm64-Add-support-for-binary-image-files.patch @@ -0,0 +1,96 @@ +From abdfe97736f89d9bc73662b9134604b0229a599e Mon Sep 17 00:00:00 2001 +From: Pratyush Anand panand@redhat.com +Date: Wed, 21 Sep 2016 18:14:25 +0000 +Subject: [PATCH 3/3] arm64: Add support for binary image files
+Signed-off-by: Pratyush Anand panand@redhat.com +[Reworked and cleaned up] +Signed-off-by: Geoff Levand geoff@infradead.org +Tested-By: Pratyush Anand panand@redhat.com +Tested-By: Matthias Brugger mbrugger@suse.com +Signed-off-by: Simon Horman horms@verge.net.au +---
- kexec/arch/arm64/kexec-image-arm64.c | 49 ++++++++++++++++++++++++++++++++----
- 1 file changed, 44 insertions(+), 5 deletions(-)
+diff --git a/kexec/arch/arm64/kexec-image-arm64.c b/kexec/arch/arm64/kexec-image-arm64.c +index 42d2ea7..960ed96 100644 +--- a/kexec/arch/arm64/kexec-image-arm64.c ++++ b/kexec/arch/arm64/kexec-image-arm64.c +@@ -3,7 +3,9 @@
- */
- #define _GNU_SOURCE
++
- #include "kexec-arm64.h"
++#include <limits.h>
- int image_arm64_probe(const char *kernel_buf, off_t kernel_size)
- {
+@@ -21,14 +23,53 @@ int image_arm64_probe(const char *kernel_buf, off_t kernel_size)
return -1;- }
+- fprintf(stderr, "kexec: ARM64 binary image files are currently NOT SUPPORTED.\n"); +- return -1; ++ return 0;
- }
- int image_arm64_load(int argc, char **argv, const char *kernel_buf,
- off_t kernel_size, struct kexec_info *info)
- {
+- return -1; ++ const struct arm64_image_header *header; ++ unsigned long kernel_segment; ++ int result; ++ ++ header = (const struct arm64_image_header *)(kernel_buf); ++ ++ if (arm64_process_image_header(header)) ++ return -1; ++ ++ kernel_segment = arm64_locate_kernel_segment(info); ++ ++ if (kernel_segment == ULONG_MAX) { ++ dbgprintf("%s: Kernel segment is not allocated\n", __func__); ++ result = -EFAILED; ++ goto exit; ++ } ++ ++ dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); ++ dbgprintf("%s: text_offset: %016lx\n", __func__, ++ arm64_mem.text_offset); ++ dbgprintf("%s: image_size: %016lx\n", __func__, ++ arm64_mem.image_size); ++ dbgprintf("%s: phys_offset: %016lx\n", __func__, ++ arm64_mem.phys_offset); ++ dbgprintf("%s: vp_offset: %016lx\n", __func__, ++ arm64_mem.vp_offset); ++ dbgprintf("%s: PE format: %s\n", __func__, ++ (arm64_header_check_pe_sig(header) ? "yes" : "no")); ++ ++ /* load the kernel */ ++ add_segment_phys_virt(info, kernel_buf, kernel_size, ++ kernel_segment + arm64_mem.text_offset, ++ arm64_mem.image_size, 0); ++ ++ result = arm64_load_other_segments(info, kernel_segment ++ + arm64_mem.text_offset); ++ ++exit: ++ if (result) ++ fprintf(stderr, "kexec: load failed.\n"); ++ return result;
- }
- void image_arm64_usage(void)
+@@ -36,6 +77,4 @@ void image_arm64_usage(void)
- printf(
- " An ARM64 binary image, compressed or not, big or little endian.\n"
- " Typically an Image, Image.gz or Image.lzma file.\n\n");
+- printf( +-" ARM64 binary image files are currently NOT SUPPORTED.\n\n");
- }
+-- +2.9.3
diff --git a/kexec-tools.spec b/kexec-tools.spec index cd26ec3..985fd2d 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,9 +1,10 @@ Name: kexec-tools Version: 2.0.13 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv2 Group: Applications/System Summary: The kexec/kdump userspace component
Source0: http://kernel.org/pub/linux/utils/kernel/kexec/%%7Bname%7D-%%7Bversion%7D.ta... Source1: kdumpctl Source2: kdump.sysconfig @@ -50,14 +51,13 @@ Requires: dracut-network, ethtool BuildRequires: zlib-devel zlib zlib-static elfutils-devel-static glib2-devel bzip2-devel ncurses-devel bison flex lzo-devel snappy-devel BuildRequires: pkgconfig intltool gettext BuildRequires: systemd-units +BuildRequires: automake autoconf libtool %ifarch %{ix86} x86_64 ppc64 ppc s390x ppc64le Obsoletes: diskdumputils netdump kexec-tools-eppic %endif
%undefine _hardened_build
-ExcludeArch: aarch64
#START INSERT
# @@ -76,8 +76,12 @@ ExcludeArch: aarch64 # Patches 401 through 500 are meant for s390 kexec-tools enablement # # -# Patches 501 through 600 are meant for ppc kexec-tools enablement +# Patches 501 through 600 are meant for ARM kexec-tools enablement # +# kexec v5 - http://lists.infradead.org/pipermail/kexec/2016-September/017110.html +Patch500: 0001-kexec-Add-common-device-tree-routines.patch +Patch501: 0002-arm64-Add-arm64-kexec-support.patch +Patch502: 0003-arm64-Add-support-for-binary-image-files.patch
# # Patches 601 onward are generic patches @@ -107,6 +111,9 @@ tar -z -x -v -f %{SOURCE9} tar -z -x -v -f %{SOURCE19} tar -z -x -v -f %{SOURCE23}
+%patch500 -p1 +%patch501 -p1 +%patch502 -p1
%patch601 -p1 %patch602 -p1 @@ -117,7 +124,7 @@ tar -z -x -v -f %{SOURCE23} %endif
%build
+autoreconf %configure \ %ifarch ppc64 --host=powerpc64-redhat-linux-gnu \ @@ -315,6 +322,9 @@ done %doc
%changelog +* Mon Sep 19 2016 Peter Robinson pbrobinson@fedoraproject.org 2.0.13-6 +- Add initial upstream support for kexec on aarch64
- Fri Sep 16 2016 Dave Young dyoung@redhat.com - 2.0.13-5
- Fix bug 1373958 for system boot without initrd
- Do not depend on /etc/fstab in kdumpctl in case it does not exist