diff -Nru kexec-tools-2.0.10/debian/changelog kexec-tools-2.0.10/debian/changelog --- kexec-tools-2.0.10/debian/changelog 2017-03-09 00:57:31.000000000 +0000 +++ kexec-tools-2.0.10/debian/changelog 2017-06-23 18:27:52.000000000 +0000 @@ -1,3 +1,9 @@ +kexec-tools (1:2.0.10-1ubuntu2.3) xenial; urgency=medium + + * Add backport of upstream arm64 crashdump support (LP: #1694859). + + -- dann frazier Fri, 23 Jun 2017 12:27:52 -0600 + kexec-tools (1:2.0.10-1ubuntu2.2) xenial; urgency=medium [ Manoj Iyer ] diff -Nru kexec-tools-2.0.10/debian/patches/0001-kexec-extend-the-semantics-of-kexec_iomem_for_each_l.patch kexec-tools-2.0.10/debian/patches/0001-kexec-extend-the-semantics-of-kexec_iomem_for_each_l.patch --- kexec-tools-2.0.10/debian/patches/0001-kexec-extend-the-semantics-of-kexec_iomem_for_each_l.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0001-kexec-extend-the-semantics-of-kexec_iomem_for_each_l.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,79 @@ +From c95df0e099b14757de483245d7b1b45e2d6e2c91 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:41 +0900 +Subject: [PATCH 01/11] kexec: extend the semantics of + kexec_iomem_for_each_line + +The current kexec_iomem_for_each_line() counts up all the lines for which +a callback function returns zero(0) or positive, and otherwise it stops +further scanning. +This behavior is inconvenient in some cases. For instance, on arm64, we want +to count up "System RAM" entries, but need to skip "reserved" entries. + +So this patch extends the semantics so that we will continue to scan +succeeding entries but not count lines for which a callback function +returns positive. + +The current users of kexec_iomem_for_each_line(), arm, sh and x86, will not +be affected by this change because +* arm + The callback function only returns -1 or 0, and the return value of + kexec_iomem_for_each_line() will never be used. +* sh, x86 + The callback function may return (-1 for sh,) 0 or 1, but always returns + 1 once we have reached the maximum number of entries allowed. + Even so the current kexec_iomem_for_each_line() counts them up. + This change actually fixes this bug. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/kexec-iomem.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/kexec/kexec-iomem.c b/kexec/kexec-iomem.c +index 7ec3853..b5b52b1 100644 +--- a/kexec/kexec-iomem.c ++++ b/kexec/kexec-iomem.c +@@ -18,6 +18,9 @@ + * Iterate over each line in the file returned by proc_iomem(). If match is + * NULL or if the line matches with our match-pattern then call the + * callback if non-NULL. ++ * If match is NULL, callback should return a negative if error. ++ * Otherwise the interation goes on, incrementing nr but only if callback ++ * returns 0 (matched). + * + * Return the number of lines matched. + */ +@@ -37,7 +40,7 @@ int kexec_iomem_for_each_line(char *match, + char *str; + int consumed; + int count; +- int nr = 0; ++ int nr = 0, ret; + + fp = fopen(iomem, "r"); + if (!fp) +@@ -50,11 +53,13 @@ int kexec_iomem_for_each_line(char *match, + str = line + consumed; + size = end - start + 1; + if (!match || memcmp(str, match, strlen(match)) == 0) { +- if (callback +- && callback(data, nr, str, start, size) < 0) { +- break; ++ if (callback) { ++ ret = callback(data, nr, str, start, size); ++ if (ret < 0) ++ break; ++ else if (ret == 0) ++ nr++; + } +- nr++; + } + } + +-- +2.11.0 + diff -Nru kexec-tools-2.0.10/debian/patches/0002-kexec-generalize-and-rename-get_kernel_stext_sym.patch kexec-tools-2.0.10/debian/patches/0002-kexec-generalize-and-rename-get_kernel_stext_sym.patch --- kexec-tools-2.0.10/debian/patches/0002-kexec-generalize-and-rename-get_kernel_stext_sym.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0002-kexec-generalize-and-rename-get_kernel_stext_sym.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,183 @@ +From 325804055e99dbf40af5e6fa546320b821d9d821 Mon Sep 17 00:00:00 2001 +From: Pratyush Anand +Date: Wed, 17 May 2017 14:51:42 +0900 +Subject: [PATCH 02/11] kexec: generalize and rename get_kernel_stext_sym() + +get_kernel_stext_sym() has been defined for both arm and i386. Other +architecture might need some other kernel symbol address. Therefore rewrite +this function as generic function to get any kernel symbol address. + +More over, kallsyms is not arch specific representation, therefore have +common function for all arches. + +Signed-off-by: Pratyush Anand +[created symbols.c] +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/Makefile | 1 + + kexec/arch/arm/crashdump-arm.c | 40 +--------------------------------------- + kexec/arch/i386/crashdump-x86.c | 29 ----------------------------- + kexec/kexec.h | 2 ++ + kexec/symbols.c | 34 ++++++++++++++++++++++++++++++++++ + 5 files changed, 38 insertions(+), 68 deletions(-) + create mode 100644 kexec/symbols.c + +Index: kexec-tools-2.0.10/kexec/Makefile +=================================================================== +--- kexec-tools-2.0.10.orig/kexec/Makefile ++++ kexec-tools-2.0.10/kexec/Makefile +@@ -26,6 +26,7 @@ KEXEC_SRCS_base += kexec/kernel_version. + KEXEC_SRCS_base += kexec/lzma.c + KEXEC_SRCS_base += kexec/zlib.c + KEXEC_SRCS_base += kexec/kexec-xen.c ++KEXEC_SRCS_base += kexec/symbols.c + + KEXEC_GENERATED_SRCS += $(PURGATORY_HEX_C) + +Index: kexec-tools-2.0.10/kexec/arch/arm/crashdump-arm.c +=================================================================== +--- kexec-tools-2.0.10.orig/kexec/arch/arm/crashdump-arm.c ++++ kexec-tools-2.0.10/kexec/arch/arm/crashdump-arm.c +@@ -63,48 +63,10 @@ static struct crash_elf_info elf_info = + unsigned long phys_offset; + extern unsigned long long user_page_offset; + +-/* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ +-static unsigned long long get_kernel_stext_sym(void) +-{ +- const char *kallsyms = "/proc/kallsyms"; +- const char *stext = "_stext"; +- char sym[128]; +- char line[128]; +- FILE *fp; +- unsigned long long vaddr = 0; +- char type; +- +- fp = fopen(kallsyms, "r"); +- if (!fp) { +- fprintf(stderr, "Cannot open %s\n", kallsyms); +- return 0; +- } +- +- while(fgets(line, sizeof(line), fp) != NULL) { +- unsigned long long addr; +- +- if (sscanf(line, "%Lx %c %s", &addr, &type, sym) != 3) +- continue; +- +- if (strcmp(sym, stext) == 0) { +- dbgprintf("kernel symbol %s vaddr = %#llx\n", stext, addr); +- vaddr = addr; +- break; +- } +- } +- +- fclose(fp); +- +- if (vaddr == 0) +- fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); +- +- return vaddr; +-} +- + static int get_kernel_page_offset(struct kexec_info *info, + struct crash_elf_info *elf_info) + { +- unsigned long long stext_sym_addr = get_kernel_stext_sym(); ++ unsigned long long stext_sym_addr = get_kernel_sym("_stext"); + if (stext_sym_addr == 0) { + if (user_page_offset != (-1ULL)) { + elf_info->page_offset = user_page_offset; +Index: kexec-tools-2.0.10/kexec/kexec.h +=================================================================== +--- kexec-tools-2.0.10.orig/kexec/kexec.h ++++ kexec-tools-2.0.10/kexec/kexec.h +@@ -308,4 +308,6 @@ int xen_kexec_load(struct kexec_info *in + int xen_kexec_unload(uint64_t kexec_flags); + void xen_kexec_exec(void); + ++extern unsigned long long get_kernel_sym(const char *text); ++ + #endif /* KEXEC_H */ +Index: kexec-tools-2.0.10/kexec/symbols.c +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.10/kexec/symbols.c +@@ -0,0 +1,34 @@ ++#include ++#include ++#include "kexec.h" ++ ++/* Retrieve kernel symbol virtual address from /proc/kallsyms */ ++unsigned long long get_kernel_sym(const char *symbol) ++{ ++ const char *kallsyms = "/proc/kallsyms"; ++ char sym[128]; ++ char line[128]; ++ FILE *fp; ++ unsigned long long vaddr; ++ char type; ++ ++ fp = fopen(kallsyms, "r"); ++ if (!fp) { ++ fprintf(stderr, "Cannot open %s\n", kallsyms); ++ return 0; ++ } ++ ++ while (fgets(line, sizeof(line), fp) != NULL) { ++ if (sscanf(line, "%llx %c %s", &vaddr, &type, sym) != 3) ++ continue; ++ if (strcmp(sym, symbol) == 0) { ++ dbgprintf("kernel symbol %s vaddr = %16llx\n", ++ symbol, vaddr); ++ return vaddr; ++ } ++ } ++ ++ dbgprintf("Cannot get kernel %s symbol address\n", symbol); ++ ++ return 0; ++} +Index: kexec-tools-2.0.10/kexec/arch/i386/crashdump-x86.c +=================================================================== +--- kexec-tools-2.0.10.orig/kexec/arch/i386/crashdump-x86.c ++++ kexec-tools-2.0.10/kexec/arch/i386/crashdump-x86.c +@@ -101,35 +101,6 @@ static int get_kernel_paddr(struct kexec + return -1; + } + +-/* Retrieve kernel symbol virtual address from /proc/kallsyms */ +-static unsigned long long get_kernel_sym(const char *symbol) +-{ +- const char *kallsyms = "/proc/kallsyms"; +- char sym[128]; +- char line[128]; +- FILE *fp; +- unsigned long long vaddr; +- char type; +- +- fp = fopen(kallsyms, "r"); +- if (!fp) { +- fprintf(stderr, "Cannot open %s\n", kallsyms); +- return 0; +- } +- +- while(fgets(line, sizeof(line), fp) != NULL) { +- if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) +- continue; +- if (strcmp(sym, symbol) == 0) { +- dbgprintf("kernel symbol %s vaddr = %16llx\n", symbol, vaddr); +- return vaddr; +- } +- } +- +- fprintf(stderr, "Cannot get kernel %s symbol address\n", symbol); +- return 0; +-} +- + /* Retrieve info regarding virtual address kernel has been compiled for and + * size of the kernel from /proc/kcore. Current /proc/kcore parsing from + * from kexec-tools fails because of malformed elf notes. A kernel patch has diff -Nru kexec-tools-2.0.10/debian/patches/0003-arm64-identify-PHYS_OFFSET-correctly.patch kexec-tools-2.0.10/debian/patches/0003-arm64-identify-PHYS_OFFSET-correctly.patch --- kexec-tools-2.0.10/debian/patches/0003-arm64-identify-PHYS_OFFSET-correctly.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0003-arm64-identify-PHYS_OFFSET-correctly.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,85 @@ +From ef26cc33b8d66460c555600b0e388f55c5cd6f21 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:43 +0900 +Subject: [PATCH 03/11] arm64: identify PHYS_OFFSET correctly + +Due to the kernel patch, commit e7cd190385d1 ("arm64: mark reserved +memblock regions explicitly in iomem"), the current code will not be able +to identify the correct value of PHYS_OFFSET if some "reserved" memory +region, which is likely to be UEFI runtime services code/data, exists at +an address below the first "System RAM" regions. + +This patch fixes this issue. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/Makefile | 1 + + kexec/arch/arm64/iomem.h | 7 +++++++ + kexec/arch/arm64/kexec-arm64.c | 12 ++++++++++-- + 3 files changed, 18 insertions(+), 2 deletions(-) + create mode 100644 kexec/arch/arm64/iomem.h + +Index: kexec-tools-2.0.14/kexec/arch/arm64/Makefile +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/Makefile ++++ kexec-tools-2.0.14/kexec/arch/arm64/Makefile +@@ -23,6 +23,7 @@ dist += $(arm64_KEXEC_SRCS) \ + kexec/arch/arm64/include/arch/options.h \ + kexec/arch/arm64/crashdump-arm64.h \ + kexec/arch/arm64/image-header.h \ ++ kexec/arch/arm64/iomem.h \ + kexec/arch/arm64/kexec-arm64.h \ + kexec/arch/arm64/Makefile + +Index: kexec-tools-2.0.14/kexec/arch/arm64/iomem.h +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.14/kexec/arch/arm64/iomem.h +@@ -0,0 +1,7 @@ ++#ifndef IOMEM_H ++#define IOMEM_H ++ ++#define SYSTEM_RAM "System RAM\n" ++#define IOMEM_RESERVED "reserved\n" ++ ++#endif +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +@@ -21,6 +21,7 @@ + #include "crashdump-arm64.h" + #include "dt-ops.h" + #include "fs2dt.h" ++#include "iomem.h" + #include "kexec-syscall.h" + #include "arch/options.h" + +@@ -476,7 +477,14 @@ static int get_memory_ranges_iomem_cb(vo + return -1; + + r = (struct memory_range *)data + nr; +- r->type = RANGE_RAM; ++ ++ if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM))) ++ r->type = RANGE_RAM; ++ else if (!strncmp(str, IOMEM_RESERVED, strlen(IOMEM_RESERVED))) ++ r->type = RANGE_RESERVED; ++ else ++ return 1; ++ + r->start = base; + r->end = base + length - 1; + +@@ -495,7 +503,7 @@ static int get_memory_ranges_iomem_cb(vo + static int get_memory_ranges_iomem(struct memory_range *array, + unsigned int *count) + { +- *count = kexec_iomem_for_each_line("System RAM\n", ++ *count = kexec_iomem_for_each_line(NULL, + get_memory_ranges_iomem_cb, array); + + if (!*count) { diff -Nru kexec-tools-2.0.10/debian/patches/0004-arm64-change-return-values-on-error-to-negative.patch kexec-tools-2.0.10/debian/patches/0004-arm64-change-return-values-on-error-to-negative.patch --- kexec-tools-2.0.10/debian/patches/0004-arm64-change-return-values-on-error-to-negative.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0004-arm64-change-return-values-on-error-to-negative.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,179 @@ +From a17234fe94bce780ac36a0ba9bfc9b6e8ffd84f0 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:44 +0900 +Subject: [PATCH 04/11] arm64: change return values on error to negative + +EFAILED is defined "-1" and so we don't need to negate it as a return value. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/kexec-arm64.c | 24 ++++++++++++------------ + kexec/arch/arm64/kexec-elf-arm64.c | 6 +++--- + kexec/arch/arm64/kexec-image-arm64.c | 4 ++-- + 3 files changed, 17 insertions(+), 17 deletions(-) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +@@ -78,7 +78,7 @@ int arm64_process_image_header(const str + #endif + + if (!arm64_header_check_magic(h)) +- return -EFAILED; ++ return EFAILED; + + if (h->image_size) { + arm64_mem.text_offset = arm64_header_text_offset(h); +@@ -201,7 +201,7 @@ static int set_bootargs(struct dtb *dtb, + if (result) { + fprintf(stderr, + "kexec: Set device tree bootargs failed.\n"); +- return -EFAILED; ++ return EFAILED; + } + + return 0; +@@ -221,7 +221,7 @@ static int read_proc_dtb(struct dtb *dtb + + if (result) { + dbgprintf("%s: %s\n", __func__, strerror(errno)); +- return -EFAILED; ++ return EFAILED; + } + + dtb->path = path; +@@ -244,7 +244,7 @@ static int read_sys_dtb(struct dtb *dtb) + + if (result) { + dbgprintf("%s: %s\n", __func__, strerror(errno)); +- return -EFAILED; ++ return EFAILED; + } + + dtb->path = path; +@@ -274,7 +274,7 @@ static int read_1st_dtb(struct dtb *dtb) + goto on_success; + + dbgprintf("%s: not found\n", __func__); +- return -EFAILED; ++ return EFAILED; + + on_success: + dbgprintf("%s: found %s\n", __func__, dtb->path); +@@ -293,7 +293,7 @@ static int setup_2nd_dtb(struct dtb *dtb + + if (result) { + fprintf(stderr, "kexec: Invalid 2nd device tree.\n"); +- return -EFAILED; ++ return EFAILED; + } + + result = set_bootargs(dtb, command_line); +@@ -348,14 +348,14 @@ int arm64_load_other_segments(struct kex + if (result) { + fprintf(stderr, + "kexec: Error: No device tree available.\n"); +- return -EFAILED; ++ return EFAILED; + } + } + + result = setup_2nd_dtb(&dtb, command_line); + + if (result) +- return -EFAILED; ++ return EFAILED; + + /* Put the other segments after the image. */ + +@@ -383,7 +383,7 @@ int arm64_load_other_segments(struct kex + + if (_ALIGN_UP(initrd_end, GiB(1)) - _ALIGN_DOWN(image_base, GiB(1)) > GiB(32)) { + fprintf(stderr, "kexec: Error: image + initrd too big.\n"); +- return -EFAILED; ++ return EFAILED; + } + + dbgprintf("initrd: base %lx, size %lxh (%ld)\n", +@@ -394,7 +394,7 @@ int arm64_load_other_segments(struct kex + initrd_base + initrd_size); + + if (result) +- return -EFAILED; ++ return EFAILED; + } + } + +@@ -402,7 +402,7 @@ int arm64_load_other_segments(struct kex + + if (dtb.size > MiB(2)) { + fprintf(stderr, "kexec: Error: dtb too big.\n"); +- return -EFAILED; ++ return EFAILED; + } + + dtb_base = add_buffer_phys_virt(info, dtb.buf, dtb.size, dtb.size, +@@ -508,7 +508,7 @@ static int get_memory_ranges_iomem(struc + + if (!*count) { + dbgprintf("%s: failed: No RAM found.\n", __func__); +- return -EFAILED; ++ return EFAILED; + } + + return 0; +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-elf-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +@@ -48,7 +48,7 @@ int elf_arm64_load(int argc, char **argv + + if (info->kexec_flags & KEXEC_ON_CRASH) { + fprintf(stderr, "kexec: kdump not yet supported on arm64\n"); +- return -EFAILED; ++ return EFAILED; + } + + result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); +@@ -92,7 +92,7 @@ int elf_arm64_load(int argc, char **argv + + if (i == ehdr.e_phnum) { + dbgprintf("%s: Valid arm64 header not found\n", __func__); +- result = -EFAILED; ++ result = EFAILED; + goto exit; + } + +@@ -100,7 +100,7 @@ int elf_arm64_load(int argc, char **argv + + if (kernel_segment == ULONG_MAX) { + dbgprintf("%s: Kernel segment is not allocated\n", __func__); +- result = -EFAILED; ++ result = EFAILED; + goto exit; + } + +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-image-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-image-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-image-arm64.c +@@ -36,13 +36,13 @@ int image_arm64_load(int argc, char **ar + header = (const struct arm64_image_header *)(kernel_buf); + + if (arm64_process_image_header(header)) +- return -1; ++ return EFAILED; + + kernel_segment = arm64_locate_kernel_segment(info); + + if (kernel_segment == ULONG_MAX) { + dbgprintf("%s: Kernel segment is not allocated\n", __func__); +- result = -EFAILED; ++ result = EFAILED; + goto exit; + } + diff -Nru kexec-tools-2.0.10/debian/patches/0005-arm64-kdump-identify-memory-regions.patch kexec-tools-2.0.10/debian/patches/0005-arm64-kdump-identify-memory-regions.patch --- kexec-tools-2.0.10/debian/patches/0005-arm64-kdump-identify-memory-regions.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0005-arm64-kdump-identify-memory-regions.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,195 @@ +From c0672c93edcb5bb32800f8d48afa05861ef32a79 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:45 +0900 +Subject: [PATCH 05/11] arm64: kdump: identify memory regions + +The following regions need to be identified for later use: + a) memory regions which belong to the 1st kernel + b) usable memory reserved for crash dump kernel + +We go through /proc/iomem to find out a) and b) which are marked +as "System RAM" and "Crash kernel", respectively. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/Makefile | 2 + + kexec/arch/arm64/crashdump-arm64.c | 109 +++++++++++++++++++++++++++++++++++-- + kexec/arch/arm64/crashdump-arm64.h | 14 ++++- + kexec/arch/arm64/iomem.h | 1 + + 4 files changed, 120 insertions(+), 6 deletions(-) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/Makefile +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/Makefile ++++ kexec-tools-2.0.14/kexec/arch/arm64/Makefile +@@ -6,6 +6,8 @@ arm64_FS2DT_INCLUDE += \ + + arm64_DT_OPS += kexec/dt-ops.c + ++arm64_MEM_REGIONS = kexec/mem_regions.c ++ + arm64_CPPFLAGS += -I $(srcdir)/kexec/ + + arm64_KEXEC_SRCS += \ +Index: kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/crashdump-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.c +@@ -1,5 +1,13 @@ + /* + * ARM64 crashdump. ++ * partly derived from arm implementation ++ * ++ * Copyright (c) 2014-2017 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. + */ + + #define _GNU_SOURCE +@@ -10,12 +18,97 @@ + #include "kexec.h" + #include "crashdump.h" + #include "crashdump-arm64.h" ++#include "iomem.h" + #include "kexec-arm64.h" + #include "kexec-elf.h" ++#include "mem_regions.h" + +-struct memory_ranges usablemem_rgns = {}; ++/* memory ranges on crashed kernel */ ++static struct memory_range system_memory_ranges[CRASH_MAX_MEMORY_RANGES]; ++static struct memory_ranges system_memory_rgns = { ++ .size = 0, ++ .max_size = CRASH_MAX_MEMORY_RANGES, ++ .ranges = system_memory_ranges, ++}; + +-int is_crashkernel_mem_reserved(void) ++/* memory range reserved for crashkernel */ ++struct memory_range crash_reserved_mem; ++struct memory_ranges usablemem_rgns = { ++ .size = 0, ++ .max_size = 1, ++ .ranges = &crash_reserved_mem, ++}; ++ ++/* ++ * iomem_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, respectively, system_memory_ranges and crash_reserved_mem. ++ */ ++ ++static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr), ++ char *str, unsigned long long base, ++ unsigned long long length) + { ++ if (strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)) == 0) ++ return mem_regions_add(&usablemem_rgns, ++ base, length, RANGE_RAM); ++ else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0) ++ return mem_regions_add(&system_memory_rgns, ++ base, length, RANGE_RAM); ++ + return 0; + } ++ ++int is_crashkernel_mem_reserved(void) ++{ ++ if (!usablemem_rgns.size) ++ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); ++ ++ return crash_reserved_mem.start != crash_reserved_mem.end; ++} ++ ++/* ++ * crash_get_memory_ranges() - read system physical memory ++ * ++ * Function reads through system physical memory and stores found memory ++ * regions in system_memory_ranges. ++ * Regions are sorted in ascending order. ++ * ++ * Returns 0 in case of success and a negative value otherwise. ++ */ ++static int crash_get_memory_ranges(void) ++{ ++ /* ++ * First read all memory regions that can be considered as ++ * system memory including the crash area. ++ */ ++ if (!usablemem_rgns.size) ++ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); ++ ++ /* allow only a single region for crash dump kernel */ ++ if (usablemem_rgns.size != 1) ++ return -EINVAL; ++ ++ dbgprint_mem_range("Reserved memory range", &crash_reserved_mem, 1); ++ ++ if (mem_regions_exclude(&system_memory_rgns, &crash_reserved_mem)) { ++ fprintf(stderr, ++ "Error: Number of crash memory ranges excedeed the max limit\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Make sure that the memory regions are sorted. ++ */ ++ mem_regions_sort(&system_memory_rgns); ++ ++ dbgprint_mem_range("Coredump memory ranges", ++ system_memory_rgns.ranges, system_memory_rgns.size); ++} +Index: kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.h +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/crashdump-arm64.h ++++ kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.h +@@ -1,12 +1,22 @@ + /* + * ARM64 crashdump. ++ * ++ * Copyright (c) 2014-2017 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. + */ + +-#if !defined(CRASHDUMP_ARM64_H) ++#ifndef CRASHDUMP_ARM64_H + #define CRASHDUMP_ARM64_H + + #include "kexec.h" + ++#define CRASH_MAX_MEMORY_RANGES 32 ++ + extern struct memory_ranges usablemem_rgns; ++extern struct memory_range crash_reserved_mem; + +-#endif ++#endif /* CRASHDUMP_ARM64_H */ +Index: kexec-tools-2.0.14/kexec/arch/arm64/iomem.h +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/iomem.h ++++ kexec-tools-2.0.14/kexec/arch/arm64/iomem.h +@@ -2,6 +2,7 @@ + #define IOMEM_H + + #define SYSTEM_RAM "System RAM\n" ++#define CRASH_KERNEL "Crash kernel\n" + #define IOMEM_RESERVED "reserved\n" + + #endif diff -Nru kexec-tools-2.0.10/debian/patches/0006-arm64-kdump-add-elf-core-header-segment.patch kexec-tools-2.0.10/debian/patches/0006-arm64-kdump-add-elf-core-header-segment.patch --- kexec-tools-2.0.10/debian/patches/0006-arm64-kdump-add-elf-core-header-segment.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0006-arm64-kdump-add-elf-core-header-segment.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,197 @@ +From 0bd5219da953639276cd17e067c030ac97feca97 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:46 +0900 +Subject: [PATCH 06/11] arm64: kdump: add elf core header segment + +Elf core header contains the information necessary for the coredump of +the 1st kernel, including its physcal memory layout as well as cpu register +states at the panic. +The segment is allocated inside the reserved memory of crash dump kernel. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/crashdump-arm64.c | 98 ++++++++++++++++++++++++++++++++++++++ + kexec/arch/arm64/crashdump-arm64.h | 3 ++ + kexec/arch/arm64/iomem.h | 2 + + kexec/arch/arm64/kexec-elf-arm64.c | 11 +++++ + 4 files changed, 114 insertions(+) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/crashdump-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.c +@@ -39,6 +39,39 @@ struct memory_ranges usablemem_rgns = { + .ranges = &crash_reserved_mem, + }; + ++struct memory_range elfcorehdr_mem; ++ ++static struct crash_elf_info elf_info = { ++ .class = ELFCLASS64, ++#if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ .data = ELFDATA2LSB, ++#else ++ .data = ELFDATA2MSB, ++#endif ++ .machine = EM_AARCH64, ++}; ++ ++/* ++ * Note: The returned value is correct only if !CONFIG_RANDOMIZE_BASE. ++ */ ++static uint64_t get_kernel_page_offset(void) ++{ ++ int i; ++ ++ if (elf_info.kern_vaddr_start == UINT64_MAX) ++ return UINT64_MAX; ++ ++ /* Current max virtual memory range is 48-bits. */ ++ for (i = 48; i > 0; i--) ++ if (!(elf_info.kern_vaddr_start & (1UL << i))) ++ break; ++ ++ if (i <= 0) ++ return UINT64_MAX; ++ else ++ return UINT64_MAX << i; ++} ++ + /* + * iomem_range_callback() - callback called for each iomem region + * @data: not used +@@ -62,6 +95,10 @@ static int iomem_range_callback(void *UN + else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0) + return mem_regions_add(&system_memory_rgns, + base, length, RANGE_RAM); ++ else if (strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) == 0) ++ elf_info.kern_paddr_start = base; ++ else if (strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) == 0) ++ elf_info.kern_size = base + length - elf_info.kern_paddr_start; + + return 0; + } +@@ -111,4 +148,65 @@ static int crash_get_memory_ranges(void) + + dbgprint_mem_range("Coredump memory ranges", + system_memory_rgns.ranges, system_memory_rgns.size); ++ ++ /* ++ * For additional kernel code/data segment. ++ * kern_paddr_start/kern_size are determined in iomem_range_callback ++ */ ++ elf_info.kern_vaddr_start = get_kernel_sym("_text"); ++ if (!elf_info.kern_vaddr_start) ++ elf_info.kern_vaddr_start = UINT64_MAX; ++ ++ return 0; ++} ++ ++/* ++ * load_crashdump_segments() - load the elf core header ++ * @info: kexec info structure ++ * ++ * This function creates and loads an additional segment of elf core header ++ : which is used to construct /proc/vmcore on crash dump kernel. ++ * ++ * Return 0 in case of success and -1 in case of error. ++ */ ++ ++int load_crashdump_segments(struct kexec_info *info) ++{ ++ 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 crash dump kernel during panic. ++ */ ++ ++ err = crash_get_memory_ranges(); ++ ++ if (err) ++ return EFAILED; ++ ++ elf_info.page_offset = get_kernel_page_offset(); ++ dbgprintf("%s: page_offset: %016llx\n", __func__, ++ elf_info.page_offset); ++ ++ err = crash_create_elf64_headers(info, &elf_info, ++ system_memory_rgns.ranges, system_memory_rgns.size, ++ &buf, &bufsz, ELF_CORE_HEADER_ALIGN); ++ ++ if (err) ++ return EFAILED; ++ ++ elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0, ++ crash_reserved_mem.start, crash_reserved_mem.end, ++ -1, 0); ++ ++ elfcorehdr_mem.start = elfcorehdr; ++ elfcorehdr_mem.end = elfcorehdr + bufsz - 1; ++ ++ dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__, ++ elfcorehdr_mem.start, elfcorehdr_mem.end); ++ ++ return 0; + } +Index: kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.h +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/crashdump-arm64.h ++++ kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.h +@@ -18,5 +18,8 @@ + + extern struct memory_ranges usablemem_rgns; + extern struct memory_range crash_reserved_mem; ++extern struct memory_range elfcorehdr_mem; ++ ++extern int load_crashdump_segments(struct kexec_info *info); + + #endif /* CRASHDUMP_ARM64_H */ +Index: kexec-tools-2.0.14/kexec/arch/arm64/iomem.h +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/iomem.h ++++ kexec-tools-2.0.14/kexec/arch/arm64/iomem.h +@@ -2,6 +2,8 @@ + #define IOMEM_H + + #define SYSTEM_RAM "System RAM\n" ++#define KERNEL_CODE "Kernel code\n" ++#define KERNEL_DATA "Kernel data\n" + #define CRASH_KERNEL "Crash kernel\n" + #define IOMEM_RESERVED "reserved\n" + +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-elf-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +@@ -119,6 +119,16 @@ int elf_arm64_load(int argc, char **argv + dbgprintf("%s: PE format: %s\n", __func__, + (arm64_header_check_pe_sig(header) ? "yes" : "no")); + ++ /* create and initialize elf core header segment */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ result = load_crashdump_segments(info); ++ if (result) { ++ dbgprintf("%s: Creating eflcorehdr failed.\n", ++ __func__); ++ goto exit; ++ } ++ } ++ + /* load the kernel */ + result = elf_exec_load(&ehdr, info); + +@@ -127,6 +137,7 @@ int elf_arm64_load(int argc, char **argv + goto exit; + } + ++ /* load additional data */ + result = arm64_load_other_segments(info, kernel_segment + + arm64_mem.text_offset); + diff -Nru kexec-tools-2.0.10/debian/patches/0007-arm64-kdump-set-up-kernel-image-segment.patch kexec-tools-2.0.10/debian/patches/0007-arm64-kdump-set-up-kernel-image-segment.patch --- kexec-tools-2.0.10/debian/patches/0007-arm64-kdump-set-up-kernel-image-segment.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0007-arm64-kdump-set-up-kernel-image-segment.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,136 @@ +From 1591926df5a602ffcbf55e99aa8a96fbebd0bafe Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:47 +0900 +Subject: [PATCH 07/11] arm64: kdump: set up kernel image segment + +On arm64, we can use the same kernel image as 1st kernel, but +we have to modify the entry point as well as segments' addresses +in the kernel's elf header in order to load them into correct places. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/crashdump-arm64.c | 24 ++++++++++++++++++++++++ + kexec/arch/arm64/crashdump-arm64.h | 1 + + kexec/arch/arm64/kexec-arm64.c | 25 ++++++++++++++++++++----- + kexec/arch/arm64/kexec-elf-arm64.c | 11 ++++++++++- + 4 files changed, 55 insertions(+), 6 deletions(-) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/crashdump-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.c +@@ -210,3 +210,27 @@ int load_crashdump_segments(struct kexec + + return 0; + } ++ ++/* ++ * e_entry and p_paddr are actually in virtual address space. ++ * Those values will be translated to physcal addresses by using ++ * virt_to_phys() in add_segment(). ++ * So let's fix up those values for later use so the memory base ++ * (arm64_mm.phys_offset) will be correctly replaced with ++ * crash_reserved_mem.start. ++ */ ++void fixup_elf_addrs(struct mem_ehdr *ehdr) ++{ ++ struct mem_phdr *phdr; ++ int i; ++ ++ ehdr->e_entry += - arm64_mem.phys_offset + crash_reserved_mem.start; ++ ++ for (i = 0; i < ehdr->e_phnum; i++) { ++ phdr = &ehdr->e_phdr[i]; ++ if (phdr->p_type != PT_LOAD) ++ continue; ++ phdr->p_paddr += ++ (-arm64_mem.phys_offset + crash_reserved_mem.start); ++ } ++} +Index: kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.h +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/crashdump-arm64.h ++++ kexec-tools-2.0.14/kexec/arch/arm64/crashdump-arm64.h +@@ -21,5 +21,6 @@ extern struct memory_range crash_reserve + extern struct memory_range elfcorehdr_mem; + + extern int load_crashdump_segments(struct kexec_info *info); ++extern void fixup_elf_addrs(struct mem_ehdr *ehdr); + + #endif /* CRASHDUMP_ARM64_H */ +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +@@ -307,12 +307,27 @@ unsigned long arm64_locate_kernel_segmen + { + unsigned long hole; + +- hole = locate_hole(info, +- arm64_mem.text_offset + arm64_mem.image_size, +- MiB(2), 0, ULONG_MAX, 1); ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ unsigned long hole_end; + +- if (hole == ULONG_MAX) +- dbgprintf("%s: locate_hole failed\n", __func__); ++ hole = (crash_reserved_mem.start < mem_min ? ++ mem_min : crash_reserved_mem.start); ++ hole = _ALIGN_UP(hole, MiB(2)); ++ hole_end = hole + arm64_mem.text_offset + arm64_mem.image_size; ++ ++ if ((hole_end > mem_max) || ++ (hole_end > crash_reserved_mem.end)) { ++ dbgprintf("%s: Crash kernel out of range\n", __func__); ++ hole = ULONG_MAX; ++ } ++ } else { ++ 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; + } +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-elf-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +@@ -9,6 +9,7 @@ + #include + #include + ++#include "crashdump-arm64.h" + #include "kexec-arm64.h" + #include "kexec-elf.h" + #include "kexec-syscall.h" +@@ -105,7 +106,8 @@ int elf_arm64_load(int argc, char **argv + } + + arm64_mem.vp_offset = _ALIGN_DOWN(ehdr.e_entry, MiB(2)); +- arm64_mem.vp_offset -= kernel_segment - get_phys_offset(); ++ if (!(info->kexec_flags & KEXEC_ON_CRASH)) ++ 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__, +@@ -130,6 +132,13 @@ int elf_arm64_load(int argc, char **argv + } + + /* load the kernel */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ /* ++ * offset addresses in elf header in order to load ++ * vmlinux (elf_exec) into crash kernel's memory ++ */ ++ fixup_elf_addrs(&ehdr); ++ + result = elf_exec_load(&ehdr, info); + + if (result) { diff -Nru kexec-tools-2.0.10/debian/patches/0008-arm64-kdump-set-up-other-segments.patch kexec-tools-2.0.10/debian/patches/0008-arm64-kdump-set-up-other-segments.patch --- kexec-tools-2.0.10/debian/patches/0008-arm64-kdump-set-up-other-segments.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0008-arm64-kdump-set-up-other-segments.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,32 @@ +From defad947feff0d0135f79893e99ca94ec9a59e0f Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:48 +0900 +Subject: [PATCH 08/11] arm64: kdump: set up other segments + +We make sure that all the other segments, initrd and device-tree blob, +also be loaded into the reserved memory of crash dump kernel. + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/kexec-arm64.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +@@ -375,7 +375,10 @@ int arm64_load_other_segments(struct kex + /* Put the other segments after the image. */ + + hole_min = image_base + arm64_mem.image_size; +- hole_max = ULONG_MAX; ++ if (info->kexec_flags & KEXEC_ON_CRASH) ++ hole_max = crash_reserved_mem.end; ++ else ++ hole_max = ULONG_MAX; + + if (arm64_opts.initrd) { + initrd_buf = slurp_file(arm64_opts.initrd, &initrd_size); diff -Nru kexec-tools-2.0.10/debian/patches/0009-arm64-kdump-add-DT-properties-to-crash-dump-kernel-s.patch kexec-tools-2.0.10/debian/patches/0009-arm64-kdump-add-DT-properties-to-crash-dump-kernel-s.patch --- kexec-tools-2.0.10/debian/patches/0009-arm64-kdump-add-DT-properties-to-crash-dump-kernel-s.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0009-arm64-kdump-add-DT-properties-to-crash-dump-kernel-s.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,279 @@ +From 5f955585c7c9166da5b8f33e3d8a4c43845ee70b Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 17 May 2017 14:51:49 +0900 +Subject: [PATCH 09/11] arm64: kdump: add DT properties to crash dump kernel's + dtb + +We pass the following properties to crash dump kernel: +linux,elfcorehdr: elf core header segment, + same as "elfcorehdr=" kernel parameter on other archs +linux,usable-memory-range: usable memory reserved for crash dump kernel + +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/kexec-arm64.c | 197 ++++++++++++++++++++++++++++++++++++- + kexec/arch/arm64/kexec-elf-arm64.c | 5 - + 2 files changed, 192 insertions(+), 10 deletions(-) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-arm64.c +@@ -25,6 +25,14 @@ + #include "kexec-syscall.h" + #include "arch/options.h" + ++#define ROOT_NODE_ADDR_CELLS_DEFAULT 1 ++#define ROOT_NODE_SIZE_CELLS_DEFAULT 1 ++ ++#define PROP_ADDR_CELLS "#address-cells" ++#define PROP_SIZE_CELLS "#size-cells" ++#define PROP_ELFCOREHDR "linux,elfcorehdr" ++#define PROP_USABLE_MEM_RANGE "linux,usable-memory-range" ++ + /* Global varables the core kexec routines expect. */ + + unsigned char reuse_initrd; +@@ -128,9 +136,6 @@ int arch_process_options(int argc, char + 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. */ + } +@@ -281,12 +286,115 @@ on_success: + return 0; + } + ++static int get_cells_size(void *fdt, uint32_t *address_cells, ++ uint32_t *size_cells) ++{ ++ int nodeoffset; ++ const uint32_t *prop = NULL; ++ int prop_len; ++ ++ /* default values */ ++ *address_cells = ROOT_NODE_ADDR_CELLS_DEFAULT; ++ *size_cells = ROOT_NODE_SIZE_CELLS_DEFAULT; ++ ++ /* under root node */ ++ nodeoffset = fdt_path_offset(fdt, "/"); ++ if (nodeoffset < 0) ++ goto on_error; ++ ++ prop = fdt_getprop(fdt, nodeoffset, PROP_ADDR_CELLS, &prop_len); ++ if (prop) { ++ if (prop_len == sizeof(*prop)) ++ *address_cells = fdt32_to_cpu(*prop); ++ else ++ goto on_error; ++ } ++ ++ prop = fdt_getprop(fdt, nodeoffset, PROP_SIZE_CELLS, &prop_len); ++ if (prop) { ++ if (prop_len == sizeof(*prop)) ++ *size_cells = fdt32_to_cpu(*prop); ++ else ++ goto on_error; ++ } ++ ++ dbgprintf("%s: #address-cells:%d #size-cells:%d\n", __func__, ++ *address_cells, *size_cells); ++ return 0; ++ ++on_error: ++ return EFAILED; ++} ++ ++static bool cells_size_fitted(uint32_t address_cells, uint32_t size_cells, ++ struct memory_range *range) ++{ ++ dbgprintf("%s: %llx-%llx\n", __func__, range->start, range->end); ++ ++ /* if *_cells >= 2, cells can hold 64-bit values anyway */ ++ if ((address_cells == 1) && (range->start >= (1ULL << 32))) ++ return false; ++ ++ if ((size_cells == 1) && ++ ((range->end - range->start + 1) >= (1ULL << 32))) ++ return false; ++ ++ return true; ++} ++ ++static void fill_property(void *buf, uint64_t val, uint32_t cells) ++{ ++ uint32_t val32; ++ int i; ++ ++ if (cells == 1) { ++ val32 = cpu_to_fdt32((uint32_t)val); ++ memcpy(buf, &val32, sizeof(uint32_t)); ++ } else { ++ for (i = 0; ++ i < (cells * sizeof(uint32_t) - sizeof(uint64_t)); i++) ++ *(char *)buf++ = 0; ++ ++ val = cpu_to_fdt64(val); ++ memcpy(buf, &val, sizeof(uint64_t)); ++ } ++} ++ ++static int fdt_setprop_range(void *fdt, int nodeoffset, ++ const char *name, struct memory_range *range, ++ uint32_t address_cells, uint32_t size_cells) ++{ ++ void *buf, *prop; ++ size_t buf_size; ++ int result; ++ ++ buf_size = (address_cells + size_cells) * sizeof(uint32_t); ++ prop = buf = xmalloc(buf_size); ++ ++ fill_property(prop, range->start, address_cells); ++ prop += address_cells * sizeof(uint32_t); ++ ++ fill_property(prop, range->end - range->start + 1, size_cells); ++ prop += size_cells * sizeof(uint32_t); ++ ++ result = fdt_setprop(fdt, nodeoffset, name, buf, buf_size); ++ ++ free(buf); ++ ++ return result; ++} ++ + /** + * setup_2nd_dtb - Setup the 2nd stage kernel's dtb. + */ + +-static int setup_2nd_dtb(struct dtb *dtb, char *command_line) ++static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash) + { ++ uint32_t address_cells, size_cells; ++ int range_len; ++ int nodeoffset; ++ char *new_buf = NULL; ++ int new_size; + int result; + + result = fdt_check_header(dtb->buf); +@@ -298,8 +406,86 @@ static int setup_2nd_dtb(struct dtb *dtb + + result = set_bootargs(dtb, command_line); + ++ if (on_crash) { ++ /* determine #address-cells and #size-cells */ ++ result = get_cells_size(dtb->buf, &address_cells, &size_cells); ++ if (result) { ++ fprintf(stderr, ++ "kexec: cannot determine cells-size.\n"); ++ result = -EINVAL; ++ goto on_error; ++ } ++ ++ if (!cells_size_fitted(address_cells, size_cells, ++ &elfcorehdr_mem)) { ++ fprintf(stderr, ++ "kexec: elfcorehdr doesn't fit cells-size.\n"); ++ result = -EINVAL; ++ goto on_error; ++ } ++ ++ if (!cells_size_fitted(address_cells, size_cells, ++ &crash_reserved_mem)) { ++ fprintf(stderr, ++ "kexec: usable memory range doesn't fit cells-size.\n"); ++ result = -EINVAL; ++ goto on_error; ++ } ++ ++ /* duplicate dt blob */ ++ range_len = sizeof(uint32_t) * (address_cells + size_cells); ++ new_size = fdt_totalsize(dtb->buf) ++ + fdt_prop_len(PROP_ELFCOREHDR, range_len) ++ + fdt_prop_len(PROP_USABLE_MEM_RANGE, range_len); ++ ++ new_buf = xmalloc(new_size); ++ result = fdt_open_into(dtb->buf, new_buf, new_size); ++ if (result) { ++ dbgprintf("%s: fdt_open_into failed: %s\n", __func__, ++ fdt_strerror(result)); ++ result = -ENOSPC; ++ goto on_error; ++ } ++ ++ /* add linux,elfcorehdr */ ++ nodeoffset = fdt_path_offset(new_buf, "/chosen"); ++ result = fdt_setprop_range(new_buf, nodeoffset, ++ PROP_ELFCOREHDR, &elfcorehdr_mem, ++ address_cells, size_cells); ++ if (result) { ++ dbgprintf("%s: fdt_setprop failed: %s\n", __func__, ++ fdt_strerror(result)); ++ result = -EINVAL; ++ goto on_error; ++ } ++ ++ /* add linux,usable-memory-range */ ++ nodeoffset = fdt_path_offset(new_buf, "/chosen"); ++ result = fdt_setprop_range(new_buf, nodeoffset, ++ PROP_USABLE_MEM_RANGE, &crash_reserved_mem, ++ address_cells, size_cells); ++ if (result) { ++ dbgprintf("%s: fdt_setprop failed: %s\n", __func__, ++ fdt_strerror(result)); ++ result = -EINVAL; ++ goto on_error; ++ } ++ ++ fdt_pack(new_buf); ++ dtb->buf = new_buf; ++ dtb->size = fdt_totalsize(new_buf); ++ } ++ + dump_reservemap(dtb); + ++ ++ return result; ++ ++on_error: ++ fprintf(stderr, "kexec: %s failed.\n", __func__); ++ if (new_buf) ++ free(new_buf); ++ + return result; + } + +@@ -367,7 +553,8 @@ int arm64_load_other_segments(struct kex + } + } + +- result = setup_2nd_dtb(&dtb, command_line); ++ result = setup_2nd_dtb(&dtb, command_line, ++ info->kexec_flags & KEXEC_ON_CRASH); + + if (result) + return EFAILED; +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-elf-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-elf-arm64.c +@@ -47,11 +47,6 @@ int elf_arm64_load(int argc, char **argv + 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) { diff -Nru kexec-tools-2.0.10/debian/patches/0010-arm64-kdump-Add-support-for-binary-image-files.patch kexec-tools-2.0.10/debian/patches/0010-arm64-kdump-Add-support-for-binary-image-files.patch --- kexec-tools-2.0.10/debian/patches/0010-arm64-kdump-Add-support-for-binary-image-files.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/0010-arm64-kdump-Add-support-for-binary-image-files.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,55 @@ +From c504ff5d85aa035aed9f14f5ce96c5d959952dd9 Mon Sep 17 00:00:00 2001 +From: Pratyush Anand +Date: Wed, 17 May 2017 14:51:50 +0900 +Subject: [PATCH 10/11] arm64: kdump: Add support for binary image files + +This patch adds support to use binary image ie arch/arm64/boot/Image with +kdump. + +Signed-off-by: Pratyush Anand +[takahiro.akashi@linaro.org: a bit reworked] +Signed-off-by: AKASHI Takahiro +Tested-by: David Woodhouse +Tested-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/arch/arm64/kexec-image-arm64.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Index: kexec-tools-2.0.14/kexec/arch/arm64/kexec-image-arm64.c +=================================================================== +--- kexec-tools-2.0.14.orig/kexec/arch/arm64/kexec-image-arm64.c ++++ kexec-tools-2.0.14/kexec/arch/arm64/kexec-image-arm64.c +@@ -4,7 +4,9 @@ + + #define _GNU_SOURCE + ++#include "crashdump-arm64.h" + #include "kexec-arm64.h" ++#include "kexec-syscall.h" + #include + + int image_arm64_probe(const char *kernel_buf, off_t kernel_size) +@@ -58,11 +60,22 @@ int image_arm64_load(int argc, char **ar + dbgprintf("%s: PE format: %s\n", __func__, + (arm64_header_check_pe_sig(header) ? "yes" : "no")); + ++ /* create and initialize elf core header segment */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ result = load_crashdump_segments(info); ++ if (result) { ++ dbgprintf("%s: Creating eflcorehdr failed.\n", ++ __func__); ++ goto exit; ++ } ++ } ++ + /* load the kernel */ + add_segment_phys_virt(info, kernel_buf, kernel_size, + kernel_segment + arm64_mem.text_offset, + arm64_mem.image_size, 0); + ++ /* load additional data */ + result = arm64_load_other_segments(info, kernel_segment + + arm64_mem.text_offset); + diff -Nru kexec-tools-2.0.10/debian/patches/arm-fix-get_kernel_stext_sym-to-close-its-file.patch kexec-tools-2.0.10/debian/patches/arm-fix-get_kernel_stext_sym-to-close-its-file.patch --- kexec-tools-2.0.10/debian/patches/arm-fix-get_kernel_stext_sym-to-close-its-file.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/arm-fix-get_kernel_stext_sym-to-close-its-file.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,64 @@ +From 38c18bb7d1e2db23491619928ca722750d510ce5 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 6 Jun 2016 18:00:00 +0100 +Subject: [PATCH 01/16] arm: fix get_kernel_stext_sym() to close its file + +Fix get_kernel_stext_sym() so that it closes its file once it's +finsihed with it - there's no need to leak file descriptors. + +Reviewed-by: Pratyush Anand +Signed-off-by: Russell King +Signed-off-by: Simon Horman +--- + kexec/arch/arm/crashdump-arm.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/kexec/arch/arm/crashdump-arm.c b/kexec/arch/arm/crashdump-arm.c +index b523e5f..a390187 100644 +--- a/kexec/arch/arm/crashdump-arm.c ++++ b/kexec/arch/arm/crashdump-arm.c +@@ -71,25 +71,34 @@ static unsigned long long get_kernel_stext_sym(void) + char sym[128]; + char line[128]; + FILE *fp; +- unsigned long long vaddr; ++ unsigned long long vaddr = 0; + char type; + +- fp = fopen(kallsyms, "r"); if (!fp) { ++ fp = fopen(kallsyms, "r"); ++ if (!fp) { + fprintf(stderr, "Cannot open %s\n", kallsyms); + return 0; + } + + while(fgets(line, sizeof(line), fp) != NULL) { +- if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) ++ unsigned long long addr; ++ ++ if (sscanf(line, "%Lx %c %s", &addr, &type, sym) != 3) + continue; ++ + if (strcmp(sym, stext) == 0) { +- dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr); +- return vaddr; ++ dbgprintf("kernel symbol %s vaddr = %#llx\n", stext, addr); ++ vaddr = addr; ++ break; + } + } + +- fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); +- return 0; ++ fclose(fp); ++ ++ if (vaddr == 0) ++ fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); ++ ++ return vaddr; + } + + static int get_kernel_page_offset(struct kexec_info *info, +-- +2.11.0 + diff -Nru kexec-tools-2.0.10/debian/patches/kexec-add-generic-helper-to-add-to-memory_regions.patch kexec-tools-2.0.10/debian/patches/kexec-add-generic-helper-to-add-to-memory_regions.patch --- kexec-tools-2.0.10/debian/patches/kexec-add-generic-helper-to-add-to-memory_regions.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/kexec-add-generic-helper-to-add-to-memory_regions.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,81 @@ +From ba1e37a8ede8d7d981c677ef7273e01aec88da7f Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 6 Jun 2016 17:59:34 +0100 +Subject: [PATCH] kexec: add generic helper to add to memory_regions + +Add a helper to add a memory range to a memory_regions array. + +Reviewed-by: Pratyush Anand +Signed-off-by: Russell King +Signed-off-by: Simon Horman +--- + kexec/Makefile | 4 ++++ + kexec/mem_regions.c | 29 +++++++++++++++++++++++++++++ + kexec/mem_regions.h | 9 +++++++++ + 3 files changed, 42 insertions(+) + create mode 100644 kexec/mem_regions.c + create mode 100644 kexec/mem_regions.h + +Index: kexec-tools-2.0.10/kexec/Makefile +=================================================================== +--- kexec-tools-2.0.10.orig/kexec/Makefile ++++ kexec-tools-2.0.10/kexec/Makefile +@@ -73,6 +73,10 @@ dist += kexec/dt-ops.c kexec/dt-ops.h + $(ARCH)_DT_OPS = + KEXEC_SRCS += $($(ARCH)_DT_OPS) + ++dist += kexec/mem_regions.c kexec/mem_regions.h ++$(ARCH)_MEM_REGIONS = ++KEXEC_SRCS += $($(ARCH)_MEM_REGIONS) ++ + include $(srcdir)/kexec/arch/alpha/Makefile + include $(srcdir)/kexec/arch/arm/Makefile + include $(srcdir)/kexec/arch/arm64/Makefile +Index: kexec-tools-2.0.10/kexec/mem_regions.c +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.10/kexec/mem_regions.c +@@ -0,0 +1,29 @@ ++#include "kexec.h" ++#include "mem_regions.h" ++ ++/** ++ * mem_regions_add() - add a memory region to a set of ranges ++ * @ranges: ranges to add the memory region to ++ * @max: maximum number of entries in memory region ++ * @base: base address of memory region ++ * @length: length of memory region in bytes ++ * @type: type of memory region ++ * ++ * Add the memory region to the set of ranges, and return %0 if successful, ++ * or %-1 if we ran out of space. ++ */ ++int mem_regions_add(struct memory_ranges *ranges, unsigned long long base, ++ unsigned long long length, int type) ++{ ++ struct memory_range *range; ++ ++ if (ranges->size >= ranges->max_size) ++ return -1; ++ ++ range = ranges->ranges + ranges->size++; ++ range->start = base; ++ range->end = base + length - 1; ++ range->type = type; ++ ++ return 0; ++} +Index: kexec-tools-2.0.10/kexec/mem_regions.h +=================================================================== +--- /dev/null ++++ kexec-tools-2.0.10/kexec/mem_regions.h +@@ -0,0 +1,9 @@ ++#ifndef MEM_REGIONS_H ++#define MEM_REGIONS_H ++ ++struct memory_ranges; ++ ++int mem_regions_add(struct memory_ranges *ranges, unsigned long long base, ++ unsigned long long length, int type); ++ ++#endif diff -Nru kexec-tools-2.0.10/debian/patches/kexec-add-helper-to-exlude-a-region-from-a-set-of-me.patch kexec-tools-2.0.10/debian/patches/kexec-add-helper-to-exlude-a-region-from-a-set-of-me.patch --- kexec-tools-2.0.10/debian/patches/kexec-add-helper-to-exlude-a-region-from-a-set-of-me.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/kexec-add-helper-to-exlude-a-region-from-a-set-of-me.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,117 @@ +From 61ac72aefb9e7c2c3b8ae79cb031a2cc84e27dd8 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 6 Jun 2016 17:59:44 +0100 +Subject: [PATCH] kexec: add helper to exlude a region from a set of memory + ranges + +Add a helper to exclude a region from a set of memory ranges. + +Signed-off-by: Russell King +Reviewed-by: Pratyush Anand +Signed-off-by: Simon Horman +--- + kexec/mem_regions.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + kexec/mem_regions.h | 4 +++ + 2 files changed, 76 insertions(+) + +diff --git a/kexec/mem_regions.c b/kexec/mem_regions.c +index 7b4bcf3..b01a5c8 100644 +--- a/kexec/mem_regions.c ++++ b/kexec/mem_regions.c +@@ -54,3 +54,75 @@ int mem_regions_add(struct memory_ranges *ranges, unsigned long long base, + + return 0; + } ++ ++static void mem_regions_remove(struct memory_ranges *ranges, int index) ++{ ++ int tail_entries; ++ ++ /* we are assured to have at least one entry */ ++ ranges->size -= 1; ++ ++ /* if we have following entries, shuffle them down one place */ ++ tail_entries = ranges->size - index; ++ if (tail_entries) ++ memmove(ranges->ranges + index, ranges->ranges + index + 1, ++ tail_entries * sizeof(*ranges->ranges)); ++ ++ /* zero the new tail entry */ ++ memset(ranges->ranges + ranges->size, 0, sizeof(*ranges->ranges)); ++} ++ ++/** ++ * mem_regions_exclude() - excludes a memory region from a set of memory ranges ++ * @ranges: memory ranges to exclude the region from ++ * @range: memory range to exclude ++ * ++ * Exclude a memory region from a set of memory ranges. We assume that ++ * the region to be excluded is either wholely located within one of the ++ * memory ranges, or not at all. ++ */ ++int mem_regions_exclude(struct memory_ranges *ranges, ++ const struct memory_range *range) ++{ ++ int i, ret; ++ ++ for (i = 0; i < ranges->size; i++) { ++ struct memory_range *r = ranges->ranges + i; ++ ++ /* ++ * We assume that crash area is fully contained in ++ * some larger memory area. ++ */ ++ if (r->start <= range->start && r->end >= range->end) { ++ if (r->start == range->start) { ++ if (r->end == range->end) ++ /* Remove this entry */ ++ mem_regions_remove(ranges, i); ++ else ++ /* Shrink the start of this memory range */ ++ r->start = range->end + 1; ++ } else if (r->end == range->end) { ++ /* Shrink the end of this memory range */ ++ r->end = range->start - 1; ++ } else { ++ /* ++ * Split this area into 2 smaller ones and ++ * remove excluded range from between. First ++ * create new entry for the remaining area. ++ */ ++ ret = mem_regions_add(ranges, range->end + 1, ++ r->end - range->end, 0); ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * Update this area to end before excluded ++ * range. ++ */ ++ r->end = range->start - 1; ++ break; ++ } ++ } ++ } ++ return 0; ++} +diff --git a/kexec/mem_regions.h b/kexec/mem_regions.h +index da7b5e8..ae9e972 100644 +--- a/kexec/mem_regions.h ++++ b/kexec/mem_regions.h +@@ -2,9 +2,13 @@ + #define MEM_REGIONS_H + + struct memory_ranges; ++struct memory_range; + + void mem_regions_sort(struct memory_ranges *ranges); + ++int mem_regions_exclude(struct memory_ranges *ranges, ++ const struct memory_range *range); ++ + int mem_regions_add(struct memory_ranges *ranges, unsigned long long base, + unsigned long long length, int type); + +-- +2.11.0 + diff -Nru kexec-tools-2.0.10/debian/patches/kexec-add-max_size-to-memory_ranges.patch kexec-tools-2.0.10/debian/patches/kexec-add-max_size-to-memory_ranges.patch --- kexec-tools-2.0.10/debian/patches/kexec-add-max_size-to-memory_ranges.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/kexec-add-max_size-to-memory_ranges.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,31 @@ +From 5450d34a886445e0787c432ff9aaa04b55b0f4c0 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 6 Jun 2016 17:59:24 +0100 +Subject: [PATCH] kexec: add max_size to memory_ranges + +Many implementations statically allocate the memory range array, which +therefore will have a maximum allowable size. Add this information to +the memory_ranges structure, so we don't have to carry it around. + +Reviewed-by: Pratyush Anand +Signed-off-by: Russell King +Signed-off-by: Simon Horman +--- + kexec/kexec.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kexec/kexec.h b/kexec/kexec.h +index c02ac8f..9194f1c 100644 +--- a/kexec/kexec.h ++++ b/kexec/kexec.h +@@ -142,6 +142,7 @@ struct memory_range { + + struct memory_ranges { + unsigned int size; ++ unsigned int max_size; + struct memory_range *ranges; + }; + +-- +2.11.0 + diff -Nru kexec-tools-2.0.10/debian/patches/kexec-add-mem_regions-sorting-implementation.patch kexec-tools-2.0.10/debian/patches/kexec-add-mem_regions-sorting-implementation.patch --- kexec-tools-2.0.10/debian/patches/kexec-add-mem_regions-sorting-implementation.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/kexec-add-mem_regions-sorting-implementation.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,69 @@ +From 7dc06a544ffd192634d624af163791dca791e845 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 6 Jun 2016 17:59:39 +0100 +Subject: [PATCH] kexec: add mem_regions sorting implementation + +Add a mem_regions sorting implementation taken from the arm code. + +Reviewed-by: Pratyush Anand +Signed-off-by: Russell King +Signed-off-by: Simon Horman +--- + kexec/mem_regions.c | 27 +++++++++++++++++++++++++++ + kexec/mem_regions.h | 2 ++ + 2 files changed, 29 insertions(+) + +diff --git a/kexec/mem_regions.c b/kexec/mem_regions.c +index 4425b86..7b4bcf3 100644 +--- a/kexec/mem_regions.c ++++ b/kexec/mem_regions.c +@@ -1,6 +1,33 @@ ++#include ++ + #include "kexec.h" + #include "mem_regions.h" + ++static int mem_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; ++} ++ ++/** ++ * mem_regions_sort() - sort ranges into ascending address order ++ * @ranges: ranges to sort ++ * ++ * Sort the memory regions into ascending address order. ++ */ ++void mem_regions_sort(struct memory_ranges *ranges) ++{ ++ qsort(ranges->ranges, ranges->size, sizeof(ranges->ranges), ++ mem_range_cmp); ++} ++ + /** + * mem_regions_add() - add a memory region to a set of ranges + * @ranges: ranges to add the memory region to +diff --git a/kexec/mem_regions.h b/kexec/mem_regions.h +index b9cfba1..da7b5e8 100644 +--- a/kexec/mem_regions.h ++++ b/kexec/mem_regions.h +@@ -3,6 +3,8 @@ + + struct memory_ranges; + ++void mem_regions_sort(struct memory_ranges *ranges); ++ + int mem_regions_add(struct memory_ranges *ranges, unsigned long long base, + unsigned long long length, int type); + +-- +2.11.0 + diff -Nru kexec-tools-2.0.10/debian/patches/kexec-arch-i386-Add-support-for-KASLR-memory-randomi.patch kexec-tools-2.0.10/debian/patches/kexec-arch-i386-Add-support-for-KASLR-memory-randomi.patch --- kexec-tools-2.0.10/debian/patches/kexec-arch-i386-Add-support-for-KASLR-memory-randomi.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/kexec-arch-i386-Add-support-for-KASLR-memory-randomi.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,94 @@ +From 9f62cbddddfc93d78d9aafbddf3e1208cb242f7b Mon Sep 17 00:00:00 2001 +From: Thomas Garnier +Date: Tue, 13 Sep 2016 15:10:05 +0800 +Subject: [PATCH] kexec/arch/i386: Add support for KASLR memory randomization + +Multiple changes were made on KASLR (right now in linux-next). One of +them is randomizing the virtual address of the physical mapping, vmalloc +and vmemmap memory sections. It breaks kdump ability to read physical +memory. + +This change identifies if KASLR memories randomization is used by +checking if the page_offset_base variable exists. It search for the +correct PAGE_OFFSET value by looking at the loaded memory section and +find the lowest aligned on PUD (the randomization level). + +Related commits on linux-next: + - 0483e1fa6e09d4948272680f691dccb1edb9677f: Base for randomization + - 021182e52fe01c1f7b126f97fd6ba048dc4234fd: Enable for PAGE_OFFSET + +Signed-off-by: Thomas Garnier +Signed-off-by: Simon Horman +--- + kexec/arch/i386/crashdump-x86.c | 29 ++++++++++++++++++++++------- + 1 file changed, 22 insertions(+), 7 deletions(-) + +Index: kexec-tools-2.0.10/kexec/arch/i386/crashdump-x86.c +=================================================================== +--- kexec-tools-2.0.10.orig/kexec/arch/i386/crashdump-x86.c ++++ kexec-tools-2.0.10/kexec/arch/i386/crashdump-x86.c +@@ -101,11 +101,10 @@ static int get_kernel_paddr(struct kexec + return -1; + } + +-/* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ +-static unsigned long long get_kernel_stext_sym(void) ++/* Retrieve kernel symbol virtual address from /proc/kallsyms */ ++static unsigned long long get_kernel_sym(const char *symbol) + { + const char *kallsyms = "/proc/kallsyms"; +- const char *stext = "_stext"; + char sym[128]; + char line[128]; + FILE *fp; +@@ -121,13 +120,13 @@ static unsigned long long get_kernel_ste + while(fgets(line, sizeof(line), fp) != NULL) { + if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) + continue; +- if (strcmp(sym, stext) == 0) { +- dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr); ++ if (strcmp(sym, symbol) == 0) { ++ dbgprintf("kernel symbol %s vaddr = %16llx\n", symbol, vaddr); + return vaddr; + } + } + +- fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); ++ fprintf(stderr, "Cannot get kernel %s symbol address\n", symbol); + return 0; + } + +@@ -150,6 +149,8 @@ static int get_kernel_vaddr_and_size(str + off_t size; + uint32_t elf_flags = 0; + uint64_t stext_sym; ++ const unsigned long long pud_mask = ~((1 << 30) - 1); ++ unsigned long long vaddr, lowest_vaddr = 0; + + if (elf_info->machine != EM_X86_64) + return 0; +@@ -179,9 +180,23 @@ static int get_kernel_vaddr_and_size(str + + end_phdr = &ehdr.e_phdr[ehdr.e_phnum]; + ++ /* Search for the real PAGE_OFFSET when KASLR memory randomization ++ * is enabled */ ++ if (get_kernel_sym("page_offset_base") != 0) { ++ for(phdr = ehdr.e_phdr; phdr != end_phdr; phdr++) { ++ if (phdr->p_type == PT_LOAD) { ++ vaddr = phdr->p_vaddr & pud_mask; ++ if (lowest_vaddr == 0 || lowest_vaddr > vaddr) ++ lowest_vaddr = vaddr; ++ } ++ } ++ if (lowest_vaddr != 0) ++ elf_info->page_offset = lowest_vaddr; ++ } ++ + /* Traverse through the Elf headers and find the region where + * _stext symbol is located in. That's where kernel is mapped */ +- stext_sym = get_kernel_stext_sym(); ++ stext_sym = get_kernel_sym("_stext"); + for(phdr = ehdr.e_phdr; stext_sym && phdr != end_phdr; phdr++) { + if (phdr->p_type == PT_LOAD) { + unsigned long long saddr = phdr->p_vaddr; diff -Nru kexec-tools-2.0.10/debian/patches/kexec-fix-mem_regions_sort.patch kexec-tools-2.0.10/debian/patches/kexec-fix-mem_regions_sort.patch --- kexec-tools-2.0.10/debian/patches/kexec-fix-mem_regions_sort.patch 1970-01-01 00:00:00.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/kexec-fix-mem_regions_sort.patch 2017-06-23 18:27:21.000000000 +0000 @@ -0,0 +1,32 @@ +From 9fd57cad8a0f1e0c7a342f014e1cc8ee31d72261 Mon Sep 17 00:00:00 2001 +From: Pratyush Anand +Date: Wed, 27 Jul 2016 23:19:42 +0530 +Subject: [PATCH] kexec: fix mem_regions_sort() + +ranges->ranges is "struct memory_range *", however each element which need +to be sorted is of type "struct memory_range". So, correct "size" argument +of qsort() as sizeof(*ranges->ranges). + +Signed-off-by: Pratyush Anand +Acked-by: Russell King +Signed-off-by: Simon Horman +--- + kexec/mem_regions.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kexec/mem_regions.c b/kexec/mem_regions.c +index e61c074..50c8abc 100644 +--- a/kexec/mem_regions.c ++++ b/kexec/mem_regions.c +@@ -24,7 +24,7 @@ static int mem_range_cmp(const void *a1, const void *a2) + */ + void mem_regions_sort(struct memory_ranges *ranges) + { +- qsort(ranges->ranges, ranges->size, sizeof(ranges->ranges), ++ qsort(ranges->ranges, ranges->size, sizeof(*ranges->ranges), + mem_range_cmp); + } + +-- +2.11.0 + diff -Nru kexec-tools-2.0.10/debian/patches/series kexec-tools-2.0.10/debian/patches/series --- kexec-tools-2.0.10/debian/patches/series 2017-03-09 00:57:31.000000000 +0000 +++ kexec-tools-2.0.10/debian/patches/series 2017-06-23 18:27:21.000000000 +0000 @@ -21,3 +21,20 @@ kexec-phys_to_virt-must-take-unsigned-long-long.patch kexec-Increase-the-upper-limit-for-RAM-segments.patch arm-do-not-build-iomem.o-target-with-no-soruce.patch +arm-fix-get_kernel_stext_sym-to-close-its-file.patch +kexec-add-max_size-to-memory_ranges.patch +kexec-add-generic-helper-to-add-to-memory_regions.patch +kexec-add-mem_regions-sorting-implementation.patch +kexec-add-helper-to-exlude-a-region-from-a-set-of-me.patch +kexec-fix-mem_regions_sort.patch +kexec-arch-i386-Add-support-for-KASLR-memory-randomi.patch +0001-kexec-extend-the-semantics-of-kexec_iomem_for_each_l.patch +0002-kexec-generalize-and-rename-get_kernel_stext_sym.patch +0003-arm64-identify-PHYS_OFFSET-correctly.patch +0004-arm64-change-return-values-on-error-to-negative.patch +0005-arm64-kdump-identify-memory-regions.patch +0006-arm64-kdump-add-elf-core-header-segment.patch +0007-arm64-kdump-set-up-kernel-image-segment.patch +0008-arm64-kdump-set-up-other-segments.patch +0009-arm64-kdump-add-DT-properties-to-crash-dump-kernel-s.patch +0010-arm64-kdump-Add-support-for-binary-image-files.patch diff -Nru kexec-tools-2.0.10/debian/rules kexec-tools-2.0.10/debian/rules --- kexec-tools-2.0.10/debian/rules 2016-03-25 15:55:53.000000000 +0000 +++ kexec-tools-2.0.10/debian/rules 2017-06-23 18:27:52.000000000 +0000 @@ -67,7 +67,7 @@ # Add here commands to install the package into debian/tmp. $(MAKE) install DESTDIR=$(CURDIR)/debian/kexec-tools -ifneq (,$(filter $(DEB_HOST_ARCH),i386 amd64 powerpc ppc64 ppc64el ia64)) +ifneq (,$(filter $(DEB_HOST_ARCH),i386 amd64 powerpc ppc64 ppc64el ia64 arm64)) install -m644 debian/kexec-tools.grub \ debian/kexec-tools/etc/default/grub.d/kexec-tools.cfg endif