* [PATCH 1/3] RISC-V: fix crashdump load memory ranges
2026-05-18 6:57 [PATCH v2 0/3] kexec-tool:bug fix for crashdump load on riscv hu.shengming
@ 2026-05-18 6:59 ` hu.shengming
2026-05-18 7:00 ` [PATCH 2/3] RISCV: Fix incorrect virtual address translation in crashdump load hu.shengming
2026-05-18 7:01 ` [PATCH 3/3] RISC-V: add bss section to kernel text elf header hu.shengming
2 siblings, 0 replies; 7+ messages in thread
From: hu.shengming @ 2026-05-18 6:59 UTC (permalink / raw)
To: hu.shengming; +Cc: horms, kexec, luo.haiyang, zhang.run, yang.tao172
From: Luo Haiyang <luo.haiyang@zte.com.cn>
The kdump service reported the following error:
kdump.sh[338]: readpage_elf: Attempt to read non-existent page at 0x17ee12000.
kdump.sh[338]: readmem: type_addr: 0, addr:ffffffd6fee12b00, size:8
kdump.sh[338]: validate_mem_section: Can't read mem_section array.
kdump.sh[338]: readpage_elf: Attempt to read non-existent page at 0x17ee12000.
kdump.sh[338]: readmem: type_addr: 0, addr:ffffffd6fee12b00, size:8
kdump.sh[338]: get_mm_sparsemem: Can't get the address of mem_section.
kdump.sh[338]: The kernel version is not supported.
kdump.sh[338]: The makedumpfile operation may be incomplete.
crash_mem_ranges only includes available memory, not all system RAM.
Inspired by the arm64 architecture, use system_mem_ranges in the
load_elfcorehdr function.
Fixes: b3fd54b (RISC-V: Add support for riscv kexec/kdump on kexec-tools)
Signed-off-by: Luo Haiyang <luo.haiyang@zte.com.cn>
---
kexec/arch/riscv/crashdump-riscv.c | 167 ++++++++++++++++++-----------
1 file changed, 102 insertions(+), 65 deletions(-)
diff --git a/kexec/arch/riscv/crashdump-riscv.c b/kexec/arch/riscv/crashdump-riscv.c
index 336d7a7..e923a71 100644
--- a/kexec/arch/riscv/crashdump-riscv.c
+++ b/kexec/arch/riscv/crashdump-riscv.c
@@ -6,6 +6,7 @@
#include "crashdump.h"
#include "kexec-elf.h"
#include "mem_regions.h"
+#include "iomem.h"
static struct crash_elf_info elf_info = {
#if __riscv_xlen == 64
@@ -18,6 +19,7 @@ static struct crash_elf_info elf_info = {
};
static struct memory_ranges crash_mem_ranges = {0};
+static struct memory_ranges system_mem_ranges = {0};
struct memory_range elfcorehdr_mem = {0};
static unsigned long long get_page_offset(struct kexec_info *info)
@@ -34,86 +36,114 @@ static unsigned long long get_page_offset(struct kexec_info *info)
return vaddr_off;
}
-int load_elfcorehdr(struct kexec_info *info)
+/*
+ * 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_rgns and crash_mem_ranges.
+ */
+static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr),
+ char *str, unsigned long long base,
+ unsigned long long length)
{
- struct memory_range crashkern_range = {0};
- struct memory_range *ranges = NULL;
- unsigned long start = 0;
- unsigned long end = 0;
- unsigned long buf_size = 0;
- unsigned long elfcorehdr_addr = 0;
- void* buf = NULL;
- int i = 0;
- int ret = 0;
+ if (strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)) == 0)
+ return mem_regions_alloc_and_add(&crash_mem_ranges,
+ base, length, RANGE_RAM);
+ else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0)
+ return mem_regions_alloc_and_add(&system_mem_ranges,
+ 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;
- ret = parse_iomem_single("Kernel code\n", &start, NULL);
- if (ret) {
- fprintf(stderr, "Cannot determine kernel physical base addr\n");
- return -EINVAL;
- }
- elf_info.kern_paddr_start = start;
+ return 0;
+}
+
+/*
+ * 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)
+{
+ int i;
+
+ if (!crash_mem_ranges.size)
+ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);
- ret = parse_iomem_single("Kernel bss\n", NULL, &end);
- if (ret) {
- fprintf(stderr, "Cannot determine kernel physical bss addr\n");
+ if (!crash_mem_ranges.size)
return -EINVAL;
+
+ dbgprint_mem_range("Reserved memory range",
+ crash_mem_ranges.ranges, crash_mem_ranges.size);
+
+ for (i = 0; i < crash_mem_ranges.size; i++) {
+ if (mem_regions_alloc_and_exclude(&system_mem_ranges,
+ &crash_mem_ranges.ranges[i])) {
+ fprintf(stderr, "Cannot allocate memory for ranges\n");
+ return -ENOMEM;
+ }
}
- elf_info.kern_paddr_start = start;
- elf_info.kern_size = end - start;
+ /*
+ * Make sure that the memory regions are sorted.
+ */
+ mem_regions_sort(&system_mem_ranges);
+
+ dbgprint_mem_range("Coredump memory ranges",
+ system_mem_ranges.ranges, system_mem_ranges.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) {
+ if (!elf_info.kern_vaddr_start)
elf_info.kern_vaddr_start = UINT64_MAX;
- }
- elf_info.page_offset = get_page_offset(info);
- dbgprintf("page_offset: %016llx\n", elf_info.page_offset);
+ return 0;
+}
- ret = parse_iomem_single("Crash kernel\n", &start, &end);
- if (ret) {
- fprintf(stderr, "Cannot determine kernel physical bss addr\n");
- return -EINVAL;
- }
- crashkern_range.start = start;
- crashkern_range.end = end;
- crashkern_range.type = RANGE_RESERVED;
-
- ranges = info->memory_range;
- for (i = 0; i < info->memory_ranges; i++) {
- ret = mem_regions_alloc_and_add(&crash_mem_ranges,
- ranges[i].start,
- ranges[i].end - ranges[i].start + 1,
- ranges[i].type);
- if (ret ) {
- fprintf(stderr, "Could not create crash_mem_ranges\n");
- return ret;
- }
- }
+int load_elfcorehdr(struct kexec_info *info)
+{
+ unsigned long buf_size = 0;
+ unsigned long elfcorehdr_addr = 0;
+ void* buf = NULL;
- ret = mem_regions_alloc_and_exclude(&crash_mem_ranges,
- &crashkern_range);
- if (ret) {
- fprintf(stderr, "Could not exclude crashkern_range\n");
- return ret;
- }
+ if (crash_get_memory_ranges())
+ return EFAILED;
+
+ elf_info.page_offset = get_page_offset(info);
+ dbgprintf("page_offset: %016llx\n", elf_info.page_offset);
#if __riscv_xlen == 64
- crash_create_elf64_headers(info, &elf_info, crash_mem_ranges.ranges,
- crash_mem_ranges.size, &buf, &buf_size,
+ crash_create_elf64_headers(info, &elf_info, system_mem_ranges.ranges,
+ system_mem_ranges.size, &buf, &buf_size,
ELF_CORE_HEADER_ALIGN);
#else
- crash_create_elf32_headers(info, &elf_info, crash_mem_ranges.ranges,
- crash_mem_ranges.size, &buf, &buf_size,
+ crash_create_elf32_headers(info, &elf_info, system_mem_ranges.ranges,
+ system_mem_ranges.size, &buf, &buf_size,
ELF_CORE_HEADER_ALIGN);
#endif
elfcorehdr_addr = add_buffer_phys_virt(info, buf, buf_size,
- buf_size, 0,
- crashkern_range.start,
- crashkern_range.end,
- -1, 0);
+ buf_size, 0,
+ crash_mem_ranges.ranges[crash_mem_ranges.size - 1].start,
+ crash_mem_ranges.ranges[crash_mem_ranges.size - 1].end,
+ -1, 0);
elfcorehdr_mem.start = elfcorehdr_addr;
elfcorehdr_mem.end = elfcorehdr_addr + buf_size - 1;
@@ -126,15 +156,22 @@ int load_elfcorehdr(struct kexec_info *info)
int is_crashkernel_mem_reserved(void)
{
- uint64_t start = 0;
- uint64_t end = 0;
+ if (!crash_mem_ranges.size)
+ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);
- return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
- (start != end) : 0;
+ return crash_mem_ranges.size;
}
int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
{
- return parse_iomem_single("Crash kernel\n", start, end);
-}
+ if (!crash_mem_ranges.size)
+ kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);
+
+ if (!crash_mem_ranges.size)
+ return -1;
+
+ *start = crash_mem_ranges.ranges[crash_mem_ranges.size - 1].start;
+ *end = crash_mem_ranges.ranges[crash_mem_ranges.size - 1].end;
+ return 0;
+}
--
2.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/3] RISCV: Fix incorrect virtual address translation in crashdump load
2026-05-18 6:57 [PATCH v2 0/3] kexec-tool:bug fix for crashdump load on riscv hu.shengming
2026-05-18 6:59 ` [PATCH 1/3] RISC-V: fix crashdump load memory ranges hu.shengming
@ 2026-05-18 7:00 ` hu.shengming
2026-05-18 7:01 ` [PATCH 3/3] RISC-V: add bss section to kernel text elf header hu.shengming
2 siblings, 0 replies; 7+ messages in thread
From: hu.shengming @ 2026-05-18 7:00 UTC (permalink / raw)
To: hu.shengming; +Cc: horms, kexec, luo.haiyang, zhang.run, yang.tao172
From: Luo Haiyang <luo.haiyang@zte.com.cn>
The kexec shows the following crashdump log:
Elf header: p_type = 1, p_offset = 0x80100000 p_paddr = 0x80100000 p_vaddr = 0xcff000 ...
Elf header: p_type = 1, p_offset = 0x100000000 p_paddr = 0x100000000 p_vaddr = 0x80bff000 ...
Elf header: p_type = 1, p_offset = 0x87ffff000 p_paddr = 0x87ffff000 p_vaddr = 0x800bfe000 ...
Obviously, phys_to_virt returns an incorrect virtual address (vaddr). On the RISC-V architecture,
the linear address mapping is defined as:
va = pa + kernel_map.va_pa_offset (kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base)
Both PAGE_OFFSET and phys_ram_base can be read from /proc/kcore.
Signed-off-by: Luo Haiyang <luo.haiyang@zte.com.cn>
---
kexec/arch/riscv/Makefile | 2 ++
kexec/arch/riscv/crashdump-riscv.c | 55 ++++++++++++++++++++++++------
util_lib/elf_info.c | 41 +++++++++++++++++-----
util_lib/include/elf_info.h | 1 +
4 files changed, 80 insertions(+), 19 deletions(-)
diff --git a/kexec/arch/riscv/Makefile b/kexec/arch/riscv/Makefile
index 18a997b..e886770 100644
--- a/kexec/arch/riscv/Makefile
+++ b/kexec/arch/riscv/Makefile
@@ -14,6 +14,8 @@ riscv_ARCH_REUSE_INITRD =
riscv_CPPFLAGS += -I $(srcdir)/kexec/
+riscv_PHYS_TO_VIRT =
+
dist += $(riscv_KEXEC_SRCS) \
kexec/arch/riscv/image-header.h \
kexec/arch/riscv/include/arch/options.h \
diff --git a/kexec/arch/riscv/crashdump-riscv.c b/kexec/arch/riscv/crashdump-riscv.c
index e923a71..6875249 100644
--- a/kexec/arch/riscv/crashdump-riscv.c
+++ b/kexec/arch/riscv/crashdump-riscv.c
@@ -1,5 +1,6 @@
#include <errno.h>
#include <elf.h>
+#include <elf_info.h>
#include <unistd.h>
#include "kexec.h"
@@ -22,18 +23,45 @@ static struct memory_ranges crash_mem_ranges = {0};
static struct memory_ranges system_mem_ranges = {0};
struct memory_range elfcorehdr_mem = {0};
-static unsigned long long get_page_offset(struct kexec_info *info)
+static unsigned long long phys_offset;
+
+static int get_page_offset(unsigned long long *page_offset)
{
- unsigned long long vaddr_off = 0;
- unsigned long long page_size = sysconf(_SC_PAGESIZE);
- unsigned long long init_start = get_kernel_sym("_sinittext");
+ int fd, ret = 0;
- /*
- * Begining of init section is aligned to page size
- */
- vaddr_off = init_start - page_size;
+ if ((fd = open("/proc/kcore", O_RDONLY)) < 0) {
+ fprintf(stderr, "Can't open (%s).\n", "/proc/kcore");
+ return EFAILED;
+ }
+
+ ret = read_page_offset_elf_kcore(fd, (long *)page_offset);
+ if (ret)
+ fprintf(stderr, "Can't get page_offset from /proc/kcore\n");
+
+ close(fd);
+ return ret;
+}
+
+static int get_phys_offset(unsigned long long *phys_offset)
+{
+ int fd, ret = 0;
+
+ if ((fd = open("/proc/kcore", O_RDONLY)) < 0) {
+ fprintf(stderr, "Can't open (%s).\n", "/proc/kcore");
+ return EFAILED;
+ }
+
+ ret = read_phys_offset_elf_kcore(fd, (long *)phys_offset);
+ if (ret)
+ fprintf(stderr, "Can't get phys_offset from /proc/kcore\n");
- return vaddr_off;
+ close(fd);
+ return ret;
+}
+
+unsigned long phys_to_virt(struct crash_elf_info *elf_info, unsigned long long p)
+{
+ return elf_info->page_offset - phys_offset + p;
}
/*
@@ -124,7 +152,14 @@ int load_elfcorehdr(struct kexec_info *info)
if (crash_get_memory_ranges())
return EFAILED;
- elf_info.page_offset = get_page_offset(info);
+ if (get_phys_offset(&phys_offset))
+ return EFAILED;
+
+ dbgprintf("phys_offset: %016llx\n", phys_offset);
+
+ if (get_page_offset(&elf_info.page_offset))
+ return EFAILED;
+
dbgprintf("page_offset: %016llx\n", elf_info.page_offset);
#if __riscv_xlen == 64
diff --git a/util_lib/elf_info.c b/util_lib/elf_info.c
index 589bc1a..36eb895 100644
--- a/util_lib/elf_info.c
+++ b/util_lib/elf_info.c
@@ -1308,16 +1308,39 @@ int read_phys_offset_elf_kcore(int fd, long *phys_off)
*phys_off = ULONG_MAX;
+ if (phys_offset != UINT64_MAX) {
+ *phys_off = phys_offset;
+ return 0;
+ }
+
+ /* If we have a valid 'PHYS_OFFSET' by now,
+ * return it to the caller now.
+ */
ret = read_elf(fd);
- if (!ret) {
- /* If we have a valid 'PHYS_OFFSET' by now,
- * return it to the caller now.
- */
- if (phys_offset != UINT64_MAX) {
- *phys_off = phys_offset;
- return ret;
- }
+ if (!ret && phys_offset != UINT64_MAX) {
+ *phys_off = phys_offset;
+ return 0;
+ }
+
+ return -EFAULT;
+}
+
+int read_page_offset_elf_kcore(int fd, long *page_off)
+{
+ int ret;
+
+ *page_off = ULONG_MAX;
+
+ if (page_offset != UINT64_MAX) {
+ *page_off = page_offset;
+ return 0;
+ }
+
+ ret = read_elf(fd);
+ if (!ret && page_offset != UINT64_MAX) {
+ *page_off = page_offset;
+ return 0;
}
- return 2;
+ return -EFAULT;
}
diff --git a/util_lib/include/elf_info.h b/util_lib/include/elf_info.h
index fdf4c3d..3ccc950 100644
--- a/util_lib/include/elf_info.h
+++ b/util_lib/include/elf_info.h
@@ -29,6 +29,7 @@ int get_pt_load(int idx,
unsigned long long *virt_start,
unsigned long long *virt_end);
int read_phys_offset_elf_kcore(int fd, long *phys_off);
+int read_page_offset_elf_kcore(int fd, long *page_off);
int read_elf(int fd);
void dump_dmesg(int fd, void (*handler)(char*, unsigned int));
extern void (*arch_scan_vmcoreinfo)(char *pos);
--
2.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread