diff options
-rw-r--r-- | kexec/arch/arm64/crashdump-arm64.c | 44 | ||||
-rw-r--r-- | kexec/arch/arm64/crashdump-arm64.h | 5 | ||||
-rw-r--r-- | kexec/arch/arm64/kexec-arm64.c | 84 |
3 files changed, 86 insertions, 47 deletions
diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c index a02019a3..d0f22538 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; @@ -119,7 +119,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; } /* @@ -133,6 +133,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. @@ -140,16 +142,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 regions 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_alloc_and_exclude(&system_memory_rgns, + &crash_reserved_mem[i])) { + fprintf(stderr, "Cannot allocate memory for ranges\n"); + return -ENOMEM; + } } /* @@ -210,7 +215,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; @@ -228,21 +234,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); } } @@ -251,11 +259,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 880b83aa..12f43087 100644 --- a/kexec/arch/arm64/crashdump-arm64.h +++ b/kexec/arch/arm64/crashdump-arm64.h @@ -16,8 +16,11 @@ #define CRASH_MAX_MEMORY_RANGES 32 +/* crash dump kernel support at most two regions, low_region and high region. */ +#define CRASH_MAX_RESERVED_RANGES 2 + 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 6f572ed5..44ca3dba 100644 --- a/kexec/arch/arm64/kexec-arm64.c +++ b/kexec/arch/arm64/kexec-arm64.c @@ -456,22 +456,32 @@ static void fill_property(void *buf, uint64_t val, uint32_t cells) } } -static int fdt_setprop_range(void *fdt, int nodeoffset, - const char *name, struct memory_range *range, +static int fdt_setprop_ranges(void *fdt, int nodeoffset, const char *name, + struct memory_range *ranges, int nr_ranges, bool reverse, uint32_t address_cells, uint32_t size_cells) { void *buf, *prop; size_t buf_size; - int result; + int i, result; + struct memory_range *range; - buf_size = (address_cells + size_cells) * sizeof(uint32_t); + buf_size = (address_cells + size_cells) * sizeof(uint32_t) * nr_ranges; prop = buf = xmalloc(buf_size); + if (!buf) + return -ENOMEM; - fill_property(prop, range->start, address_cells); - prop += address_cells * sizeof(uint32_t); + for (i = 0; i < nr_ranges; i++) { + if (reverse) + range = ranges + (nr_ranges - 1 - i); + else + range = ranges + i; - fill_property(prop, range->end - range->start + 1, size_cells); - prop += size_cells * sizeof(uint32_t); + 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); @@ -493,7 +503,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); @@ -524,18 +534,20 @@ 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); @@ -619,8 +631,8 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash) if (on_crash) { /* add linux,elfcorehdr */ nodeoffset = fdt_path_offset(new_buf, "/chosen"); - result = fdt_setprop_range(new_buf, nodeoffset, - PROP_ELFCOREHDR, &elfcorehdr_mem, + result = fdt_setprop_ranges(new_buf, nodeoffset, + PROP_ELFCOREHDR, &elfcorehdr_mem, 1, false, address_cells, size_cells); if (result) { dbgprintf("%s: fdt_setprop failed: %s\n", __func__, @@ -629,10 +641,17 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash) goto on_error; } - /* add linux,usable-memory-range */ + /* + * add linux,usable-memory-range + * + * crash dump kernel support one or two regions, to make + * compatibility with existing user-space and older kdump, the + * low region is always the last one. + */ 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.ranges, usablemem_rgns.size, true, address_cells, size_cells); if (result) { dbgprintf("%s: fdt_setprop failed: %s\n", __func__, @@ -665,13 +684,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; } @@ -745,7 +764,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; @@ -979,12 +998,21 @@ int get_phys_base_from_pt_load(unsigned long *phys_offset) return 0; } -static bool to_be_excluded(char *str) +static bool to_be_excluded(char *str, unsigned long long start, unsigned long long end) { + if (!strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL))) { + uint64_t load_start, load_end; + + if (!get_crash_kernel_load_range(&load_start, &load_end) && + (load_start == start) && (load_end == end)) + return false; + + return true; + } + if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) || !strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) || - !strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) || - !strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL))) + !strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA))) return false; else return true; @@ -1066,7 +1094,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges, memranges.size - 1, memranges.ranges[memranges.size - 1].start, memranges.ranges[memranges.size - 1].end); - } else if (to_be_excluded(str)) { + } else if (to_be_excluded(str, start, end)) { if (!memranges.size) continue; |