* [PATCH v4 1/4] RISC-V: fix crashdump load memory ranges
2026-05-21 4:06 [PATCH v4 0/4] kexec-tool:bug fix for crashdump load on riscv luo.haiyang
@ 2026-05-21 4:08 ` luo.haiyang
2026-05-21 4:09 ` [PATCH v4 2/4] RISCV: Fix incorrect virtual address translation in crashdump load luo.haiyang
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: luo.haiyang @ 2026-05-21 4:08 UTC (permalink / raw)
To: luo.haiyang; +Cc: kexec, horms, zhang.run, cai.qu
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] 8+ messages in thread* [PATCH v4 2/4] RISCV: Fix incorrect virtual address translation in crashdump load
2026-05-21 4:06 [PATCH v4 0/4] kexec-tool:bug fix for crashdump load on riscv luo.haiyang
2026-05-21 4:08 ` [PATCH v4 1/4] RISC-V: fix crashdump load memory ranges luo.haiyang
@ 2026-05-21 4:09 ` luo.haiyang
2026-05-27 7:27 ` [PATCH v4 2/4] RISCV: Fix incorrect virtual address translation in? " Simon Horman
2026-05-21 4:12 ` [PATCH v4 3/4] RISC-V: use kernel image to creat kernel text elf header luo.haiyang
2026-05-21 4:13 ` [PATCH v4 4/4] RISC-V: kernel image memory rang should not be excluded luo.haiyang
3 siblings, 1 reply; 8+ messages in thread
From: luo.haiyang @ 2026-05-21 4:09 UTC (permalink / raw)
To: luo.haiyang; +Cc: kexec, horms, zhang.run, cai.qu
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] 8+ messages in thread* [PATCH v4 3/4] RISC-V: use kernel image to creat kernel text elf header
2026-05-21 4:06 [PATCH v4 0/4] kexec-tool:bug fix for crashdump load on riscv luo.haiyang
2026-05-21 4:08 ` [PATCH v4 1/4] RISC-V: fix crashdump load memory ranges luo.haiyang
2026-05-21 4:09 ` [PATCH v4 2/4] RISCV: Fix incorrect virtual address translation in crashdump load luo.haiyang
@ 2026-05-21 4:12 ` luo.haiyang
2026-05-21 4:13 ` [PATCH v4 4/4] RISC-V: kernel image memory rang should not be excluded luo.haiyang
3 siblings, 0 replies; 8+ messages in thread
From: luo.haiyang @ 2026-05-21 4:12 UTC (permalink / raw)
To: luo.haiyang; +Cc: kexec, horms, zhang.run, cai.qu
From: Luo Haiyang <luo.haiyang@zte.com.cn>
The kdump service reported the following error:
No program header covering vaddr 0xffffffff819fa200 found kexec bug?
saving vmcore-dmesg.txt failed
prb stores the address of printk_rb_dynamic, which resides in the bss segment.
But the PHDR (Program Header) does not contains it. The correct approach is to
use the entire kernel memory range (includs text, rodata, data, bss) to create
the Kernel text Elf header. On RISC-V, we can use the "kernel image" directly,
which can be read from /proc/iomem.
Signed-off-by: Luo Haiyang <luo.haiyang@zte.com.cn>
---
kexec/arch/riscv/crashdump-riscv.c | 10 +++++-----
kexec/arch/riscv/iomem.h | 1 +
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/kexec/arch/riscv/crashdump-riscv.c b/kexec/arch/riscv/crashdump-riscv.c
index 6875249..deb9a49 100644
--- a/kexec/arch/riscv/crashdump-riscv.c
+++ b/kexec/arch/riscv/crashdump-riscv.c
@@ -80,16 +80,16 @@ static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr),
char *str, unsigned long long base,
unsigned long long length)
{
- if (strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)) == 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)
+ } 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)
+ } else if (strncmp(str, KERNEL_IMAGE, strlen(KERNEL_IMAGE)) == 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;
+ elf_info.kern_size = length;
+ }
return 0;
}
diff --git a/kexec/arch/riscv/iomem.h b/kexec/arch/riscv/iomem.h
index 7671e26..86da971 100644
--- a/kexec/arch/riscv/iomem.h
+++ b/kexec/arch/riscv/iomem.h
@@ -4,6 +4,7 @@
#define SYSTEM_RAM "System RAM\n"
#define KERNEL_CODE "Kernel code\n"
#define KERNEL_DATA "Kernel data\n"
+#define KERNEL_IMAGE "Kernel image\n"
#define CRASH_KERNEL "Crash kernel\n"
#define IOMEM_RESERVED "Reserved\n"
--
2.27.0
^ permalink raw reply related [flat|nested] 8+ messages in thread