You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
7.6 KiB
282 lines
7.6 KiB
From 7c59b94be4abf8b28dd02bae8b79542377a86618 Mon Sep 17 00:00:00 2001 |
|
Message-Id: <7c59b94be4abf8b28dd02bae8b79542377a86618.1489676829.git.panand@redhat.com> |
|
In-Reply-To: <f85183096d31d865c97565614535d84943b12908.1489676829.git.panand@redhat.com> |
|
References: <f85183096d31d865c97565614535d84943b12908.1489676829.git.panand@redhat.com> |
|
From: AKASHI Takahiro <takahiro.akashi@linaro.org> |
|
Date: Wed, 15 Mar 2017 18:38:23 +0900 |
|
Subject: [PATCH 09/10] 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 <takahiro.akashi@linaro.org> |
|
--- |
|
kexec/arch/arm64/kexec-arm64.c | 197 ++++++++++++++++++++++++++++++++++++- |
|
kexec/arch/arm64/kexec-elf-arm64.c | 5 - |
|
2 files changed, 192 insertions(+), 10 deletions(-) |
|
|
|
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c |
|
index 5e30107b043f..f3f101d1be48 100644 |
|
--- a/kexec/arch/arm64/kexec-arm64.c |
|
+++ b/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 **argv) |
|
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; |
|
+} |
|
+ |
|
+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 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, char *command_line) |
|
|
|
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 = 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 = 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 kexec_info *info, |
|
} |
|
} |
|
|
|
- result = setup_2nd_dtb(&dtb, command_line); |
|
+ result = setup_2nd_dtb(&dtb, command_line, |
|
+ info->kexec_flags & KEXEC_ON_CRASH); |
|
|
|
if (result) |
|
return -EFAILED; |
|
diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c |
|
index 842ce21e2387..b17a31afa24e 100644 |
|
--- a/kexec/arch/arm64/kexec-elf-arm64.c |
|
+++ b/kexec/arch/arm64/kexec-elf-arm64.c |
|
@@ -47,11 +47,6 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, |
|
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) { |
|
-- |
|
2.9.3 |
|
|
|
|