Re: [PATCH v4 2/4] RISCV: Fix incorrect virtual address translation in crashdump load

luo.haiyang at zte.com.cn luo.haiyang at zte.com.cn
Wed May 27 01:18:16 PDT 2026


From: Luo Haiyang <luo.haiyang at 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 at 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



More information about the kexec mailing list