ARM kernel can be compiled with CONFIG_VMSPLIT_1G, CONFIG_VMSPLIT_2G or CONFIG_VMSPLIT_3G. This patch dynamically detects PAGE_OFFSET according to _stext symbol from /proc/kallsyms. Signed-off-by: Wang Nan <wangnan0 at huawei.com> --- kexec/arch/arm/crashdump-arm.c | 49 +++++++++++++++++++++++++++++++++++++++++- kexec/arch/arm/crashdump-arm.h | 4 +++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/kexec/arch/arm/crashdump-arm.c b/kexec/arch/arm/crashdump-arm.c index 0cd6935..e6ff3e0 100644 --- a/kexec/arch/arm/crashdump-arm.c +++ b/kexec/arch/arm/crashdump-arm.c @@ -56,11 +56,55 @@ static struct crash_elf_info elf_info = { .class = ELFCLASS32, .data = ELFDATANATIVE, .machine = EM_ARM, - .page_offset = PAGE_OFFSET, + .page_offset = DEFAULT_PAGE_OFFSET, }; unsigned long phys_offset; +/* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ +static unsigned long long get_kernel_stext_sym(void) +{ + const char *kallsyms = "/proc/kallsyms"; + const char *stext = "_stext"; + char sym[128]; + char line[128]; + FILE *fp; + unsigned long long vaddr; + char type; + + fp = fopen(kallsyms, "r"); if (!fp) { + fprintf(stderr, "Cannot open %s\n", kallsyms); + return 0; + } + + while(fgets(line, sizeof(line), fp) != NULL) { + if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) + continue; + if (strcmp(sym, stext) == 0) { + dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr); + return vaddr; + } + } + + fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); + return 0; +} + +static int get_kernel_page_offset(struct kexec_info *info, + struct crash_elf_info *elf_info) +{ + unsigned long long stext_sym_addr = get_kernel_stext_sym(); + if (stext_sym_addr == 0) { + elf_info->page_offset = (unsigned long long)DEFAULT_PAGE_OFFSET; + dbgprintf("Unable to get _stext symbol from /proc/kallsyms, use default: %llx\n", + elf_info->page_offset); + return 0; + } + elf_info->page_offset = stext_sym_addr & (~KVBASE_MASK); + dbgprintf("page_offset is set to %llx\n", elf_info->page_offset); + return 0; +} + /** * crash_range_callback() - callback called for each iomem region * @data: not used @@ -292,6 +336,9 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline) phys_offset = usablemem_rgns.ranges->start; dbgprintf("phys_offset: %#lx\n", phys_offset); + if (get_kernel_page_offset(info, &elf_info)) + return -1; + err = crash_create_elf32_headers(info, &elf_info, usablemem_rgns.ranges, usablemem_rgns.size, &buf, &bufsz, diff --git a/kexec/arch/arm/crashdump-arm.h b/kexec/arch/arm/crashdump-arm.h index a342922..2dbde04 100644 --- a/kexec/arch/arm/crashdump-arm.h +++ b/kexec/arch/arm/crashdump-arm.h @@ -6,9 +6,11 @@ extern "C" { #endif #define COMMAND_LINE_SIZE 1024 -#define PAGE_OFFSET 0xc0000000 +#define DEFAULT_PAGE_OFFSET (0xc0000000) +#define KVBASE_MASK (0x1ffffff) #define CRASH_MAX_MEMORY_RANGES 32 + extern struct memory_ranges usablemem_rgns; struct kexec_info; -- 1.8.4