From: Luo Haiyang <[email protected]> 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 <[email protected]> --- 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
