|
|
a6d77e |
From 9cd9f0ab98ce6ddbdbb9a045ed2887e0dd857afe Mon Sep 17 00:00:00 2001
|
|
|
a6d77e |
Message-Id: <9cd9f0ab98ce6ddbdbb9a045ed2887e0dd857afe.1431592766.git.panand@redhat.com>
|
|
|
a6d77e |
In-Reply-To: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com>
|
|
|
a6d77e |
References: <1fb6841aa15407dbf371589d7abca7bc2d35815c.1431592766.git.panand@redhat.com>
|
|
|
a6d77e |
From: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
|
|
a6d77e |
Date: Tue, 17 Feb 2015 16:06:55 +0900
|
|
|
a6d77e |
Subject: [PATCH 08/17] arm64: kdump: create elf core header
|
|
|
a6d77e |
|
|
|
a6d77e |
---
|
|
|
a6d77e |
kexec/arch/arm64/crashdump-arm64.c | 295 ++++++++++++++++++++++++++++++++++++-
|
|
|
a6d77e |
kexec/arch/arm64/crashdump-arm64.h | 17 ++-
|
|
|
a6d77e |
kexec/arch/arm64/kexec-arm64.c | 4 +-
|
|
|
a6d77e |
kexec/arch/arm64/kexec-elf-arm64.c | 31 +++-
|
|
|
a6d77e |
4 files changed, 332 insertions(+), 15 deletions(-)
|
|
|
a6d77e |
|
|
|
a6d77e |
diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c
|
|
|
a6d77e |
index d2272c8124d0..ec83cf0c0f38 100644
|
|
|
a6d77e |
--- a/kexec/arch/arm64/crashdump-arm64.c
|
|
|
a6d77e |
+++ b/kexec/arch/arm64/crashdump-arm64.c
|
|
|
a6d77e |
@@ -1,11 +1,28 @@
|
|
|
a6d77e |
/*
|
|
|
a6d77e |
- * ARM64 crashdump.
|
|
|
a6d77e |
+ * crashdump for arm64
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Copyright (C) Nokia Corporation, 2010.
|
|
|
a6d77e |
+ * Author: Mika Westerberg
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Based on x86 implementation
|
|
|
a6d77e |
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Copyright (c) 2014 Linaro Limited
|
|
|
a6d77e |
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * This program is free software; you can redistribute it and/or modify
|
|
|
a6d77e |
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
a6d77e |
+ * published by the Free Software Foundation.
|
|
|
a6d77e |
*/
|
|
|
a6d77e |
|
|
|
a6d77e |
-#define _GNU_SOURCE
|
|
|
a6d77e |
+#define _GNU_SOURCE /* for asprintf */
|
|
|
a6d77e |
|
|
|
a6d77e |
+#include <assert.h>
|
|
|
a6d77e |
+#include <elf.h>
|
|
|
a6d77e |
#include <errno.h>
|
|
|
a6d77e |
-#include <linux/elf.h>
|
|
|
a6d77e |
+#include <stdio.h>
|
|
|
a6d77e |
+#include <stdlib.h>
|
|
|
a6d77e |
+#include <unistd.h>
|
|
|
a6d77e |
|
|
|
a6d77e |
#include "kexec.h"
|
|
|
a6d77e |
#include "crashdump.h"
|
|
|
a6d77e |
@@ -13,9 +30,279 @@
|
|
|
a6d77e |
#include "kexec-arm64.h"
|
|
|
a6d77e |
#include "kexec-elf.h"
|
|
|
a6d77e |
|
|
|
a6d77e |
-struct memory_ranges usablemem_rgns = {};
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/*
|
|
|
a6d77e |
+ * Used to save various memory ranges/regions needed for the captured
|
|
|
a6d77e |
+ * kernel to boot. (like memmap= option in other archs)
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+static struct memory_range crash_memory_ranges[CRASH_MAX_MEMORY_RANGES];
|
|
|
a6d77e |
+struct memory_ranges crashmem_rgns = {
|
|
|
a6d77e |
+ .size = 0,
|
|
|
a6d77e |
+ .ranges = crash_memory_ranges,
|
|
|
a6d77e |
+};
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/* memory range reserved for crashkernel */
|
|
|
a6d77e |
+struct memory_range crash_reserved_mem;
|
|
|
a6d77e |
+struct memory_ranges usablemem_rgns = {
|
|
|
a6d77e |
+ .size = 0,
|
|
|
a6d77e |
+ .ranges = &crash_reserved_mem,
|
|
|
a6d77e |
+};
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+static struct crash_elf_info elf_info = {
|
|
|
a6d77e |
+ .class = ELFCLASS64,
|
|
|
a6d77e |
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
|
|
a6d77e |
+ .data = ELFDATA2LSB,
|
|
|
a6d77e |
+#else
|
|
|
a6d77e |
+ .data = ELFDATA2MSB,
|
|
|
a6d77e |
+#endif
|
|
|
a6d77e |
+ .machine = EM_AARCH64,
|
|
|
a6d77e |
+};
|
|
|
a6d77e |
|
|
|
a6d77e |
int is_crashkernel_mem_reserved(void)
|
|
|
a6d77e |
{
|
|
|
a6d77e |
+ uint64_t start, end;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (parse_iomem_single("Crash kernel\n", &start, &end) == 0)
|
|
|
a6d77e |
+ return start != end;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ return 0;
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/*
|
|
|
a6d77e |
+ * crash_range_callback() - callback called for each iomem region
|
|
|
a6d77e |
+ * @data: not used
|
|
|
a6d77e |
+ * @nr: not used
|
|
|
a6d77e |
+ * @str: name of the memory region
|
|
|
a6d77e |
+ * @base: start address of the memory region
|
|
|
a6d77e |
+ * @length: size of the memory region
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * This function is called once for each memory region found in /proc/iomem.
|
|
|
a6d77e |
+ * It locates system RAM and crashkernel reserved memory and places these to
|
|
|
a6d77e |
+ * variables: @crash_memory_ranges and @crash_reserved_mem. Number of memory
|
|
|
a6d77e |
+ * regions is placed in @crash_memory_nr_ranges.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+static int crash_range_callback(void *UNUSED(data), int UNUSED(nr),
|
|
|
a6d77e |
+ char *str, unsigned long long base,
|
|
|
a6d77e |
+ unsigned long long length)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ struct memory_range *range;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ assert(arm64_mem.memstart);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (crashmem_rgns.size >= CRASH_MAX_MEMORY_RANGES)
|
|
|
a6d77e |
+ return 1;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ range = crashmem_rgns.ranges + crashmem_rgns.size;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (strncmp(str, "System RAM\n", 11) == 0) {
|
|
|
a6d77e |
+ range->start = base;
|
|
|
a6d77e |
+ range->end = base + length - 1;
|
|
|
a6d77e |
+ range->type = RANGE_RAM;
|
|
|
a6d77e |
+ crashmem_rgns.size++;
|
|
|
a6d77e |
+ } else if (strncmp(str, "Crash kernel\n", 13) == 0) {
|
|
|
a6d77e |
+ if (base < arm64_mem.memstart)
|
|
|
a6d77e |
+ base += arm64_mem.memstart;
|
|
|
a6d77e |
+ crash_reserved_mem.start = base;
|
|
|
a6d77e |
+ crash_reserved_mem.end = base + length - 1;
|
|
|
a6d77e |
+ crash_reserved_mem.type = RANGE_RAM;
|
|
|
a6d77e |
+ usablemem_rgns.size++;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ return 0;
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/*
|
|
|
a6d77e |
+ * crash_exclude_range() - excludes memory region reserved for crashkernel
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Function locates where crashkernel reserved memory is and removes that
|
|
|
a6d77e |
+ * region from the available memory regions.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+static void crash_exclude_range(void)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ const struct memory_range *range = &crash_reserved_mem;
|
|
|
a6d77e |
+ int i;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ for (i = 0; i < crashmem_rgns.size; i++) {
|
|
|
a6d77e |
+ struct memory_range *r = crashmem_rgns.ranges + i;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * We assume that crash area is fully contained in
|
|
|
a6d77e |
+ * some larger memory area.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ if (r->start <= range->start && r->end >= range->end) {
|
|
|
a6d77e |
+ struct memory_range *new;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (r->start == range->start) {
|
|
|
a6d77e |
+ if (r->end == range->end) {
|
|
|
a6d77e |
+ memcpy(r, r + 1,
|
|
|
a6d77e |
+ sizeof(r)
|
|
|
a6d77e |
+ * (crashmem_rgns.size - i - 1));
|
|
|
a6d77e |
+ crashmem_rgns.size--;
|
|
|
a6d77e |
+ } else {
|
|
|
a6d77e |
+ r->start = range->end + 1;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+ break;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+ if (r->end == range->end) {
|
|
|
a6d77e |
+ r->end = range->start - 1;
|
|
|
a6d77e |
+ break;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * Let's split this area into 2 smaller ones and
|
|
|
a6d77e |
+ * remove excluded range from between. First create
|
|
|
a6d77e |
+ * new entry for the remaining area.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ new = crashmem_rgns.ranges + crashmem_rgns.size;
|
|
|
a6d77e |
+ new->start = range->end + 1;
|
|
|
a6d77e |
+ new->end = r->end;
|
|
|
a6d77e |
+ crashmem_rgns.size++;
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * Next update this area to end before excluded range.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ r->end = range->start - 1;
|
|
|
a6d77e |
+ break;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/*
|
|
|
a6d77e |
+ * crash_get_memory_ranges() - read system physical memory
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Function reads through system physical memory and stores found memory
|
|
|
a6d77e |
+ * regions in @crash_memory_ranges. Number of memory regions found is placed
|
|
|
a6d77e |
+ * in @crash_memory_nr_ranges. Regions are sorted in ascending order.
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Returns %0 in case of success and %-1 otherwise (errno is set).
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+static int crash_get_memory_ranges(void)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * First read all memory regions that can be considered as
|
|
|
a6d77e |
+ * system memory including the crash area.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ kexec_iomem_for_each_line(NULL, crash_range_callback, NULL);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (usablemem_rgns.size != 1) {
|
|
|
a6d77e |
+ errno = EINVAL;
|
|
|
a6d77e |
+ return -1;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * Exclude memory reserved for crashkernel (this may result int
|
|
|
a6d77e |
+ * split memory regions).
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * FIXME:
|
|
|
a6d77e |
+ * Do we have to check crashkernel is within main memory?
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ crash_exclude_range();
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ return 0;
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/*
|
|
|
a6d77e |
+ * range_size - Return range size in MiB.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+static unsigned long range_size(const struct memory_range *r)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ return (r->end - r->start + 1) >> 20;
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+static void dump_crash_ranges(void)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ int i;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (!kexec_debug)
|
|
|
a6d77e |
+ return;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ dbgprintf("%s: kernel: %016llx - %016llx (%ld MiB)\n", __func__,
|
|
|
a6d77e |
+ crash_reserved_mem.start, crash_reserved_mem.end,
|
|
|
a6d77e |
+ range_size(&crash_reserved_mem));
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ for (i = 0; i < crashmem_rgns.size; i++) {
|
|
|
a6d77e |
+ struct memory_range *r = crashmem_rgns.ranges + i;
|
|
|
a6d77e |
+ dbgprintf("%s: RAM: %016llx - %016llx (%ld MiB)\n", __func__,
|
|
|
a6d77e |
+ r->start, r->end, range_size(r));
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+/*
|
|
|
a6d77e |
+ * load_crashdump_segments() - create elf core header for /proc/vmcore
|
|
|
a6d77e |
+ * @info: kexec info structure
|
|
|
a6d77e |
+ * @option: To be appended to kernel command line
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * This function loads additional segments which are needed for the dump
|
|
|
a6d77e |
+ * capture kernel. It also updates kernel command line passed in
|
|
|
a6d77e |
+ * @command_line_extra to have the correct parameters for the dump capture
|
|
|
a6d77e |
+ * kernel.
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Return %0 in case of success and %-1 in case of error.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+int load_crashdump_segments(struct kexec_info *info, char **option)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ unsigned long elfcorehdr;
|
|
|
a6d77e |
+ unsigned long bufsz;
|
|
|
a6d77e |
+ void *buf;
|
|
|
a6d77e |
+ int err;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * First fetch all the memory (RAM) ranges that we are going to
|
|
|
a6d77e |
+ * pass to the crashdump kernel during panic.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ err = crash_get_memory_ranges();
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (err)
|
|
|
a6d77e |
+ return err;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ dump_crash_ranges();
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ elf_info.page_offset = arm64_mem.page_offset;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ err = crash_create_elf64_headers(info, &elf_info, crashmem_rgns.ranges,
|
|
|
a6d77e |
+ crashmem_rgns.size, &buf, &bufsz, ELF_CORE_HEADER_ALIGN);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (err)
|
|
|
a6d77e |
+ return err;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ /*
|
|
|
a6d77e |
+ * FIXME: check if we need 128KB alignment here as stated in arm.
|
|
|
a6d77e |
+ */
|
|
|
a6d77e |
+ elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0,
|
|
|
a6d77e |
+ crash_reserved_mem.start, crash_reserved_mem.end,
|
|
|
a6d77e |
+ -1, 0);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ err = asprintf(option, " elfcorehdr=%#lx@%#lx", bufsz, elfcorehdr);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (err == -1)
|
|
|
a6d77e |
+ return err;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ dbgprintf("%s:%s\n", __func__, *option);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
return 0;
|
|
|
a6d77e |
}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ struct mem_phdr *phdr;
|
|
|
a6d77e |
+ int i;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ ehdr->e_entry += crash_reserved_mem.start;
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ for (i = 0; i < ehdr->e_phnum; i++) {
|
|
|
a6d77e |
+ phdr = &ehdr->e_phdr[i];
|
|
|
a6d77e |
+ if (phdr->p_type != PT_LOAD)
|
|
|
a6d77e |
+ continue;
|
|
|
a6d77e |
+ phdr->p_paddr +=
|
|
|
a6d77e |
+ (-arm64_mem.memstart + crash_reserved_mem.start);
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info)
|
|
|
a6d77e |
+{
|
|
|
a6d77e |
+ info->entry = (void *)crash_reserved_mem.start + arm64_mem.text_offset;
|
|
|
a6d77e |
+}
|
|
|
a6d77e |
diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h
|
|
|
a6d77e |
index f33c7a25b454..3f8b38350841 100644
|
|
|
a6d77e |
--- a/kexec/arch/arm64/crashdump-arm64.h
|
|
|
a6d77e |
+++ b/kexec/arch/arm64/crashdump-arm64.h
|
|
|
a6d77e |
@@ -1,12 +1,25 @@
|
|
|
a6d77e |
/*
|
|
|
a6d77e |
- * ARM64 crashdump.
|
|
|
a6d77e |
+ * crashdump for arm64
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * Copyright (c) 2014 Linaro Limited
|
|
|
a6d77e |
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
|
|
a6d77e |
+ *
|
|
|
a6d77e |
+ * This program is free software; you can redistribute it and/or modify
|
|
|
a6d77e |
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
a6d77e |
+ * published by the Free Software Foundation.
|
|
|
a6d77e |
*/
|
|
|
a6d77e |
|
|
|
a6d77e |
-#if !defined(CRASHDUMP_ARM64_H)
|
|
|
a6d77e |
+#ifndef CRASHDUMP_ARM64_H
|
|
|
a6d77e |
#define CRASHDUMP_ARM64_H
|
|
|
a6d77e |
|
|
|
a6d77e |
#include "kexec.h"
|
|
|
a6d77e |
|
|
|
a6d77e |
+#define CRASH_MAX_MEMORY_RANGES 32
|
|
|
a6d77e |
+
|
|
|
a6d77e |
extern struct memory_ranges usablemem_rgns;
|
|
|
a6d77e |
|
|
|
a6d77e |
+int load_crashdump_segments(struct kexec_info *info, char **option);
|
|
|
a6d77e |
+void modify_ehdr_for_crashmem(struct mem_ehdr *ehdr);
|
|
|
a6d77e |
+void set_crash_entry(struct mem_ehdr *ehdr, struct kexec_info *info);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
#endif
|
|
|
a6d77e |
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
|
|
|
a6d77e |
index eb68b6b3d9e3..e83e83bdd6db 100644
|
|
|
a6d77e |
--- a/kexec/arch/arm64/kexec-arm64.c
|
|
|
a6d77e |
+++ b/kexec/arch/arm64/kexec-arm64.c
|
|
|
a6d77e |
@@ -758,7 +758,7 @@ unsigned long phys_to_virt(struct crash_elf_info *UNUSED(elf_info),
|
|
|
a6d77e |
v = p - arm64_mem.memstart + arm64_mem.page_offset;
|
|
|
a6d77e |
|
|
|
a6d77e |
dbgprintf("%s: %016lx -> %016lx\n", __func__, p, v);
|
|
|
a6d77e |
- return p;
|
|
|
a6d77e |
+ return v;
|
|
|
a6d77e |
}
|
|
|
a6d77e |
|
|
|
a6d77e |
void add_segment(struct kexec_info *info, const void *buf, size_t bufsz,
|
|
|
a6d77e |
@@ -924,7 +924,7 @@ static int get_memory_ranges_iomem(struct memory_range *array,
|
|
|
a6d77e |
|
|
|
a6d77e |
r.type = RANGE_RAM;
|
|
|
a6d77e |
|
|
|
a6d77e |
- dbgprintf("%s:%d: RAM: %016llx - %016llx : %s", __func__,
|
|
|
a6d77e |
+ dbgprintf("%s:%d: RAM: %016llx - %016llx : %s", __func__,
|
|
|
a6d77e |
__LINE__, r.start, r.end, str);
|
|
|
a6d77e |
|
|
|
a6d77e |
array[(*count)++] = r;
|
|
|
a6d77e |
diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c
|
|
|
a6d77e |
index 8b336054a6ab..903602985eb4 100644
|
|
|
a6d77e |
--- a/kexec/arch/arm64/kexec-elf-arm64.c
|
|
|
a6d77e |
+++ b/kexec/arch/arm64/kexec-elf-arm64.c
|
|
|
a6d77e |
@@ -9,9 +9,10 @@
|
|
|
a6d77e |
#include <errno.h>
|
|
|
a6d77e |
#include <getopt.h>
|
|
|
a6d77e |
#include <libfdt.h>
|
|
|
a6d77e |
+#include <stdlib.h>
|
|
|
a6d77e |
|
|
|
a6d77e |
-#include "dt-ops.h"
|
|
|
a6d77e |
#include "crashdump-arm64.h"
|
|
|
a6d77e |
+#include "dt-ops.h"
|
|
|
a6d77e |
#include "kexec-arm64.h"
|
|
|
a6d77e |
#include "fs2dt.h"
|
|
|
a6d77e |
#include "kexec-syscall.h"
|
|
|
a6d77e |
@@ -45,16 +46,13 @@ on_exit:
|
|
|
a6d77e |
int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
|
|
|
a6d77e |
off_t kernel_size, struct kexec_info *info)
|
|
|
a6d77e |
{
|
|
|
a6d77e |
+ char *header_option = NULL;
|
|
|
a6d77e |
int result;
|
|
|
a6d77e |
struct mem_ehdr ehdr;
|
|
|
a6d77e |
bool found_header;
|
|
|
a6d77e |
int i;
|
|
|
a6d77e |
|
|
|
a6d77e |
- if (info->kexec_flags & KEXEC_ON_CRASH) {
|
|
|
a6d77e |
- fprintf(stderr, "kexec: kdump not yet supported on arm64\n");
|
|
|
a6d77e |
- return -EINVAL;
|
|
|
a6d77e |
- }
|
|
|
a6d77e |
-
|
|
|
a6d77e |
+ /* Parse the Elf file */
|
|
|
a6d77e |
result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0);
|
|
|
a6d77e |
|
|
|
a6d77e |
if (result < 0) {
|
|
|
a6d77e |
@@ -94,6 +92,18 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
|
|
|
a6d77e |
goto exit;
|
|
|
a6d77e |
}
|
|
|
a6d77e |
|
|
|
a6d77e |
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
|
|
|
a6d77e |
+ result = load_crashdump_segments(info, &header_option);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (result) {
|
|
|
a6d77e |
+ fprintf(stderr, "kexec: creating eflcorehdr failed.\n");
|
|
|
a6d77e |
+ goto exit;
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+ }
|
|
|
a6d77e |
+
|
|
|
a6d77e |
+ if (info->kexec_flags & KEXEC_ON_CRASH)
|
|
|
a6d77e |
+ modify_ehdr_for_crashmem(&ehdr);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
result = elf_exec_load(&ehdr, info);
|
|
|
a6d77e |
|
|
|
a6d77e |
if (result) {
|
|
|
a6d77e |
@@ -101,6 +111,11 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
|
|
|
a6d77e |
goto exit;
|
|
|
a6d77e |
}
|
|
|
a6d77e |
|
|
|
a6d77e |
+ if (info->kexec_flags & KEXEC_ON_CRASH)
|
|
|
a6d77e |
+ set_crash_entry(&ehdr, info);
|
|
|
a6d77e |
+ else
|
|
|
a6d77e |
+ info->entry = (void *)virt_to_phys(ehdr.e_entry);
|
|
|
a6d77e |
+
|
|
|
a6d77e |
dbgprintf("%s: text_offset: %016lx\n", __func__, arm64_mem.text_offset);
|
|
|
a6d77e |
dbgprintf("%s: image_size: %016lx\n", __func__, arm64_mem.image_size);
|
|
|
a6d77e |
dbgprintf("%s: page_offset: %016lx\n", __func__, arm64_mem.page_offset);
|
|
|
a6d77e |
@@ -108,9 +123,11 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
|
|
|
a6d77e |
dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__,
|
|
|
a6d77e |
ehdr.e_entry, virt_to_phys(ehdr.e_entry));
|
|
|
a6d77e |
|
|
|
a6d77e |
- result = arm64_load_other_segments(info, virt_to_phys(ehdr.e_entry));
|
|
|
a6d77e |
+ result = arm64_load_other_segments(info, (unsigned long)info->entry);
|
|
|
a6d77e |
exit:
|
|
|
a6d77e |
free_elf_info(&ehdr);
|
|
|
a6d77e |
+ if (header_option)
|
|
|
a6d77e |
+ free(header_option);
|
|
|
a6d77e |
return result;
|
|
|
a6d77e |
}
|
|
|
a6d77e |
|
|
|
a6d77e |
--
|
|
|
a6d77e |
2.1.0
|
|
|
a6d77e |
|