[PATCH 2/2] LoongArch: kdump: Set up kernel image segment

Youling Tang tangyouling at loongson.cn
Fri Feb 24 01:51:08 PST 2023


On LoongArch, we can use the same kernel image as 1st kernel when
[1] is merged, but we have to modify the entry point as well as
segments' addresses in the kernel's elf header (or pei format
vmlinux.efi) in order to load them into correct places.

[1]: https://lore.kernel.org/loongarch/1677150391-12838-1-git-send-email-tangyouling@loongson.cn/T/#t

Signed-off-by: Youling Tang <tangyouling at loongson.cn>
---
 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__,
-- 
2.37.1




More information about the kexec mailing list