From 1591926df5a602ffcbf55e99aa8a96fbebd0bafe Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 17 May 2017 14:51:47 +0900 Subject: arm64: kdump: set up kernel image segment On arm64, we can use the same kernel image as 1st kernel, but we have to modify the entry point as well as segments' addresses in the kernel's elf header in order to load them into correct places. Signed-off-by: AKASHI Takahiro Tested-by: David Woodhouse Tested-by: Pratyush Anand Signed-off-by: Simon Horman --- kexec/arch/arm64/crashdump-arm64.c | 24 ++++++++++++++++++++++++ kexec/arch/arm64/crashdump-arm64.h | 1 + kexec/arch/arm64/kexec-arm64.c | 25 ++++++++++++++++++++----- kexec/arch/arm64/kexec-elf-arm64.c | 11 ++++++++++- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c index d142435..4fd7aa8 100644 --- a/kexec/arch/arm64/crashdump-arm64.c +++ b/kexec/arch/arm64/crashdump-arm64.c @@ -211,6 +211,30 @@ int load_crashdump_segments(struct kexec_info *info) return 0; } +/* + * e_entry and p_paddr are actually in virtual address space. + * Those values will be translated to physcal addresses by using + * virt_to_phys() in add_segment(). + * So let's fix up those values for later use so the memory base + * (arm64_mm.phys_offset) will be correctly replaced with + * crash_reserved_mem.start. + */ +void fixup_elf_addrs(struct mem_ehdr *ehdr) +{ + struct mem_phdr *phdr; + int i; + + ehdr->e_entry += - arm64_mem.phys_offset + crash_reserved_mem.start; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &ehdr->e_phdr[i]; + if (phdr->p_type != PT_LOAD) + continue; + phdr->p_paddr += + (-arm64_mem.phys_offset + crash_reserved_mem.start); + } +} + int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) { if (!usablemem_rgns.size) diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h index 64c677d..880b83a 100644 --- a/kexec/arch/arm64/crashdump-arm64.h +++ b/kexec/arch/arm64/crashdump-arm64.h @@ -21,5 +21,6 @@ extern struct memory_range crash_reserved_mem; extern struct memory_range elfcorehdr_mem; extern int load_crashdump_segments(struct kexec_info *info); +extern void fixup_elf_addrs(struct mem_ehdr *ehdr); #endif /* CRASHDUMP_ARM64_H */ diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c index 153c96f..6c21756 100644 --- a/kexec/arch/arm64/kexec-arm64.c +++ b/kexec/arch/arm64/kexec-arm64.c @@ -308,12 +308,27 @@ unsigned long arm64_locate_kernel_segment(struct kexec_info *info) { unsigned long hole; - hole = locate_hole(info, - arm64_mem.text_offset + arm64_mem.image_size, - MiB(2), 0, ULONG_MAX, 1); + if (info->kexec_flags & KEXEC_ON_CRASH) { + unsigned long hole_end; + + hole = (crash_reserved_mem.start < mem_min ? + mem_min : crash_reserved_mem.start); + hole = _ALIGN_UP(hole, MiB(2)); + hole_end = hole + arm64_mem.text_offset + arm64_mem.image_size; + + if ((hole_end > mem_max) || + (hole_end > crash_reserved_mem.end)) { + dbgprintf("%s: Crash kernel out of range\n", __func__); + hole = ULONG_MAX; + } + } else { + hole = locate_hole(info, + arm64_mem.text_offset + arm64_mem.image_size, + MiB(2), 0, ULONG_MAX, 1); - if (hole == ULONG_MAX) - dbgprintf("%s: locate_hole failed\n", __func__); + if (hole == ULONG_MAX) + dbgprintf("%s: locate_hole failed\n", __func__); + } return hole; } diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c index 900c693..a961147 100644 --- a/kexec/arch/arm64/kexec-elf-arm64.c +++ b/kexec/arch/arm64/kexec-elf-arm64.c @@ -9,6 +9,7 @@ #include #include +#include "crashdump-arm64.h" #include "kexec-arm64.h" #include "kexec-elf.h" #include "kexec-syscall.h" @@ -105,7 +106,8 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, } arm64_mem.vp_offset = _ALIGN_DOWN(ehdr.e_entry, MiB(2)); - arm64_mem.vp_offset -= kernel_segment - get_phys_offset(); + if (!(info->kexec_flags & KEXEC_ON_CRASH)) + arm64_mem.vp_offset -= kernel_segment - get_phys_offset(); dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); dbgprintf("%s: text_offset: %016lx\n", __func__, @@ -130,6 +132,13 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, } /* load the kernel */ + if (info->kexec_flags & KEXEC_ON_CRASH) + /* + * offset addresses in elf header in order to load + * vmlinux (elf_exec) into crash kernel's memory + */ + fixup_elf_addrs(&ehdr); + result = elf_exec_load(&ehdr, info); if (result) { -- cgit