246 lines
8.6 KiB
Diff
246 lines
8.6 KiB
Diff
From 510981a6b810c18d1bc3f5917ad743f3a6c85cf7 Mon Sep 17 00:00:00 2001
|
|
From: Ming Wang <wangming01@loongson.cn>
|
|
Date: Fri, 17 May 2024 10:39:31 +0800
|
|
Subject: [PATCH] kexec: loongarch: fix some issue.
|
|
|
|
Signed-off-by: Hongchen Zhang <zhanghongchen@loongson.cn>
|
|
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
|
---
|
|
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
|
|
|