----- Original Message -----
From: "Baoquan He" <bhe(a)redhat.com>
To: "Pingfan Liu" <piliu(a)redhat.com>
Cc: kexec(a)lists.fedoraproject.org, "Pratyush Anand" <panand(a)redhat.com>,
"Xunlei Pang" <xpang(a)redhat.com>, "Dave
Young" <dyoung(a)redhat.com>, pbrobinson(a)gmail.com
Sent: Tuesday, October 25, 2016 3:45:23 PM
Subject: Re: [F25 PATCH]: Add initial upstream support for kexec on aarch64
On 10/25/16 at 02:50pm, Pingfan Liu wrote:
> From: Pingfan Liu <piliu(a)redhat.com>
>
> Fix Bug 925630 - kexec-tools: support for arm64
>
https://bugzilla.redhat.com/show_bug.cgi?id=925630
>
> Support for the ARM 64 bit CPU architecture (aarch64) was introduced in
> autoconf 2.69. kexec-tools appears to use an earlier version of
> autoconf, preventing its being built. This series fix this issue by
> updates config.guess and config.sub to recognize aarch64
Don't understand what you are trying to do. What I got is you are back
porting aarch64 supporting code to f25, meanwhile you found it still
doesn't work because kexec-tools is still using old autoconf. So you fix
it too in this patch. Right?
Yeah, I got the info from comments in bugzilla. I think it refers to the added
"autoreconf" in kexec-tools.spec.
Thx,
Pingfan
> >
> > patchset backported from upstream:
> > commit abdfe97736f89d9bc73662b9134604b0229a599e
> > commit 522df5f7217fda01ece3f6ac3e9987b0320c2bb0
> > commit 217bcc00c9309416a6c6cd0584196559d28a9259
> >
> > Signed-off-by: Pingfan Liu <piliu(a)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(a)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(a)infradead.org>
> > +Tested-By: Pratyush Anand <panand(a)redhat.com>
> > +Tested-By: Matthias Brugger <mbrugger(a)suse.com>
> > +Signed-off-by: Simon Horman <horms(a)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(a)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(a)infradead.org>
> > +Tested-By: Pratyush Anand <panand(a)redhat.com>
> > +Tested-By: Matthias Brugger <mbrugger(a)suse.com>
> > +Signed-off-by: Simon Horman <horms(a)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(a)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(a)redhat.com>
> > +[Reworked and cleaned up]
> > +Signed-off-by: Geoff Levand <geoff(a)infradead.org>
> > +Tested-By: Pratyush Anand <panand(a)redhat.com>
> > +Tested-By: Matthias Brugger <mbrugger(a)suse.com>
> > +Signed-off-by: Simon Horman <horms(a)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/%{name}-%{version}.tar.xz
> > 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(a)fedoraproject.org> 2.0.13-6
> > +- Add initial upstream support for kexec on aarch64
> > +
> > * Fri Sep 16 2016 Dave Young <dyoung(a)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
> > --
> > 2.9.3
> >
>