277 lines
9.2 KiB
Diff
277 lines
9.2 KiB
Diff
From 6633170a04b1fc55eb72adc0150ffcd1b85be8ce Mon Sep 17 00:00:00 2001
|
|
From: Chen Zhou <chenzhou10@huawei.com>
|
|
Date: Fri, 29 Mar 2019 21:01:29 +0800
|
|
Subject: [PATCH] kexec-tools: support more than one crash kernel regions
|
|
|
|
reason: When crashkernel is reserved above 4G in memory, kernel should
|
|
reserve some amount of low memory for swiotlb and some DMA buffers.
|
|
So there may be two crash kernel regions, one is below 4G, the other
|
|
is above 4G.
|
|
|
|
Currently, there is only one crash kernel region on arm64, and pass
|
|
"linux,usable-memory-range = <BASE SIZE>" property to crash dump
|
|
kernel. Now, we pass
|
|
"linux,usable-memory-range = <BASE1 SIZE1 BASE2 SIZE2>" to crash
|
|
dump kernel to support two crash kernel regions and load crash
|
|
kernel high.
|
|
|
|
This patch paves the way for the use of arm64 reserving crashkernel
|
|
above 4G. The details are as below:
|
|
Link: https://lore.kernel.org/linux-arm-kernel/20190403030546.23718-1-chenzhou10@huawei.com/T/#t
|
|
|
|
Signed-off-by: Chen Zhou <chenzhou10@huawei.com>
|
|
---
|
|
kexec/arch/arm64/crashdump-arm64.c | 44 +++++++++++++++++------------
|
|
kexec/arch/arm64/crashdump-arm64.h | 3 +-
|
|
kexec/arch/arm64/kexec-arm64.c | 57 +++++++++++++++++++++++++++++---------
|
|
3 files changed, 72 insertions(+), 32 deletions(-)
|
|
|
|
diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c
|
|
index 4fd7aa8..158e778 100644
|
|
--- a/kexec/arch/arm64/crashdump-arm64.c
|
|
+++ b/kexec/arch/arm64/crashdump-arm64.c
|
|
@@ -27,11 +27,11 @@
|
|
static struct memory_ranges system_memory_rgns;
|
|
|
|
/* memory range reserved for crashkernel */
|
|
-struct memory_range crash_reserved_mem;
|
|
+struct memory_range crash_reserved_mem[CRASH_MAX_RESERVED_RANGES];
|
|
struct memory_ranges usablemem_rgns = {
|
|
.size = 0,
|
|
- .max_size = 1,
|
|
- .ranges = &crash_reserved_mem,
|
|
+ .max_size = CRASH_MAX_RESERVED_RANGES,
|
|
+ .ranges = crash_reserved_mem,
|
|
};
|
|
|
|
struct memory_range elfcorehdr_mem;
|
|
@@ -108,7 +108,7 @@ 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;
|
|
+ return usablemem_rgns.size;
|
|
}
|
|
|
|
/*
|
|
@@ -122,6 +122,8 @@ int is_crashkernel_mem_reserved(void)
|
|
*/
|
|
static int crash_get_memory_ranges(void)
|
|
{
|
|
+ int i;
|
|
+
|
|
/*
|
|
* First read all memory regions that can be considered as
|
|
* system memory including the crash area.
|
|
@@ -124,16 +126,19 @@ static int crash_get_memory_ranges(void)
|
|
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)
|
|
+ /* allow one or two region for crash dump kernel */
|
|
+ if (!usablemem_rgns.size)
|
|
return -EINVAL;
|
|
|
|
- dbgprint_mem_range("Reserved memory range", &crash_reserved_mem, 1);
|
|
+ dbgprint_mem_range("Reserved memory range",
|
|
+ usablemem_rgns.ranges, usablemem_rgns.size);
|
|
|
|
- if (mem_regions_alloc_and_exclude(&system_memory_rgns,
|
|
- &crash_reserved_mem)) {
|
|
- fprintf(stderr, "Cannot allocate memory for ranges\n");
|
|
- return -ENOMEM;
|
|
+ for (i = 0; i < usablemem_rgns.size; i++) {
|
|
+ if (mem_regions_exclude(&system_memory_rgns, &crash_reserved_mem[i])) {
|
|
+ fprintf(stderr,
|
|
+ "Error: Number of crash memory ranges excedeed the max limit\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -199,7 +204,8 @@ int load_crashdump_segments(struct kexec_info *info)
|
|
return EFAILED;
|
|
|
|
elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0,
|
|
- crash_reserved_mem.start, crash_reserved_mem.end,
|
|
+ crash_reserved_mem[usablemem_rgns.size - 1].start,
|
|
+ crash_reserved_mem[usablemem_rgns.size - 1].end,
|
|
-1, 0);
|
|
|
|
elfcorehdr_mem.start = elfcorehdr;
|
|
@@ -217,21 +223,23 @@ int load_crashdump_segments(struct kexec_info *info)
|
|
* 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.
|
|
+ * crash_reserved_mem[usablemem_rgns.size - 1].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;
|
|
+ ehdr->e_entry += -arm64_mem.phys_offset +
|
|
+ crash_reserved_mem[usablemem_rgns.size - 1].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);
|
|
+ (-arm64_mem.phys_offset +
|
|
+ crash_reserved_mem[usablemem_rgns.size - 1].start);
|
|
}
|
|
}
|
|
|
|
@@ -240,11 +248,11 @@ int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
|
|
if (!usablemem_rgns.size)
|
|
kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);
|
|
|
|
- if (!crash_reserved_mem.end)
|
|
+ if (!usablemem_rgns.size)
|
|
return -1;
|
|
|
|
- *start = crash_reserved_mem.start;
|
|
- *end = crash_reserved_mem.end;
|
|
+ *start = crash_reserved_mem[usablemem_rgns.size - 1].start;
|
|
+ *end = crash_reserved_mem[usablemem_rgns.size - 1].end;
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h
|
|
index 880b83a..c07233f 100644
|
|
--- a/kexec/arch/arm64/crashdump-arm64.h
|
|
+++ b/kexec/arch/arm64/crashdump-arm64.h
|
|
@@ -15,9 +15,10 @@
|
|
#include "kexec.h"
|
|
|
|
#define CRASH_MAX_MEMORY_RANGES 32
|
|
+#define CRASH_MAX_RESERVED_RANGES 8
|
|
|
|
extern struct memory_ranges usablemem_rgns;
|
|
-extern struct memory_range crash_reserved_mem;
|
|
+extern struct memory_range crash_reserved_mem[];
|
|
extern struct memory_range elfcorehdr_mem;
|
|
|
|
extern int load_crashdump_segments(struct kexec_info *info);
|
|
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
|
|
index 2992bce..2bf8b66 100644
|
|
--- a/kexec/arch/arm64/kexec-arm64.c
|
|
+++ b/kexec/arch/arm64/kexec-arm64.c
|
|
@@ -414,6 +414,34 @@ static int fdt_setprop_range(void *fdt, int nodeoffset,
|
|
return result;
|
|
}
|
|
|
|
+static int fdt_setprop_ranges(void *fdt, int nodeoffset,
|
|
+ const char *name, struct memory_ranges *ranges,
|
|
+ uint32_t address_cells, uint32_t size_cells)
|
|
+{
|
|
+ void *buf, *prop;
|
|
+ size_t buf_size;
|
|
+ int i, result;
|
|
+
|
|
+ buf_size = (address_cells + size_cells) * sizeof(uint32_t) *
|
|
+ ranges->size;
|
|
+ prop = buf = xmalloc(buf_size);
|
|
+
|
|
+ for (i = 0; i < ranges->size; i++) {
|
|
+ fill_property(prop, ranges->ranges[i].start, address_cells);
|
|
+ prop += address_cells * sizeof(uint32_t);
|
|
+
|
|
+ fill_property(prop, ranges->ranges[i].end -
|
|
+ ranges->ranges[i].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.
|
|
*/
|
|
@@ -428,7 +456,7 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
|
|
int len, range_len;
|
|
int nodeoffset;
|
|
int new_size;
|
|
- int result, kaslr_seed;
|
|
+ int i, result, kaslr_seed;
|
|
|
|
result = fdt_check_header(dtb->buf);
|
|
|
|
@@ -459,18 +487,21 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
|
|
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;
|
|
+ for (i = 0; i < usablemem_rgns.size; i++) {
|
|
+ if (!cells_size_fitted(address_cells, size_cells,
|
|
+ &crash_reserved_mem[i])) {
|
|
+ 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);
|
|
+ + fdt_prop_len(PROP_USABLE_MEM_RANGE, range_len * usablemem_rgns.size);
|
|
|
|
new_buf = xmalloc(new_size);
|
|
result = fdt_open_into(dtb->buf, new_buf, new_size);
|
|
@@ -565,8 +596,8 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
|
|
|
|
/* 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,
|
|
+ result = fdt_setprop_ranges(new_buf, nodeoffset,
|
|
+ PROP_USABLE_MEM_RANGE, &usablemem_rgns,
|
|
address_cells, size_cells);
|
|
if (result) {
|
|
dbgprintf("%s: fdt_setprop failed: %s\n", __func__,
|
|
@@ -599,13 +630,13 @@ unsigned long arm64_locate_kernel_segment(struct kexec_info *info)
|
|
if (info->kexec_flags & KEXEC_ON_CRASH) {
|
|
unsigned long hole_end;
|
|
|
|
- hole = (crash_reserved_mem.start < mem_min ?
|
|
- mem_min : crash_reserved_mem.start);
|
|
+ hole = (crash_reserved_mem[usablemem_rgns.size - 1].start < mem_min ?
|
|
+ mem_min : crash_reserved_mem[usablemem_rgns.size - 1].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)) {
|
|
+ (hole_end > crash_reserved_mem[usablemem_rgns.size - 1].end)) {
|
|
dbgprintf("%s: Crash kernel out of range\n", __func__);
|
|
hole = ULONG_MAX;
|
|
}
|
|
@@ -673,7 +704,7 @@ int arm64_load_other_segments(struct kexec_info *info,
|
|
|
|
hole_min = image_base + arm64_mem.image_size;
|
|
if (info->kexec_flags & KEXEC_ON_CRASH)
|
|
- hole_max = crash_reserved_mem.end;
|
|
+ hole_max = crash_reserved_mem[usablemem_rgns.size - 1].end;
|
|
else
|
|
hole_max = ULONG_MAX;
|
|
|
|
--
|
|
2.7.4
|
|
|