From a8de94e5f033afc1424dc37933c9d1ecb3dc1b9f Mon Sep 17 00:00:00 2001 From: Youling Tang Date: Sat, 4 Mar 2023 11:09:11 +0800 Subject: LoongArch: kdump: Set up kernel image segment On LoongArch, we can use the same kernel image as 1st kernel when 3f89765d622 ("LoongArch: kdump: Add single kernel image implementation") is merged, but we have to modify the entry point as well as segments addresses in the kernel elf header (or PE format vmlinux.efi) in order to load them into correct places. Signed-off-by: Youling Tang Signed-off-by: Simon Horman --- kexec/arch/loongarch/crashdump-loongarch.c | 22 ++++++++++++++++++++++ kexec/arch/loongarch/crashdump-loongarch.h | 1 + kexec/arch/loongarch/kexec-elf-loongarch.c | 8 ++++++++ kexec/arch/loongarch/kexec-loongarch.c | 3 ++- kexec/arch/loongarch/kexec-pei-loongarch.c | 7 +++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/kexec/arch/loongarch/crashdump-loongarch.c b/kexec/arch/loongarch/crashdump-loongarch.c index aaf6cf3..81250e4 100644 --- a/kexec/arch/loongarch/crashdump-loongarch.c +++ b/kexec/arch/loongarch/crashdump-loongarch.c @@ -183,6 +183,28 @@ 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 will be + * correctly replaced with crash_reserved_mem[usablemem_rgns.size - 1].start. + */ +void fixup_elf_addrs(struct mem_ehdr *ehdr) +{ + struct mem_phdr *phdr; + int i; + + ehdr->e_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &ehdr->e_phdr[i]; + if (phdr->p_type != PT_LOAD) + continue; + phdr->p_paddr += crash_reserved_mem[usablemem_rgns.size - 1].start; + } +} + int get_crash_kernel_load_range(uint64_t *start, uint64_t *end) { if (!usablemem_rgns.size) diff --git a/kexec/arch/loongarch/crashdump-loongarch.h b/kexec/arch/loongarch/crashdump-loongarch.h index 3eb4e0a..25ff24b 100644 --- a/kexec/arch/loongarch/crashdump-loongarch.h +++ b/kexec/arch/loongarch/crashdump-loongarch.h @@ -8,6 +8,7 @@ extern struct memory_range elfcorehdr_mem; int load_crashdump_segments(struct kexec_info *info); int is_crashkernel_mem_reserved(void); +void fixup_elf_addrs(struct mem_ehdr *ehdr); int get_crash_kernel_load_range(uint64_t *start, uint64_t *end); #define PAGE_OFFSET 0x9000000000000000ULL diff --git a/kexec/arch/loongarch/kexec-elf-loongarch.c b/kexec/arch/loongarch/kexec-elf-loongarch.c index 2bf128f..45387ca 100644 --- a/kexec/arch/loongarch/kexec-elf-loongarch.c +++ b/kexec/arch/loongarch/kexec-elf-loongarch.c @@ -90,6 +90,14 @@ int elf_loongarch_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); + info->entry = (void *)virt_to_phys(ehdr.e_entry); result = elf_exec_load(&ehdr, info); diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c index 4c7361c..f47c998 100644 --- a/kexec/arch/loongarch/kexec-loongarch.c +++ b/kexec/arch/loongarch/kexec-loongarch.c @@ -253,7 +253,8 @@ unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) unsigned long hole_end; hole = (crash_reserved_mem[usablemem_rgns.size - 1].start < mem_min ? - mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start); + mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start) + + loongarch_mem.text_offset; hole = _ALIGN_UP(hole, MiB(1)); hole_end = hole + loongarch_mem.text_offset + loongarch_mem.image_size; diff --git a/kexec/arch/loongarch/kexec-pei-loongarch.c b/kexec/arch/loongarch/kexec-pei-loongarch.c index f86ac61..1a11103 100644 --- a/kexec/arch/loongarch/kexec-pei-loongarch.c +++ b/kexec/arch/loongarch/kexec-pei-loongarch.c @@ -66,6 +66,13 @@ int pei_loongarch_load(int argc, char **argv, const char *buf, kernel_entry = virt_to_phys(loongarch_header_kernel_entry(header)); + if (info->kexec_flags & KEXEC_ON_CRASH) + /* + * offset addresses in order to load vmlinux.efi into + * crash kernel's memory. + */ + kernel_entry += crash_reserved_mem[usablemem_rgns.size - 1].start; + dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); dbgprintf("%s: kernel_entry: %016lx\n", __func__, kernel_entry); dbgprintf("%s: image_size: %016lx\n", __func__, -- cgit v1.2.1