From 510981a6b810c18d1bc3f5917ad743f3a6c85cf7 Mon Sep 17 00:00:00 2001 From: Ming Wang Date: Fri, 17 May 2024 10:39:31 +0800 Subject: [PATCH] kexec: loongarch: fix some issue. Signed-off-by: Hongchen Zhang Signed-off-by: Ming Wang --- kexec/arch/loongarch/crashdump-loongarch.c | 22 ++++++++++++ kexec/arch/loongarch/crashdump-loongarch.h | 1 + kexec/arch/loongarch/kexec-elf-loongarch.c | 40 +++++++++++++++++++--- kexec/arch/loongarch/kexec-loongarch.c | 22 ++++++++---- kexec/arch/loongarch/kexec-pei-loongarch.c | 7 ++++ kexec/kexec-syscall.h | 2 +- 6 files changed, 82 insertions(+), 12 deletions(-) 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..7e84d03 100644 --- a/kexec/arch/loongarch/kexec-elf-loongarch.c +++ b/kexec/arch/loongarch/kexec-elf-loongarch.c @@ -54,6 +54,7 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, unsigned long kernel_segment; struct mem_ehdr ehdr; int result; + int i; result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); @@ -62,6 +63,26 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, goto exit; } + /* Find and process the loongarch image header. */ + for (i = 0; i < ehdr.e_phnum; i++) { + struct mem_phdr *phdr = &ehdr.e_phdr[i]; + + if (phdr->p_type != PT_LOAD) + continue; + + header = (const struct loongarch_image_header *)( + kernel_buf + phdr->p_offset); + + if (!loongarch_process_image_header(header)) + break; + } + + if (i == ehdr.e_phnum) { + dbgprintf("%s: Valid loongarch image header not found\n", __func__); + result = EFAILED; + goto exit; + } + kernel_segment = loongarch_locate_kernel_segment(info); if (kernel_segment == ULONG_MAX) { @@ -72,13 +93,12 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); dbgprintf("%s: image_size: %016lx\n", __func__, - kernel_size); + loongarch_mem.image_size); dbgprintf("%s: text_offset: %016lx\n", __func__, loongarch_mem.text_offset); dbgprintf("%s: phys_offset: %016lx\n", __func__, loongarch_mem.phys_offset); - dbgprintf("%s: PE format: %s\n", __func__, - (loongarch_header_check_pe_sig(header) ? "yes" : "no")); + dbgprintf("%s: PE format: no\n", __func__); /* create and initialize elf core header segment */ if (info->kexec_flags & KEXEC_ON_CRASH) { @@ -90,6 +110,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); @@ -99,8 +127,12 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf, goto exit; } + /* for vmlinuz kernel image */ + if (kernel_size < MiB(16)) + kernel_size = MiB(64); + /* load additional data */ - result = loongarch_load_other_segments(info, kernel_segment + kernel_size); + result = loongarch_load_other_segments(info, kernel_segment + loongarch_mem.image_size); exit: free_elf_info(&ehdr); diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c index 4c7361c..6485080 100644 --- a/kexec/arch/loongarch/kexec-loongarch.c +++ b/kexec/arch/loongarch/kexec-loongarch.c @@ -221,6 +221,10 @@ int arch_process_options(int argc, char **argv) cmdline = get_command_line(); remove_parameter(cmdline, "kexec"); remove_parameter(cmdline, "initrd"); + remove_parameter(cmdline, "rd_start"); + remove_parameter(cmdline, "rd_size"); + remove_parameter(cmdline, "vfio_iommu_type1.allow_unsafe_interrupts"); + remove_parameter(cmdline, "nokaslr"); break; case OPT_INITRD: arch_options.initrd_file = optarg; @@ -253,8 +257,9 @@ 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); - hole = _ALIGN_UP(hole, MiB(1)); + mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start) + + loongarch_mem.text_offset; + hole = _ALIGN_UP(hole, MiB(16)); hole_end = hole + loongarch_mem.text_offset + loongarch_mem.image_size; if ((hole_end > mem_max) || @@ -265,7 +270,7 @@ unsigned long loongarch_locate_kernel_segment(struct kexec_info *info) } else { hole = locate_hole(info, loongarch_mem.text_offset + loongarch_mem.image_size, - MiB(1), 0, ULONG_MAX, 1); + MiB(16), 0, ULONG_MAX, 1); if (hole == ULONG_MAX) dbgprintf("%s: locate_hole failed\n", __func__); @@ -283,6 +288,7 @@ int loongarch_load_other_segments(struct kexec_info *info, unsigned long hole_mi unsigned long initrd_min, hole_max; char *initrd_buf = NULL; unsigned long pagesize = getpagesize(); + int i; if (arch_options.command_line) { if (strlen(arch_options.command_line) > @@ -320,15 +326,17 @@ int loongarch_load_other_segments(struct kexec_info *info, unsigned long hole_mi cmdline_add_elfcorehdr(cmdline, elfcorehdr_mem.start, elfcorehdr_mem.end - elfcorehdr_mem.start + 1); - cmdline_add_mem(cmdline, crash_reserved_mem[usablemem_rgns.size - 1].start, - crash_reserved_mem[usablemem_rgns.size - 1].end - - crash_reserved_mem[usablemem_rgns.size - 1].start + 1); + for(i = 0;i < usablemem_rgns.size; i++) { + cmdline_add_mem(cmdline, crash_reserved_mem[i].start, + crash_reserved_mem[i].end - + crash_reserved_mem[i].start + 1); + } } cmdline[sizeof(cmdline) - 1] = 0; add_buffer(info, cmdline, sizeof(cmdline), sizeof(cmdline), sizeof(void *), _ALIGN_UP(hole_min, getpagesize()), - 0xffffffff, 1); + hole_max, 1); dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__, cmdline); 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__, diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h index e392c01..f18b014 100644 --- a/kexec/kexec-syscall.h +++ b/kexec/kexec-syscall.h @@ -59,7 +59,7 @@ #endif #endif /*ifndef __NR_kexec_load*/ -#ifdef __arm__ +#if defined(__arm__) || defined(__loongarch__) #undef __NR_kexec_file_load #endif -- 2.43.0