From bc46b33f03c30e40d873a785a55f40beb0e33e7d Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Thu, 27 Mar 2014 11:56:56 +0000 Subject: [PATCH] actually commit kexec-aarch64.patch patch --- kexec-aarch64.patch | 794 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 794 insertions(+) create mode 100644 kexec-aarch64.patch diff --git a/kexec-aarch64.patch b/kexec-aarch64.patch new file mode 100644 index 0000000..6c60fcd --- /dev/null +++ b/kexec-aarch64.patch @@ -0,0 +1,794 @@ +From: Geoff Levand +Date: Mon, 15 Jul 2013 23:32:36 +0000 (-0700) +Subject: Add arm64 support +X-Git-Url: https://git.linaro.org/gitweb?p=people%2Fgeoff%2Fkexec-tools.git;a=commitdiff_plain;h=fbf5ac6c2c70ec0f6da2b9ff563e573999752c01 + +Add arm64 support + +Signed-off-by: Geoff Levand +--- + +Index: kexec-tools-2.0.4/configure.ac +=================================================================== +--- kexec-tools-2.0.4.orig/configure.ac ++++ kexec-tools-2.0.4/configure.ac +@@ -30,6 +30,9 @@ case $target_cpu in + powerpc64 ) + ARCH="ppc64" + ;; ++ aarch64 ) ++ ARCH="arm64" ++ ;; + arm* ) + ARCH="arm" + ;; +Index: kexec-tools-2.0.4/kexec/Makefile +=================================================================== +--- kexec-tools-2.0.4.orig/kexec/Makefile ++++ kexec-tools-2.0.4/kexec/Makefile +@@ -70,6 +70,7 @@ KEXEC_SRCS += $($(ARCH)_FS2DT) + + 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/mips/Makefile +Index: kexec-tools-2.0.4/kexec/arch/arm64/Makefile +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/kexec/arch/arm64/Makefile +@@ -0,0 +1,13 @@ ++ ++arm64_KEXEC_SRCS += \ ++ kexec/arch/arm64/kexec-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 = ++ ++dist += $(arm64_KEXEC_SRCS) \ ++ kexec/arch/arm64/Makefile \ ++ kexec/arch/arm64/kexec-arm64.h +Index: kexec-tools-2.0.4/kexec/arch/arm64/crashdump-arm64.c +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/kexec/arch/arm64/crashdump-arm64.c +@@ -0,0 +1,305 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation (version 2 of the License). ++ */ ++ ++#include "../../kexec.h" ++#include "../../kexec-elf.h" ++#include "../../crashdump.h" ++ ++int is_crashkernel_mem_reserved(void) ++{ ++ return 0; ++} ++ ++#if 0 ++/* ++ * Used to save various memory ranges/regions needed for the captured ++ * kernel to boot. (lime memmap= option in other archs) ++ */ ++static struct memory_range crash_memory_ranges[CRASH_MAX_MEMORY_RANGES]; ++struct memory_ranges usablemem_rgns = { ++ .size = 0, ++ .ranges = crash_memory_ranges, ++}; ++ ++/* memory range reserved for crashkernel */ ++static struct memory_range crash_reserved_mem; ++ ++static struct crash_elf_info elf_info = { ++ .class = ELFCLASS32, ++ .data = ELFDATA2LSB, ++ .machine = EM_ARM, ++ .page_offset = PAGE_OFFSET, ++}; ++ ++unsigned long phys_offset; ++ ++/** ++ * crash_range_callback() - callback called for each iomem region ++ * @data: not used ++ * @nr: not used ++ * @str: name of the memory region ++ * @base: start address of the memory region ++ * @length: size of the memory region ++ * ++ * This function is called once for each memory region found in /proc/iomem. It ++ * locates system RAM and crashkernel reserved memory and places these to ++ * variables: @crash_memory_ranges and @crash_reserved_mem. Number of memory ++ * regions is placed in @crash_memory_nr_ranges. ++ */ ++static int crash_range_callback(void *UNUSED(data), int UNUSED(nr), ++ char *str, unsigned long base, ++ unsigned long length) ++{ ++ struct memory_range *range; ++ ++ if (usablemem_rgns.size >= CRASH_MAX_MEMORY_RANGES) ++ return 1; ++ ++ range = usablemem_rgns.ranges + usablemem_rgns.size; ++ ++ if (strncmp(str, "System RAM\n", 11) == 0) { ++ range->start = base; ++ range->end = base + length - 1; ++ range->type = RANGE_RAM; ++ usablemem_rgns.size++; ++ } else if (strncmp(str, "Crash kernel\n", 13) == 0) { ++ crash_reserved_mem.start = base; ++ crash_reserved_mem.end = base + length - 1; ++ crash_reserved_mem.type = RANGE_RAM; ++ } ++ ++ return 0; ++} ++ ++/** ++ * crash_exclude_range() - excludes memory region reserved for crashkernel ++ * ++ * Function locates where crashkernel reserved memory is and removes that region ++ * from the available memory regions. ++ */ ++static void crash_exclude_range(void) ++{ ++ const struct memory_range *range = &crash_reserved_mem; ++ int i; ++ ++ for (i = 0; i < usablemem_rgns.size; i++) { ++ struct memory_range *r = usablemem_rgns.ranges + i; ++ ++ /* ++ * We assume that crash area is fully contained in ++ * some larger memory area. ++ */ ++ if (r->start <= range->start && r->end >= range->end) { ++ struct memory_range *new; ++ /* ++ * Let's split this area into 2 smaller ones and ++ * remove excluded range from between. First create ++ * new entry for the remaining area. ++ */ ++ new = usablemem_rgns.ranges + usablemem_rgns.size; ++ new->start = range->end + 1; ++ new->end = r->end; ++ usablemem_rgns.size++; ++ /* ++ * Next update this area to end before excluded range. ++ */ ++ r->end = range->start - 1; ++ break; ++ } ++ } ++} ++ ++static int range_cmp(const void *a1, const void *a2) ++{ ++ const struct memory_range *r1 = a1; ++ const struct memory_range *r2 = a2; ++ ++ if (r1->start > r2->start) ++ return 1; ++ if (r1->start < r2->start) ++ return -1; ++ ++ return 0; ++} ++ ++/** ++ * crash_get_memory_ranges() - read system physical memory ++ * ++ * Function reads through system physical memory and stores found memory regions ++ * in @crash_memory_ranges. Number of memory regions found is placed in ++ * @crash_memory_nr_ranges. Regions are sorted in ascending order. ++ * ++ * Returns %0 in case of success and %-1 otherwise (errno is set). ++ */ ++static int crash_get_memory_ranges(void) ++{ ++ /* ++ * First read all memory regions that can be considered as ++ * system memory including the crash area. ++ */ ++ kexec_iomem_for_each_line(NULL, crash_range_callback, NULL); ++ ++ if (usablemem_rgns.size < 1) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* ++ * Exclude memory reserved for crashkernel (this may result a split memory ++ * region). ++ */ ++ crash_exclude_range(); ++ ++ /* ++ * Make sure that the memory regions are sorted. ++ */ ++ qsort(usablemem_rgns.ranges, usablemem_rgns.size, ++ sizeof(*usablemem_rgns.ranges), range_cmp); ++ ++ return 0; ++} ++ ++/** ++ * cmdline_add_elfcorehdr() - adds elfcorehdr= to @cmdline ++ * @cmdline: buffer where parameter is placed ++ * @elfcorehdr: physical address of elfcorehdr ++ * ++ * Function appends 'elfcorehdr=start' at the end of the command line given in ++ * @cmdline. Note that @cmdline must be at least %COMMAND_LINE_SIZE bytes long ++ * (inclunding %NUL). ++ */ ++static void cmdline_add_elfcorehdr(char *cmdline, unsigned long elfcorehdr) ++{ ++ char buf[COMMAND_LINE_SIZE]; ++ int buflen; ++ ++ buflen = snprintf(buf, sizeof(buf), "%s elfcorehdr=%#lx", ++ cmdline, elfcorehdr); ++ if (buflen < 0) ++ die("Failed to construct elfcorehdr= command line parameter\n"); ++ if (buflen >= sizeof(buf)) ++ die("Command line overflow\n"); ++ ++ (void) strncpy(cmdline, buf, COMMAND_LINE_SIZE); ++ cmdline[COMMAND_LINE_SIZE - 1] = '\0'; ++} ++ ++/** ++ * cmdline_add_mem() - adds mem= parameter to kernel command line ++ * @cmdline: buffer where parameter is placed ++ * @size: size of the kernel reserved memory (in bytes) ++ * ++ * This function appends 'mem=size' at the end of the command line given in ++ * @cmdline. Note that @cmdline must be at least %COMMAND_LINE_SIZE bytes long ++ * (including %NUL). ++ */ ++static void cmdline_add_mem(char *cmdline, unsigned long size) ++{ ++ char buf[COMMAND_LINE_SIZE]; ++ int buflen; ++ ++ buflen = snprintf(buf, sizeof(buf), "%s mem=%ldK", cmdline, size >> 10); ++ if (buflen < 0) ++ die("Failed to construct mem= command line parameter\n"); ++ if (buflen >= sizeof(buf)) ++ die("Command line overflow\n"); ++ ++ (void) strncpy(cmdline, buf, COMMAND_LINE_SIZE); ++ cmdline[COMMAND_LINE_SIZE - 1] = '\0'; ++} ++ ++static unsigned long long range_size(const struct memory_range *r) ++{ ++ return r->end - r->start + 1; ++} ++ ++static void dump_memory_ranges(void) ++{ ++ int i; ++ ++ if (!kexec_debug) ++ return; ++ ++ dbgprintf("crashkernel: [%#llx - %#llx] (%ldM)\n", ++ crash_reserved_mem.start, crash_reserved_mem.end, ++ (unsigned long)range_size(&crash_reserved_mem) >> 20); ++ ++ for (i = 0; i < usablemem_rgns.size; i++) { ++ struct memory_range *r = usablemem_rgns.ranges + i; ++ dbgprintf("memory range: [%#llx - %#llx] (%ldM)\n", ++ r->start, r->end, (unsigned long)range_size(r) >> 20); ++ } ++} ++ ++/** ++ * load_crashdump_segments() - loads additional segments needed for kdump ++ * @info: kexec info structure ++ * @mod_cmdline: kernel command line ++ * ++ * This function loads additional segments which are needed for the dump capture ++ * kernel. It also updates kernel command line passed in @mod_cmdline to have ++ * right parameters for the dump capture kernel. ++ * ++ * Return %0 in case of success and %-1 in case of error. ++ */ ++int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline) ++{ ++ unsigned long elfcorehdr; ++ unsigned long bufsz; ++ void *buf; ++ int err; ++ ++ /* ++ * First fetch all the memory (RAM) ranges that we are going to pass to ++ * the crashdump kernel during panic. ++ */ ++ err = crash_get_memory_ranges(); ++ if (err) ++ return err; ++ ++ /* ++ * Now that we have memory regions sorted, we can use first memory ++ * region as PHYS_OFFSET. ++ */ ++ phys_offset = usablemem_rgns.ranges->start; ++ dbgprintf("phys_offset: %#lx\n", phys_offset); ++ ++ err = crash_create_elf32_headers(info, &elf_info, ++ usablemem_rgns.ranges, ++ usablemem_rgns.size, &buf, &bufsz, ++ ELF_CORE_HEADER_ALIGN); ++ if (err) ++ return err; ++ ++ /* ++ * We allocate ELF core header from the end of the memory area reserved ++ * for the crashkernel. We align the header to SECTION_SIZE (which is ++ * 1MB) so that available memory passed in kernel command line will be ++ * aligned to 1MB. This is because kernel create_mapping() wants memory ++ * regions to be aligned to SECTION_SIZE. ++ */ ++ elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 1 << 20, ++ crash_reserved_mem.start, ++ crash_reserved_mem.end, -1, 0); ++ ++ dbgprintf("elfcorehdr: %#lx\n", elfcorehdr); ++ cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); ++ ++ /* ++ * Add 'mem=size' parameter to dump capture kernel command line. This ++ * prevents the dump capture kernel from using any other memory regions ++ * which belong to the primary kernel. ++ */ ++ cmdline_add_mem(mod_cmdline, elfcorehdr - crash_reserved_mem.start); ++ ++ dump_memory_ranges(); ++ dbgprintf("kernel command line: \"%s\"\n", mod_cmdline); ++ ++ return 0; ++} ++ ++#endif ++ +Index: kexec-tools-2.0.4/kexec/arch/arm64/include/arch/options.h +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/kexec/arch/arm64/include/arch/options.h +@@ -0,0 +1,26 @@ ++#ifndef KEXEC_ARCH_ARM64_OPTIONS_H ++#define KEXEC_ARCH_ARM64_OPTIONS_H ++ ++//#define OPT_ARCH_MAX ((OPT_MAX)+0) ++ ++#define OPT_APPEND ((OPT_MAX)+0) ++#define OPT_RAMDISK ((OPT_MAX)+1) ++#define OPT_DTB ((OPT_MAX)+2) ++ ++#define OPT_ARCH_MAX ((OPT_MAX)+3) ++ ++ ++#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_RAMDISK }, \ ++ { "ramdisk", 1, NULL, OPT_RAMDISK }, \ ++ ++#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 ++ ++#endif /* KEXEC_ARCH_ARM64_OPTIONS_H */ +Index: kexec-tools-2.0.4/kexec/arch/arm64/kexec-arm64.c +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/kexec/arch/arm64/kexec-arm64.c +@@ -0,0 +1,177 @@ ++/* ++ * ARM64 kexec support. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++ ++//#include ++ ++#include "../../kexec.h" ++#include "../../kexec-syscall.h" ++#include "kexec-arm64.h" ++ ++ ++void arch_usage(void) ++{ ++ fprintf(stderr, "%s:%d: ->\n", __func__, __LINE__); ++ ++ printf( ++" --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"); ++ ++ fprintf(stderr, "%s:%d: <-\n", __func__, __LINE__); ++} ++ ++int arch_process_options(int UNUSED(argc), char **UNUSED(argv)) ++{ ++ fprintf(stderr, "%s:%d: do\n", __func__, __LINE__); ++ return 0; ++} ++ ++const struct arch_map_entry arches[] = { ++ { "aarch64", KEXEC_ARCH_ARM64 }, ++ { NULL, 0 }, ++}; ++ ++void arch_update_purgatory(struct kexec_info *UNUSED(info)) ++{ ++ fprintf(stderr, "%s:%d: do\n", __func__, __LINE__); ++} ++ ++unsigned long virt_to_phys(unsigned long addr) ++{ ++ fprintf(stderr, "%s:%d: %016lx -> %016lx\n", __func__, __LINE__, addr, ++ addr + 0x080000000UL); ++ return addr + 0x080000000UL; ++} ++ ++void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, ++ unsigned long base, size_t memsz) ++{ ++ fprintf(stderr, "%s:%d: ->\n", __func__, __LINE__); ++ add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); ++ fprintf(stderr, "%s:%d: <-\n", __func__, __LINE__); ++} ++ ++static int get_memory_ranges_1(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) ++{ ++ static struct memory_range memory_range[KEXEC_SEGMENT_MAX]; ++ const char *iomem; ++ int range_count = 0; ++ char line[MAX_LINE]; ++ FILE *fp; ++ ++ iomem = proc_iomem(); ++ fp = fopen(iomem, "r"); ++ ++ if (!fp) { ++ fprintf(stderr, "Cannot open %s: %s\n", ++ iomem, strerror(errno)); ++ return -1; ++ } ++ ++ dbgprintf("memory ranges:\n"); ++ ++ while(fgets(line, sizeof(line), fp) != 0) { ++ struct memory_range r; ++ char *str; ++ int consumed; ++ ++ if (range_count >= KEXEC_SEGMENT_MAX) ++ break; ++ ++ if (sscanf(line, "%Lx-%Lx : %n", &r.start, &r.end, &consumed) ++ != 2) ++ continue; ++ ++ str = line + consumed; ++ r.end++; ++ ++ if (memcmp(str, "System RAM\n", 11)) { ++ dbgprintf(" Skip: %016Lx - %016Lx : %s", r.start, r.end, ++ str); ++ continue; ++ } ++ ++ r.type = RANGE_RAM; ++ memory_range[range_count] = r; ++ range_count++; ++ ++ dbgprintf(" Add: %016Lx - %016Lx : %s", r.start, r.end, str); ++ } ++ ++ fclose(fp); ++ *range = memory_range; ++ *ranges = range_count; ++ ++ return 0; ++} ++ ++static int get_memory_ranges_2(struct memory_range **range, int *ranges, ++ unsigned long UNUSED(kexec_flags)) ++{ ++ static struct memory_range memory_range[2]; ++ ++ memory_range[0].start = 0x080000000; ++ memory_range[0].end = 0x100000000; ++ memory_range[0].type = RANGE_RAM; ++ ++ memory_range[1].start = 0x900000000; ++ memory_range[1].end = 0x880000000; ++ memory_range[1].type = RANGE_RAM; ++ ++ *range = memory_range; ++ *ranges = sizeof(memory_range) / sizeof(memory_range[0]); ++ ++ return 0; ++} ++ ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) ++{ ++ /* FIXME: Should get this info from device tree. */ ++ ++ return get_memory_ranges_1(range, ranges, kexec_flags); ++} ++ ++struct file_type file_type[] = { ++ { "elf-arm64", elf_arm64_probe, elf_arm64_load, elf_arm64_usage }, ++}; ++ ++int file_types = sizeof(file_type) / sizeof(file_type[0]); ++ ++int arch_compat_trampoline(struct kexec_info *info) ++{ ++ fprintf(stderr, "%s:%d: do\n", __func__, __LINE__); ++ return 0; ++} ++ ++void arch_reuse_initrd(void) ++{ ++} ++ ++int machine_verify_elf_rel(struct mem_ehdr *ehdr) ++{ ++ (void)ehdr; ++ ++ fprintf(stderr, "%s:%d: do\n", __func__, __LINE__); ++ return 0; ++} ++ ++void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, ++ void *location, unsigned long address, unsigned long value) ++{ ++ (void)ehdr; ++ (void)r_type; ++ (void)location; ++ (void)address; ++ (void)value; ++ fprintf(stderr, "%s:%d: do\n", __func__, __LINE__); ++} +Index: kexec-tools-2.0.4/kexec/arch/arm64/kexec-arm64.h +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/kexec/arch/arm64/kexec-arm64.h +@@ -0,0 +1,20 @@ ++/* ++ * ARM64 kexec support. ++ */ ++ ++#if !defined(KEXEC_ARM64_H) ++#define KEXEC_ARM64_H ++ ++/* #include FIXME: this is broken */ ++#include ++ ++#include "../../kexec.h" ++ ++#define KEXEC_SEGMENT_MAX 16 /* FIXME: this should come from */ ++ ++int elf_arm64_probe(const char *buf, off_t len); ++int elf_arm64_load(int argc, char **argv, const char *buf, off_t len, ++ struct kexec_info *info); ++void elf_arm64_usage(void); ++ ++#endif +\ No newline at end of file +Index: kexec-tools-2.0.4/kexec/arch/arm64/kexec-elf-arm64.c +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/kexec/arch/arm64/kexec-elf-arm64.c +@@ -0,0 +1,114 @@ ++/* ++ * ARM64 kexec support. ++ */ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++ ++#include "../../kexec-syscall.h" ++ ++#include "kexec-arm64.h" ++#include "arch/options.h" ++ ++#if !defined(EM_AARCH64) ++# define EM_AARCH64 183 ++#endif ++ ++int elf_arm64_probe(const char *buf, off_t len) ++{ ++ int result; ++ struct mem_ehdr ehdr; ++ ++ fprintf(stderr, "%s:%d: ->\n", __func__, __LINE__); ++ ++ result = build_elf_exec_info(buf, len, &ehdr, 0); ++ ++ if (result < 0) { ++ dbgprintf("Not an ELF executable\n"); ++ goto out; ++ } ++ ++ if (ehdr.e_machine != EM_AARCH64) { ++ dbgprintf("Not an AARCH64 executable\n"); ++ result = -1; ++ goto out; ++ } ++ ++ result = 0; ++ ++out: ++ free_elf_info(&ehdr); ++ fprintf(stderr, "%s:%d: <-\n", __func__, __LINE__); ++ return result; ++} ++ ++int elf_arm64_load(int argc, char **argv, const char *buf, off_t len, ++ struct kexec_info *info) ++{ ++ static const struct option options[] = { ++ KEXEC_ARCH_OPTIONS ++ { 0 } ++ }; ++ static const char short_options[] = KEXEC_OPT_STR ""; ++ const char *command_line = NULL; ++ unsigned int command_line_len = 0; ++ const char *ramdisk = NULL; ++ const char *dtb = NULL; ++ int opt; ++ struct mem_ehdr ehdr; ++ int result; ++ ++ fprintf(stderr, "%s:%d: ->\n", __func__, __LINE__); ++ ++ while ((opt = getopt_long(argc, argv, short_options, options, 0)) ++ != -1) { ++ switch (opt) { ++ default: ++ if (opt < OPT_MAX) /* Ignore core options */ ++ break; ++ case OPT_APPEND: ++ command_line = optarg; ++ command_line_len = strlen(command_line) + 1; ++ break; ++ case OPT_RAMDISK: ++ ramdisk = optarg; ++ break; ++ case OPT_DTB: ++ dtb = optarg; ++ break; ++ } ++ } ++ ++ fprintf(stderr, "%s:%d: command_line: %s\n", __func__, __LINE__, command_line); ++ fprintf(stderr, "%s:%d: ramdisk: %s\n", __func__, __LINE__, ramdisk); ++ fprintf(stderr, "%s:%d: dtb: %s\n", __func__, __LINE__, dtb); ++ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ fprintf(stderr, "kexec: kdump not yet supported on arm64\n"); ++ return -1; ++ } ++ ++ result = build_elf_exec_info(buf, len, &ehdr, 0); ++ ++ if (result < 0) { ++ free_elf_info(&ehdr); ++ fprintf(stderr, "%s:%d: free_elf_info failed\n", __func__, ++ __LINE__); ++ return result; ++ } ++ ++ elf_exec_build_load(info, &ehdr, buf, len, 0); ++ ++ info->entry = (void*)0x80080000UL; // FIXME ++ ++ fprintf(stderr, "%s:%d: <-\n", __func__, __LINE__); ++ return 0; ++} ++ ++void elf_arm64_usage(void) ++{ ++ fprintf(stderr, "%s:%d: ->\n", __func__, __LINE__); ++ fprintf(stderr, "%s:%d: <-\n", __func__, __LINE__); ++} +Index: kexec-tools-2.0.4/kexec/kexec-syscall.h +=================================================================== +--- kexec-tools-2.0.4.orig/kexec/kexec-syscall.h ++++ kexec-tools-2.0.4/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 +@@ -72,6 +72,8 @@ static inline long kexec_load(void *entr + #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_AARCH64 (183 << 16) */ + #define KEXEC_ARCH_S390 (22 << 16) + #define KEXEC_ARCH_SH (42 << 16) + #define KEXEC_ARCH_MIPS_LE (10 << 16) +@@ -114,5 +116,8 @@ static inline long kexec_load(void *entr + #if defined(__mips__) + #define KEXEC_ARCH_NATIVE KEXEC_ARCH_MIPS + #endif ++#if defined(__arm64__) ++#define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 ++#endif + + #endif /* KEXEC_SYSCALL_H */ +Index: kexec-tools-2.0.4/kexec/kexec.c +=================================================================== +--- kexec-tools-2.0.4.orig/kexec/kexec.c ++++ kexec-tools-2.0.4/kexec/kexec.c +@@ -659,6 +659,8 @@ static int my_load(const char *type, int + info.backup_start = 0; + info.kexec_flags = kexec_flags; + ++ fprintf(stderr, "%s:%d: do\n", __func__, __LINE__); ++ + result = 0; + if (argc - fileind <= 0) { + fprintf(stderr, "No kernel specified\n"); +Index: kexec-tools-2.0.4/purgatory/arch/arm64/Makefile +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.4/purgatory/arch/arm64/Makefile +@@ -0,0 +1,7 @@ ++# ++# Purgatory arm64 ++# ++ ++arm64_PURGATORY_SRCS = ++ ++dist += purgatory/arch/arm64/Makefile $(arm64_PURGATORY_SRCS) +Index: kexec-tools-2.0.4/configure +=================================================================== +--- kexec-tools-2.0.4.orig/configure ++++ kexec-tools-2.0.4/configure +@@ -2256,6 +2256,9 @@ case $target_cpu in + powerpc64 ) + ARCH="ppc64" + ;; ++ aarch64 ) ++ ARCH="arm64" ++ ;; + arm* ) + ARCH="arm" + ;;