Skip to contentSkip to conversation

Add kexec_file support for LoongArch

PATCH Superseded Youling Tang 6 participants 30 messages Aug 11, 2025 – Aug 16, 2025

Subsystems (3)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

cover Add kexec_file support for LoongArch

From: Youling Tang <[email protected]>

This patchset implement kexec_file_load() support on LoongArch.

This patch series enables us to load the LoongArch vmlinuz.efi or vmlinux.efi by specifying its file decriptor, instead of user-filled buffer via kexec_load() syscall.

To use kexec_file_load() system call, instead of kexec_load(), at kexec command, '-s' options must be specified. kexec-tools needs to apply the corresponding patches. These patches can be found in repository [1] and will be submitted to the kexec-tools community later.

The basic usage of kexec_file is:
1) Load second kernel image:

 # kexec -s -l vmlinuz.efi --initrd=initrd.img --reuse-cmdline

2) Startup second kernel:

 # kexec -e

For kdump:
1) Load capture kernel image:

 # kexec -s -p vmlinuz.efi --initrd=initrd.img --reuse-cmdline

2) Do something to crash, like:

 # echo c > /proc/sysrq-trigger

Link:
[1] https://github.com/tangyouling/kexec-tools/commits/main/

Youling Tang (6):
LoongArch: Add struct loongarch_image_header for kernel image
LoongArch: Add kexec_file support
LoongArch/kexec_file: Add initrd loading LoongArch/kexec_file: Add crash dump support LoongArch/kexec_file: Add "mem" parameter to limit memory usage of
kdump kernel
LoongArch: Enable CONFIG_KEXEC_FILE

 arch/loongarch/Kconfig                     |   8 +
 arch/loongarch/configs/loongson3_defconfig |   1 +
 arch/loongarch/include/asm/image.h         |  58 +++++
 arch/loongarch/include/asm/kexec.h         |  12 ++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 ++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++-
 arch/loongarch/kernel/machine_kexec_file.c | 234 +++++++++++++++++++++
 8 files changed, 448 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/include/asm/image.h
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c
Signature · 1 line
2.34.1
#1 lore raw

PATCH 1/6 LoongArch: Add struct loongarch_image_header for kernel image

From: Youling Tang <[email protected]>

Define a dedicated image header structure for LoongArch architecture to standardize kernel loading in bootloaders (primarily for kexec_file).

This header includes critical metadata such as PE signature, entry points, image size and load address offset, etc.

---
 arch/loongarch/include/asm/image.h | 40 ++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 arch/loongarch/include/asm/image.h
arch/loongarch/include/asm/image.h new file +40 -0
new file mode 100644
index 000000000000..1f090736e71d
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * LoongArch binary image header.
+ *
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ *
+ * Most code is derived from LoongArch port of kexec-tools
+ */
+
+#ifndef __ASM_IMAGE_H
+#define __ASM_IMAGE_H
+#ifndef __ASSEMBLY__
+
+/**
+ * struct loongarch_image_header
+ *
+ * @pe_sig: Optional PE format 'MZ' signature.
+ * @reserved_1: Reserved.
+ * @kernel_entry: Kernel image entry pointer.
+ * @image_size: An estimated size of the memory image size in LSB byte order.
+ * @text_offset: The image load offset in LSB byte order.
+ * @reserved_2: Reserved.
+ * @reserved_3: Reserved.
+ * @pe_header: Optional offset to a PE format header.
+ **/
+
+struct loongarch_image_header {
+	uint8_t pe_sig[2];
+	uint16_t reserved_1[3];
+	uint64_t kernel_entry;
+	uint64_t image_size;
+	uint64_t text_offset;
+	uint64_t reserved_2[3];
+	uint32_t reserved_3;
+	uint32_t pe_header;
+};
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_IMAGE_H */
Signature · 1 line
2.34.1
#2 lore raw

PATCH 2/6 LoongArch: Add kexec_file support

In reply to Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
 arch/loongarch/Kconfig                     |   8 ++
 arch/loongarch/include/asm/image.h         |  18 ++++
 arch/loongarch/include/asm/kexec.h         |  12 +++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
 arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
 7 files changed, 219 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c
arch/loongarch/Kconfig +8 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH
 config ARCH_SUPPORTS_KEXEC
 	def_bool y
 
+config ARCH_SUPPORTS_KEXEC_FILE
+	def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+	def_bool y
+	depends on KEXEC_FILE
+	select HAVE_IMA_KEXEC if IMA
+
 config ARCH_SUPPORTS_CRASH_DUMP
 	def_bool y
 
arch/loongarch/include/asm/image.h +18 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
 	uint32_t pe_header;
 };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+	if (!h)
+		return 0;
+
+	return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+		&& h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_IMAGE_H */
arch/loongarch/include/asm/kexec.h +12 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
 	unsigned long systable_ptr;
 };
 
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+extern int load_other_segments(struct kimage *image,
+		unsigned long kernel_load_addr, unsigned long kernel_size,
+		char *initrd, unsigned long initrd_len,
+		char *cmdline, unsigned long cmdline_len);
+#endif
+
 typedef void (*do_kexec_t)(unsigned long efi_boot,
 			   unsigned long cmdline_ptr,
 			   unsigned long systable_ptr,
arch/loongarch/kernel/Makefile +1 -0
index 6f5a4574a911..bd9405ee3888 100644
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
 obj-$(CONFIG_RELOCATABLE)	+= relocate.o
 
 obj-$(CONFIG_KEXEC_CORE)	+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o kexec_image.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 
 obj-$(CONFIG_UNWINDER_GUESS)	+= unwind_guess.o
arch/loongarch/kernel/kexec_image.c new file +112 -0

112 lines not on this page · raw message

arch/loongarch/kernel/machine_kexec.c +22 -11
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
 	kimage->arch.efi_boot = fw_arg0;
 	kimage->arch.systable_ptr = fw_arg2;
 
-	/* Find the command line */
-	for (i = 0; i < kimage->nr_segments; i++) {
-		if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
-			if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
-				kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
-			break;
+	if (kimage->file_mode == 1) {
+		/*
+		 * kimage->cmdline_buf will be released in kexec_file_load, so copy to
+		 * the KEXEC_CMDLINE_ADDR safe area.
+		 */
+		memcpy((void *)KEXEC_CMDLINE_ADDR, (void *)kimage->arch.cmdline_ptr,
+					strlen((char *)kimage->arch.cmdline_ptr) + 1);
+		kimage->arch.cmdline_ptr = (unsigned long)KEXEC_CMDLINE_ADDR;
+	} else {
+		/* Find the command line */
+		for (i = 0; i < kimage->nr_segments; i++) {
+			if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
+				if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
+					kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
+				break;
+			}
 		}
-	}
 
-	if (!kimage->arch.cmdline_ptr) {
-		pr_err("Command line not included in the provided image\n");
-		return -EINVAL;
+		if (!kimage->arch.cmdline_ptr) {
+			pr_err("Command line not included in the provided image\n");
+			return -EINVAL;
+		}
 	}
 
 	/* kexec/kdump need a safe page to save reboot_code_buffer */
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
 	local_irq_disable();
 
 	pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-	pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+	pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+	pr_notice("Command line at %s\n", (char *)cmdline_ptr);
 	pr_notice("System table at 0x%lx\n", systable_ptr);
 	pr_notice("We will call new kernel at 0x%lx\n", start_addr);
 	pr_notice("Bye ...\n");
arch/loongarch/kernel/machine_kexec_file.c new file +46 -0

46 lines not on this page · raw message

Signature · 1 line
2.34.1
maintainer
#3 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Hi, Youling,

Quoted 80 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
 arch/loongarch/Kconfig                     |   8 ++
 arch/loongarch/include/asm/image.h         |  18 ++++
 arch/loongarch/include/asm/kexec.h         |  12 +++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
 arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
 7 files changed, 219 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c
arch/loongarch/Kconfig +8 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH
 config ARCH_SUPPORTS_KEXEC
        def_bool y
 
+config ARCH_SUPPORTS_KEXEC_FILE
+       def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+       depends on KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+
 config ARCH_SUPPORTS_CRASH_DUMP
        def_bool y
 
arch/loongarch/include/asm/image.h +18 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
        uint32_t pe_header;
 };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+       if (!h)
+               return 0;
+
+       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_IMAGE_H */
arch/loongarch/include/asm/kexec.h +0 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
        unsigned long systable_ptr;
 };
 

arch/loongarch/include/asm/kexec.h struct kimage_arch { · line 53

Quoted 10 lines
arch/loongarch/include/asm/kexec.h +10 -0
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+extern int load_other_segments(struct kimage *image,
+               unsigned long kernel_load_addr, unsigned long kernel_size,
+               char *initrd, unsigned long initrd_len,
+               char *cmdline, unsigned long cmdline_len);

I think the RISC-V naming "load_extra_segments" is better.

Quoted 10 lines
arch/loongarch/include/asm/kexec.h +2 -0
+#endif
+
 typedef void (*do_kexec_t)(unsigned long efi_boot,
                           unsigned long cmdline_ptr,
                           unsigned long systable_ptr,
arch/loongarch/kernel/Makefile +0 -0
index 6f5a4574a911..bd9405ee3888 100644

arch/loongarch/kernel/Makefile obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o · line 65

Quoted 4 lines
arch/loongarch/kernel/Makefile +1 -0
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)     += sysrq.o
 obj-$(CONFIG_RELOCATABLE)      += relocate.o
 
 obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o kexec_image.o

We only support the efi format, so we don't need to split a kexec_image.c like RISC-V, just put everything into machine_kexec_file.c is OK.

Huacai

Quoted 229 lines
arch/loongarch/kernel/Makefile +0 -0
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
 obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
arch/loongarch/kernel/kexec_image.c new file +112 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)    "kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+       const struct loongarch_image_header *h =
+               (const struct loongarch_image_header *)(kernel_buf);
+
+       if (!h || (kernel_len < sizeof(*h))) {
+               pr_err("No loongarch image header.\n");
+               return -EINVAL;
+       }
+
+       if (!loongarch_header_check_pe_sig(h)) {
+               pr_err("Bad loongarch PE image header.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void *image_load(struct kimage *image,
+                               char *kernel, unsigned long kernel_len,
+                               char *initrd, unsigned long initrd_len,
+                               char *cmdline, unsigned long cmdline_len)
+{
+       struct loongarch_image_header *h;
+       struct kexec_buf kbuf;
+       unsigned long text_offset, kernel_segment_number;
+       struct kexec_segment *kernel_segment;
+       int ret;
+
+       h = (struct loongarch_image_header *)kernel;
+       if (!h->image_size)
+               return ERR_PTR(-EINVAL);
+
+       /* Load the kernel */
+       kbuf.image = image;
+       kbuf.buf_min = 0;
+       kbuf.buf_max = ULONG_MAX;
+       kbuf.top_down = false;
+
+       kbuf.buffer = kernel;
+       kbuf.bufsz = kernel_len;
+       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+       kbuf.memsz = le64_to_cpu(h->image_size);
+       text_offset = le64_to_cpu(h->text_offset);
+       kbuf.buf_align = SZ_2M;
+
+       kernel_segment_number = image->nr_segments;
+
+       /*
+        * The location of the kernel segment may make it impossible to satisfy
+        * the other segment requirements, so we try repeatedly to find a
+        * location that will work.
+        */
+       while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+               /* Try to load additional data */
+               kernel_segment = &image->segment[kernel_segment_number];
+               ret = load_other_segments(image, kernel_segment->mem,
+                                         kernel_segment->memsz, initrd,
+                                         initrd_len, cmdline, cmdline_len);
+               if (!ret)
+                       break;
+
+               /*
+                * We couldn't find space for the other segments; erase the
+                * kernel segment and try the next available hole.
+                */
+               image->nr_segments -= 1;
+               kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+       }
+
+       if (ret) {
+               pr_err("Could not find any suitable kernel location!");
+               return ERR_PTR(ret);
+       }
+
+       kernel_segment = &image->segment[kernel_segment_number];
+
+       /* Make sure the second kernel jumps to the correct "kernel_entry". */
+       image->start = kernel_segment->mem + h->kernel_entry - text_offset;
+
+       kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                     kernel_segment->mem, kbuf.bufsz,
+                     kernel_segment->memsz);
+
+       return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+       .probe = image_probe,
+       .load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +22 -11
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
        kimage->arch.efi_boot = fw_arg0;
        kimage->arch.systable_ptr = fw_arg2;
 
-       /* Find the command line */
-       for (i = 0; i < kimage->nr_segments; i++) {
-               if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
-                       if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
-                               kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
-                       break;
+       if (kimage->file_mode == 1) {
+               /*
+                * kimage->cmdline_buf will be released in kexec_file_load, so copy to
+                * the KEXEC_CMDLINE_ADDR safe area.
+                */
+               memcpy((void *)KEXEC_CMDLINE_ADDR, (void *)kimage->arch.cmdline_ptr,
+                                       strlen((char *)kimage->arch.cmdline_ptr) + 1);
+               kimage->arch.cmdline_ptr = (unsigned long)KEXEC_CMDLINE_ADDR;
+       } else {
+               /* Find the command line */
+               for (i = 0; i < kimage->nr_segments; i++) {
+                       if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
+                               if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
+                                       kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
+                               break;
+                       }
                }
-       }
 
-       if (!kimage->arch.cmdline_ptr) {
-               pr_err("Command line not included in the provided image\n");
-               return -EINVAL;
+               if (!kimage->arch.cmdline_ptr) {
+                       pr_err("Command line not included in the provided image\n");
+                       return -EINVAL;
+               }
        }
 
        /* kexec/kdump need a safe page to save reboot_code_buffer */
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
        local_irq_disable();
 
        pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-       pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+       pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+       pr_notice("Command line at %s\n", (char *)cmdline_ptr);
        pr_notice("System table at 0x%lx\n", systable_ptr);
        pr_notice("We will call new kernel at 0x%lx\n", start_addr);
        pr_notice("Bye ...\n");
arch/loongarch/kernel/machine_kexec_file.c new file +46 -1
new file mode 100644
index 000000000000..bc91ae0afa4c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for LoongArch
+ *
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ *
+ * Most code is derived from LoongArch port of kexec-tools
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/bootinfo.h>
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+       &kexec_image_ops,
+       NULL
+};
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image)
+{
+       vfree(image->elf_headers);
+       image->elf_headers = NULL;
+       image->elf_headers_sz = 0;
+
+       return kexec_image_post_load_cleanup_default(image);
+}
+
+int load_other_segments(struct kimage *image,
+                       unsigned long kernel_load_addr,
+                       unsigned long kernel_size,
+                       char *initrd, unsigned long initrd_len,
+                       char *cmdline, unsigned long cmdline_len)
+{
+       image->arch.cmdline_ptr = (unsigned long)cmdline;
+
+       return 0;
+}
--

2.34.1

#4 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Hi, Huacai

Quoted 82 lines · Huacai Chen

Hi, Youling,

Quoted 79 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++
  arch/loongarch/include/asm/image.h         |  18 ++++
  arch/loongarch/include/asm/kexec.h         |  12 +++
  arch/loongarch/kernel/Makefile             |   1 +
  arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
  arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
  7 files changed, 219 insertions(+), 11 deletions(-)

create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

arch/loongarch/Kconfig +8 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH
  config ARCH_SUPPORTS_KEXEC
         def_bool y
 
+config ARCH_SUPPORTS_KEXEC_FILE
+       def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+       depends on KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+
  config ARCH_SUPPORTS_CRASH_DUMP
         def_bool y
 
arch/loongarch/include/asm/image.h +18 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
         uint32_t pe_header;
  };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+       if (!h)
+               return 0;
+
+       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+
  #endif /* __ASSEMBLY__ */
  #endif /* __ASM_IMAGE_H */
arch/loongarch/include/asm/kexec.h +0 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
         unsigned long systable_ptr;
  };
 
Quoted 11 lines

arch/loongarch/include/asm/kexec.h struct kimage_arch { · line 53

Quoted 10 lines
arch/loongarch/include/asm/kexec.h +10 -0
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+extern int load_other_segments(struct kimage *image,
+               unsigned long kernel_load_addr, unsigned long kernel_size,
+               char *initrd, unsigned long initrd_len,
+               char *cmdline, unsigned long cmdline_len);

I think the RISC-V naming "load_extra_segments" is better.

This name is also fine, but I prefer it to be consistent with that in kexec-tools.

Quoted 13 lines
Quoted 13 lines
arch/loongarch/include/asm/kexec.h +2 -0
+#endif
+
  typedef void (*do_kexec_t)(unsigned long efi_boot,
                            unsigned long cmdline_ptr,
                            unsigned long systable_ptr,
arch/loongarch/kernel/Makefile +0 -0
index 6f5a4574a911..bd9405ee3888 100644
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)     += sysrq.o
  obj-$(CONFIG_RELOCATABLE)      += relocate.o
 
Quoted 5 lines

arch/loongarch/kernel/Makefile obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o · line 65

Quoted 2 lines
arch/loongarch/kernel/Makefile +1 -0
  obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o kexec_image.o

We only support the efi format, so we don't need to split a kexec_image.c like RISC-V, just put everything into machine_kexec_file.c is OK.

I hope it is separated and consistent with other architectures. For instance, arm64 only supports one type.

Youling.

Quoted 232 lines

Huacai

Quoted 229 lines
arch/loongarch/kernel/Makefile +0 -0
  obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
  obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
arch/loongarch/kernel/kexec_image.c new file +112 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)    "kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+       const struct loongarch_image_header *h =
+               (const struct loongarch_image_header *)(kernel_buf);
+
+       if (!h || (kernel_len < sizeof(*h))) {
+               pr_err("No loongarch image header.\n");
+               return -EINVAL;
+       }
+
+       if (!loongarch_header_check_pe_sig(h)) {
+               pr_err("Bad loongarch PE image header.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void *image_load(struct kimage *image,
+                               char *kernel, unsigned long kernel_len,
+                               char *initrd, unsigned long initrd_len,
+                               char *cmdline, unsigned long cmdline_len)
+{
+       struct loongarch_image_header *h;
+       struct kexec_buf kbuf;
+       unsigned long text_offset, kernel_segment_number;
+       struct kexec_segment *kernel_segment;
+       int ret;
+
+       h = (struct loongarch_image_header *)kernel;
+       if (!h->image_size)
+               return ERR_PTR(-EINVAL);
+
+       /* Load the kernel */
+       kbuf.image = image;
+       kbuf.buf_min = 0;
+       kbuf.buf_max = ULONG_MAX;
+       kbuf.top_down = false;
+
+       kbuf.buffer = kernel;
+       kbuf.bufsz = kernel_len;
+       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+       kbuf.memsz = le64_to_cpu(h->image_size);
+       text_offset = le64_to_cpu(h->text_offset);
+       kbuf.buf_align = SZ_2M;
+
+       kernel_segment_number = image->nr_segments;
+
+       /*
+        * The location of the kernel segment may make it impossible to satisfy
+        * the other segment requirements, so we try repeatedly to find a
+        * location that will work.
+        */
+       while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+               /* Try to load additional data */
+               kernel_segment = &image->segment[kernel_segment_number];
+               ret = load_other_segments(image, kernel_segment->mem,
+                                         kernel_segment->memsz, initrd,
+                                         initrd_len, cmdline, cmdline_len);
+               if (!ret)
+                       break;
+
+               /*
+                * We couldn't find space for the other segments; erase the
+                * kernel segment and try the next available hole.
+                */
+               image->nr_segments -= 1;
+               kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+       }
+
+       if (ret) {
+               pr_err("Could not find any suitable kernel location!");
+               return ERR_PTR(ret);
+       }
+
+       kernel_segment = &image->segment[kernel_segment_number];
+
+       /* Make sure the second kernel jumps to the correct "kernel_entry". */
+       image->start = kernel_segment->mem + h->kernel_entry - text_offset;
+
+       kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                     kernel_segment->mem, kbuf.bufsz,
+                     kernel_segment->memsz);
+
+       return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+       .probe = image_probe,
+       .load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +22 -11
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
         kimage->arch.efi_boot = fw_arg0;
         kimage->arch.systable_ptr = fw_arg2;
 
-       /* Find the command line */
-       for (i = 0; i < kimage->nr_segments; i++) {
-               if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
-                       if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
-                               kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
-                       break;
+       if (kimage->file_mode == 1) {
+               /*
+                * kimage->cmdline_buf will be released in kexec_file_load, so copy to
+                * the KEXEC_CMDLINE_ADDR safe area.
+                */
+               memcpy((void *)KEXEC_CMDLINE_ADDR, (void *)kimage->arch.cmdline_ptr,
+                                       strlen((char *)kimage->arch.cmdline_ptr) + 1);
+               kimage->arch.cmdline_ptr = (unsigned long)KEXEC_CMDLINE_ADDR;
+       } else {
+               /* Find the command line */
+               for (i = 0; i < kimage->nr_segments; i++) {
+                       if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
+                               if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
+                                       kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
+                               break;
+                       }
                 }
-       }
 
-       if (!kimage->arch.cmdline_ptr) {
-               pr_err("Command line not included in the provided image\n");
-               return -EINVAL;
+               if (!kimage->arch.cmdline_ptr) {
+                       pr_err("Command line not included in the provided image\n");
+                       return -EINVAL;
+               }
         }
 
         /* kexec/kdump need a safe page to save reboot_code_buffer */
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
         local_irq_disable();
 
         pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-       pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+       pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+       pr_notice("Command line at %s\n", (char *)cmdline_ptr);
         pr_notice("System table at 0x%lx\n", systable_ptr);
         pr_notice("We will call new kernel at 0x%lx\n", start_addr);
         pr_notice("Bye ...\n");
arch/loongarch/kernel/machine_kexec_file.c new file +46 -1
new file mode 100644
index 000000000000..bc91ae0afa4c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for LoongArch
+ *
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ *
+ * Most code is derived from LoongArch port of kexec-tools
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/bootinfo.h>
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+       &kexec_image_ops,
+       NULL
+};
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image)
+{
+       vfree(image->elf_headers);
+       image->elf_headers = NULL;
+       image->elf_headers_sz = 0;
+
+       return kexec_image_post_load_cleanup_default(image);
+}
+
+int load_other_segments(struct kimage *image,
+                       unsigned long kernel_load_addr,
+                       unsigned long kernel_size,
+                       char *initrd, unsigned long initrd_len,
+                       char *cmdline, unsigned long cmdline_len)
+{
+       image->arch.cmdline_ptr = (unsigned long)cmdline;
+
+       return 0;
+}
--

2.34.1

#5 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 95 lines · Youling Tang

Hi, Huacai

Quoted 82 lines · Huacai Chen

Hi, Youling,

Quoted 79 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++ arch/loongarch/include/asm/image.h         |  18 ++++ arch/loongarch/include/asm/kexec.h         |  12 +++ arch/loongarch/kernel/Makefile             |   1 + arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++ arch/loongarch/kernel/machine_kexec.c      |  33 ++++-- arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++

  7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

arch/loongarch/Kconfig +0 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH

  config ARCH_SUPPORTS_KEXEC
         def_bool y

arch/loongarch/Kconfig +8 -0
+config ARCH_SUPPORTS_KEXEC_FILE
+       def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+       depends on KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+

  config ARCH_SUPPORTS_CRASH_DUMP
         def_bool y

arch/loongarch/include/asm/image.h +18 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
          uint32_t pe_header;
   };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+       if (!h)
+               return 0;
+
+       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+
   #endif /* __ASSEMBLY__ */
   #endif /* __ASM_IMAGE_H */
arch/loongarch/include/asm/kexec.h +0 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
          unsigned long systable_ptr;
   };
 
Quoted 11 lines

arch/loongarch/include/asm/kexec.h struct kimage_arch { · line 53

Quoted 10 lines
arch/loongarch/include/asm/kexec.h +10 -0
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+extern int load_other_segments(struct kimage *image,
+               unsigned long kernel_load_addr, unsigned long kernel_size,
+               char *initrd, unsigned long initrd_len,
+               char *cmdline, unsigned long cmdline_len);

I think the RISC-V naming "load_extra_segments" is better.

Quoted 2 lines

This name is also fine, but I prefer it to be consistent with that in kexec-tools.

I have looked at the code of kexec-tools, and it seems that you referenced a great deal of ARM code when implementing the LoongArch part.

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
arch/loongarch/include/asm/kexec.h +2 -0
+#endif
+
   typedef void (*do_kexec_t)(unsigned long efi_boot,
                             unsigned long cmdline_ptr,
                             unsigned long systable_ptr,
arch/loongarch/kernel/Makefile +0 -0
index 6f5a4574a911..bd9405ee3888 100644
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)     += sysrq.o

  obj-$(CONFIG_RELOCATABLE)      += relocate.o

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

  obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o kexec_image.o

We only support the efi format, so we don't need to split a kexec_image.c like RISC-V, just put everything into machine_kexec_file.c is OK.

I hope it is separated and consistent with other architectures. For instance, arm64 only supports one type.

The ARM64 architecture has a long history, and we shouldn't be constrained by it.

Thanks,
Yanteng

Quoted 4 lines

Youling.

Quoted 2 lines

Huacai

#6 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Hi, Yanteng

Quoted 120 lines · Yanteng Si
Quoted 101 lines · Youling Tang

Hi, Huacai

Quoted 86 lines · Huacai Chen

Hi, Youling,

Quoted 83 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++ arch/loongarch/include/asm/image.h         |  18 ++++ arch/loongarch/include/asm/kexec.h         |  12 +++ arch/loongarch/kernel/Makefile             |   1 + arch/loongarch/kernel/kexec_image.c        | 112
+++++++++++++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++++-- arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++

  7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

arch/loongarch/Kconfig +0 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH

  config ARCH_SUPPORTS_KEXEC
         def_bool y

arch/loongarch/Kconfig +8 -0
+config ARCH_SUPPORTS_KEXEC_FILE
+       def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+       depends on KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+

  config ARCH_SUPPORTS_CRASH_DUMP
         def_bool y

arch/loongarch/include/asm/image.h +5 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
          uint32_t pe_header;
   };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 
 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch 

image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */

arch/loongarch/include/asm/image.h +2 -0
+
+static inline int loongarch_header_check_pe_sig(const struct 

loongarch_image_header *h)

arch/loongarch/include/asm/image.h +8 -0
+{
+       if (!h)
+               return 0;
+
+       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+

  #endif /* __ASSEMBLY__ */
  #endif /* __ASM_IMAGE_H */

arch/loongarch/include/asm/kexec.h +0 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
          unsigned long systable_ptr;
   };
 
Quoted 13 lines
Quoted 9 lines
arch/loongarch/include/asm/kexec.h +5 -0
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup 

arch_kimage_file_post_load_cleanup

arch/loongarch/include/asm/kexec.h +3 -0
+
+extern int load_other_segments(struct kimage *image,
+               unsigned long kernel_load_addr, unsigned long 
Quoted 3 lines

kernel_size,
+               char *initrd, unsigned long initrd_len, +               char *cmdline, unsigned long cmdline_len);

I think the RISC-V naming "load_extra_segments" is better.

Quoted 2 lines

This name is also fine, but I prefer it to be consistent with that in kexec-tools.

I have looked at the code of kexec-tools, and it seems that you referenced a great deal of ARM code when implementing the LoongArch part.

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
arch/loongarch/include/asm/kexec.h +2 -0
+#endif
+

  typedef void (*do_kexec_t)(unsigned long efi_boot, unsigned long cmdline_ptr, unsigned long systable_ptr,

arch/loongarch/kernel/Makefile +0 -0
index 6f5a4574a911..bd9405ee3888 100644
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)     += sysrq.o

  obj-$(CONFIG_RELOCATABLE)      += relocate.o

Quoted 8 lines
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

  obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o kexec_image.o

We only support the efi format, so we don't need to split a kexec_image.c like RISC-V, just put everything into machine_kexec_file.c is OK.

I hope it is separated and consistent with other architectures. For instance, arm64 only supports one type.

The ARM64 architecture has a long history, and we shouldn't be constrained by it.

Support for kexec_elf.c in ELF format may be considered for addition in the future.

Thanks,
Youling.

Quoted 8 lines

Thanks,
Yanteng

Quoted 4 lines

Youling.

Quoted 2 lines

Huacai

#7 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 121 lines · Youling Tang

Hi, Yanteng

Quoted 119 lines · Yanteng Si
Quoted 95 lines · Youling Tang

Hi, Huacai

Quoted 82 lines · Huacai Chen

Hi, Youling,

Quoted 79 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++ arch/loongarch/include/asm/image.h         |  18 ++++ arch/loongarch/include/asm/kexec.h         |  12 +++ arch/loongarch/kernel/Makefile             |   1 + arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++ arch/loongarch/kernel/machine_kexec.c      |  33 ++++-- arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++

  7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

arch/loongarch/Kconfig +0 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH

  config ARCH_SUPPORTS_KEXEC
         def_bool y

arch/loongarch/Kconfig +8 -0
+config ARCH_SUPPORTS_KEXEC_FILE
+       def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+       depends on KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+

  config ARCH_SUPPORTS_CRASH_DUMP
         def_bool y

arch/loongarch/include/asm/image.h +18 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
          uint32_t pe_header;
   };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+       if (!h)
+               return 0;
+
+       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+
   #endif /* __ASSEMBLY__ */
   #endif /* __ASM_IMAGE_H */
arch/loongarch/include/asm/kexec.h +0 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
          unsigned long systable_ptr;
   };
 
Quoted 11 lines

arch/loongarch/include/asm/kexec.h struct kimage_arch { · line 53

Quoted 10 lines
arch/loongarch/include/asm/kexec.h +10 -0
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+extern int load_other_segments(struct kimage *image,
+               unsigned long kernel_load_addr, unsigned long kernel_size,
+               char *initrd, unsigned long initrd_len,
+               char *cmdline, unsigned long cmdline_len);

I think the RISC-V naming "load_extra_segments" is better.

Quoted 2 lines

This name is also fine, but I prefer it to be consistent with that in kexec-tools.

I have looked at the code of kexec-tools, and it seems that you referenced a great deal of ARM code when implementing the LoongArch part.

Quoted 18 lines
Quoted 18 lines
Quoted 13 lines
arch/loongarch/include/asm/kexec.h +2 -0
+#endif
+
   typedef void (*do_kexec_t)(unsigned long efi_boot,
                             unsigned long cmdline_ptr,
                             unsigned long systable_ptr,
arch/loongarch/kernel/Makefile +0 -0
index 6f5a4574a911..bd9405ee3888 100644
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)     += sysrq.o

  obj-$(CONFIG_RELOCATABLE)      += relocate.o

Quoted 2 lines

  obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o kexec_image.o

We only support the efi format, so we don't need to split a kexec_image.c like RISC-V, just put everything into machine_kexec_file.c is OK.

Quoted 5 lines
Quoted 3 lines
Quoted 2 lines

I hope it is separated and consistent with other architectures. For instance, arm64 only supports one type.

The ARM64 architecture has a long history, and we shouldn't be constrained by it.

Support for kexec_elf.c in ELF format may be considered for addition in the future.

Ok, I see.

Thanks,

Yanteng

Quoted 11 lines

Thanks,
Youling.

Quoted 8 lines

Thanks,
Yanteng

Quoted 4 lines

Youling.

Quoted 2 lines

Huacai

maintainer
#8 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

In reply to Youling Tang
Quoted 96 lines · Youling Tang

Hi, Huacai

Quoted 82 lines · Huacai Chen

Hi, Youling,

Quoted 79 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++
  arch/loongarch/include/asm/image.h         |  18 ++++
  arch/loongarch/include/asm/kexec.h         |  12 +++
  arch/loongarch/kernel/Makefile             |   1 +
  arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
  arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
  7 files changed, 219 insertions(+), 11 deletions(-)

create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

arch/loongarch/Kconfig +8 -0
index f0abc38c40ac..fd50c83f7827 100644
@@ -625,6 +625,14 @@ config CPU_HAS_PREFETCH
  config ARCH_SUPPORTS_KEXEC
         def_bool y
 
+config ARCH_SUPPORTS_KEXEC_FILE
+       def_bool 64BIT
+
+config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+       depends on KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+
  config ARCH_SUPPORTS_CRASH_DUMP
         def_bool y
 
arch/loongarch/include/asm/image.h +18 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
         uint32_t pe_header;
  };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+       if (!h)
+               return 0;
+
+       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
+}
+
  #endif /* __ASSEMBLY__ */
  #endif /* __ASM_IMAGE_H */
arch/loongarch/include/asm/kexec.h +0 -0
index cf95cd3eb2de..3ef8517a3670 100644
@@ -41,6 +41,18 @@ struct kimage_arch {
         unsigned long systable_ptr;
  };
 
Quoted 11 lines

arch/loongarch/include/asm/kexec.h struct kimage_arch { · line 53

Quoted 10 lines
arch/loongarch/include/asm/kexec.h +10 -0
+#ifdef CONFIG_KEXEC_FILE
+extern const struct kexec_file_ops kexec_image_ops;
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+extern int load_other_segments(struct kimage *image,
+               unsigned long kernel_load_addr, unsigned long kernel_size,
+               char *initrd, unsigned long initrd_len,
+               char *cmdline, unsigned long cmdline_len);

I think the RISC-V naming "load_extra_segments" is better.

Quoted 2 lines

This name is also fine, but I prefer it to be consistent with that in kexec-tools.

OK, then you can keep your original name.

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
arch/loongarch/include/asm/kexec.h +2 -0
+#endif
+
  typedef void (*do_kexec_t)(unsigned long efi_boot,
                            unsigned long cmdline_ptr,
                            unsigned long systable_ptr,
arch/loongarch/kernel/Makefile +0 -0
index 6f5a4574a911..bd9405ee3888 100644
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ)     += sysrq.o
  obj-$(CONFIG_RELOCATABLE)      += relocate.o
 
Quoted 7 lines
Quoted 5 lines

arch/loongarch/kernel/Makefile obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o · line 65

Quoted 2 lines
arch/loongarch/kernel/Makefile +1 -0
  obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o kexec_image.o

We only support the efi format, so we don't need to split a kexec_image.c like RISC-V, just put everything into machine_kexec_file.c is OK.

I hope it is separated and consistent with other architectures. For instance, arm64 only supports one type.

It seems only ARM64 and RISC-V are consistent, x86/powerpc/parisc are not.

Huacai

Quoted 234 lines

Youling.

Quoted 232 lines

Huacai

Quoted 229 lines
arch/loongarch/kernel/Makefile +0 -0
  obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
  obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
arch/loongarch/kernel/kexec_image.c new file +112 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)    "kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+       const struct loongarch_image_header *h =
+               (const struct loongarch_image_header *)(kernel_buf);
+
+       if (!h || (kernel_len < sizeof(*h))) {
+               pr_err("No loongarch image header.\n");
+               return -EINVAL;
+       }
+
+       if (!loongarch_header_check_pe_sig(h)) {
+               pr_err("Bad loongarch PE image header.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void *image_load(struct kimage *image,
+                               char *kernel, unsigned long kernel_len,
+                               char *initrd, unsigned long initrd_len,
+                               char *cmdline, unsigned long cmdline_len)
+{
+       struct loongarch_image_header *h;
+       struct kexec_buf kbuf;
+       unsigned long text_offset, kernel_segment_number;
+       struct kexec_segment *kernel_segment;
+       int ret;
+
+       h = (struct loongarch_image_header *)kernel;
+       if (!h->image_size)
+               return ERR_PTR(-EINVAL);
+
+       /* Load the kernel */
+       kbuf.image = image;
+       kbuf.buf_min = 0;
+       kbuf.buf_max = ULONG_MAX;
+       kbuf.top_down = false;
+
+       kbuf.buffer = kernel;
+       kbuf.bufsz = kernel_len;
+       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+       kbuf.memsz = le64_to_cpu(h->image_size);
+       text_offset = le64_to_cpu(h->text_offset);
+       kbuf.buf_align = SZ_2M;
+
+       kernel_segment_number = image->nr_segments;
+
+       /*
+        * The location of the kernel segment may make it impossible to satisfy
+        * the other segment requirements, so we try repeatedly to find a
+        * location that will work.
+        */
+       while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+               /* Try to load additional data */
+               kernel_segment = &image->segment[kernel_segment_number];
+               ret = load_other_segments(image, kernel_segment->mem,
+                                         kernel_segment->memsz, initrd,
+                                         initrd_len, cmdline, cmdline_len);
+               if (!ret)
+                       break;
+
+               /*
+                * We couldn't find space for the other segments; erase the
+                * kernel segment and try the next available hole.
+                */
+               image->nr_segments -= 1;
+               kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+       }
+
+       if (ret) {
+               pr_err("Could not find any suitable kernel location!");
+               return ERR_PTR(ret);
+       }
+
+       kernel_segment = &image->segment[kernel_segment_number];
+
+       /* Make sure the second kernel jumps to the correct "kernel_entry". */
+       image->start = kernel_segment->mem + h->kernel_entry - text_offset;
+
+       kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                     kernel_segment->mem, kbuf.bufsz,
+                     kernel_segment->memsz);
+
+       return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+       .probe = image_probe,
+       .load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +22 -11
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
         kimage->arch.efi_boot = fw_arg0;
         kimage->arch.systable_ptr = fw_arg2;
 
-       /* Find the command line */
-       for (i = 0; i < kimage->nr_segments; i++) {
-               if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
-                       if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
-                               kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
-                       break;
+       if (kimage->file_mode == 1) {
+               /*
+                * kimage->cmdline_buf will be released in kexec_file_load, so copy to
+                * the KEXEC_CMDLINE_ADDR safe area.
+                */
+               memcpy((void *)KEXEC_CMDLINE_ADDR, (void *)kimage->arch.cmdline_ptr,
+                                       strlen((char *)kimage->arch.cmdline_ptr) + 1);
+               kimage->arch.cmdline_ptr = (unsigned long)KEXEC_CMDLINE_ADDR;
+       } else {
+               /* Find the command line */
+               for (i = 0; i < kimage->nr_segments; i++) {
+                       if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
+                               if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
+                                       kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
+                               break;
+                       }
                 }
-       }
 
-       if (!kimage->arch.cmdline_ptr) {
-               pr_err("Command line not included in the provided image\n");
-               return -EINVAL;
+               if (!kimage->arch.cmdline_ptr) {
+                       pr_err("Command line not included in the provided image\n");
+                       return -EINVAL;
+               }
         }
 
         /* kexec/kdump need a safe page to save reboot_code_buffer */
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
         local_irq_disable();
 
         pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-       pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+       pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+       pr_notice("Command line at %s\n", (char *)cmdline_ptr);
         pr_notice("System table at 0x%lx\n", systable_ptr);
         pr_notice("We will call new kernel at 0x%lx\n", start_addr);
         pr_notice("Bye ...\n");
arch/loongarch/kernel/machine_kexec_file.c new file +46 -1
new file mode 100644
index 000000000000..bc91ae0afa4c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for LoongArch
+ *
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ *
+ * Most code is derived from LoongArch port of kexec-tools
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/bootinfo.h>
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+       &kexec_image_ops,
+       NULL
+};
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image)
+{
+       vfree(image->elf_headers);
+       image->elf_headers = NULL;
+       image->elf_headers_sz = 0;
+
+       return kexec_image_post_load_cleanup_default(image);
+}
+
+int load_other_segments(struct kimage *image,
+                       unsigned long kernel_load_addr,
+                       unsigned long kernel_size,
+                       char *initrd, unsigned long initrd_len,
+                       char *cmdline, unsigned long cmdline_len)
+{
+       image->arch.cmdline_ptr = (unsigned long)cmdline;
+
+       return 0;
+}
--

2.34.1

#9 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

In reply to Youling Tang
Quoted 23 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
 arch/loongarch/Kconfig                     |   8 ++
 arch/loongarch/include/asm/image.h         |  18 ++++
 arch/loongarch/include/asm/kexec.h         |  12 +++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
 arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
 7 files changed, 219 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 40

Quoted 10 lines
arch/loongarch/include/asm/image.h +2 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
 	uint32_t pe_header;
 };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};

loongarch_pe_machtype isn't used at all.

Quoted 4 lines
arch/loongarch/include/asm/image.h +4 -0
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 54

Quoted 10 lines
arch/loongarch/include/asm/image.h +10 -0
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+	if (!h)
+		return 0;
+
+	return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+		&& h->pe_sig[1] == loongarch_image_pe_sig[1]);

This could be simplified with a memcmp(). Also, this check isn't strict
enough: PE files for any architectures, and even legacy MS-DOS COM executables all start with "MZ".

Quoted 4 lines
arch/loongarch/include/asm/image.h +2 -0
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_IMAGE_H */

...

Quoted 20 lines
arch/loongarch/kernel/kexec_image.c new file +14 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)	"kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>

arch/loongarch/kernel/kexec_image.c line 24

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	const struct loongarch_image_header *h =
+		(const struct loongarch_image_header *)(kernel_buf);

Parentheses around "kernel_buf" are unnecessary.

arch/loongarch/kernel/kexec_image.c line 26

Quoted 1 line
arch/loongarch/kernel/kexec_image.c new file +1 -0
+	if (!h || (kernel_len < sizeof(*h))) {

Comparisons have higher priority than logic operations, so this pair of parentheses is redundant, too.

Quoted 29 lines
arch/loongarch/kernel/kexec_image.c new file +29 -0
+		pr_err("No loongarch image header.\n");
+		return -EINVAL;
+	}
+
+	if (!loongarch_header_check_pe_sig(h)) {
+		pr_err("Bad loongarch PE image header.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *image_load(struct kimage *image,
+				char *kernel, unsigned long kernel_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	struct loongarch_image_header *h;
+	struct kexec_buf kbuf;
+	unsigned long text_offset, kernel_segment_number;
+	struct kexec_segment *kernel_segment;
+	int ret;
+
+	h = (struct loongarch_image_header *)kernel;
+	if (!h->image_size)
+		return ERR_PTR(-EINVAL);
+
+	/* Load the kernel */
+	kbuf.image = image;

arch/loongarch/kernel/kexec_image.c line 65

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+	kbuf.buf_min = 0;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.top_down = false;
+
+	kbuf.buffer = kernel;
+	kbuf.bufsz = kernel_len;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = le64_to_cpu(h->image_size);
+	text_offset = le64_to_cpu(h->text_offset);
+	kbuf.buf_align = SZ_2M;

I think this aligment is unnecessary for relocatable LoongArch kernels:
it should be enough to align to the page size. See also my comments below.

Quoted 24 lines
arch/loongarch/kernel/kexec_image.c new file +24 -0
+	kernel_segment_number = image->nr_segments;
+
+	/*
+	 * The location of the kernel segment may make it impossible to satisfy
+	 * the other segment requirements, so we try repeatedly to find a
+	 * location that will work.
+	 */
+	while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+		/* Try to load additional data */
+		kernel_segment = &image->segment[kernel_segment_number];
+		ret = load_other_segments(image, kernel_segment->mem,
+					  kernel_segment->memsz, initrd,
+					  initrd_len, cmdline, cmdline_len);
+		if (!ret)
+			break;
+
+		/*
+		 * We couldn't find space for the other segments; erase the
+		 * kernel segment and try the next available hole.
+		 */
+		image->nr_segments -= 1;
+		kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	}

arch/loongarch/kernel/kexec_image.c line 100

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+
+	if (ret) {
+		pr_err("Could not find any suitable kernel location!");
+		return ERR_PTR(ret);
+	}
+
+	kernel_segment = &image->segment[kernel_segment_number];
+
+	/* Make sure the second kernel jumps to the correct "kernel_entry". */
+	image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

Quoted 16 lines
arch/loongarch/kernel/kexec_image.c new file +11 -0
+	kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		      kernel_segment->mem, kbuf.bufsz,
+		      kernel_segment->memsz);
+
+	return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+	.probe = image_probe,
+	.load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +0 -0
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)

...

Quoted 11 lines
arch/loongarch/kernel/machine_kexec.c +4 -3
-	if (!kimage->arch.cmdline_ptr) {
-		pr_err("Command line not included in the provided image\n");
-		return -EINVAL;
+		if (!kimage->arch.cmdline_ptr) {
+			pr_err("Command line not included in the provided image\n");
+			return -EINVAL;
+		}
 	}
 
 	/* kexec/kdump need a safe page to save reboot_code_buffer */

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 302

Quoted 6 lines
arch/loongarch/kernel/machine_kexec.c +2 -1
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
 	local_irq_disable();
 
 	pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-	pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+	pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+	pr_notice("Command line at %s\n", (char *)cmdline_ptr);

The printed message doesn't match meaning of the pointer: you're printing the content of cmdline_ptr, instead of its address, thus "Command line at" sounds confusing to me.

Furthermore, this chunk isn't related to "support for kexec_file", I think it's better to separate it into another patch (or even another series).

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 305

Quoted 3 lines
arch/loongarch/kernel/machine_kexec.c +0 -0
 	pr_notice("System table at 0x%lx\n", systable_ptr);
 	pr_notice("We will call new kernel at 0x%lx\n", start_addr);
 	pr_notice("Bye ...\n");

Best regards,
Yao Zi

maintainer
#10 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 100 lines · Yao Zi
Quoted 23 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
 arch/loongarch/Kconfig                     |   8 ++
 arch/loongarch/include/asm/image.h         |  18 ++++
 arch/loongarch/include/asm/kexec.h         |  12 +++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
 arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
 7 files changed, 219 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 40

Quoted 10 lines
arch/loongarch/include/asm/image.h +2 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
      uint32_t pe_header;
 };
 
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};

loongarch_pe_machtype isn't used at all.

Quoted 4 lines
arch/loongarch/include/asm/image.h +4 -0
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 54

Quoted 10 lines
arch/loongarch/include/asm/image.h +10 -0
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+     if (!h)
+             return 0;
+
+     return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+             && h->pe_sig[1] == loongarch_image_pe_sig[1]);

This could be simplified with a memcmp(). Also, this check isn't strict
enough: PE files for any architectures, and even legacy MS-DOS COM executables all start with "MZ".

Quoted 4 lines
arch/loongarch/include/asm/image.h +2 -0
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_IMAGE_H */

...

Quoted 20 lines
arch/loongarch/kernel/kexec_image.c new file +14 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)  "kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>

arch/loongarch/kernel/kexec_image.c line 24

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+     const struct loongarch_image_header *h =
+             (const struct loongarch_image_header *)(kernel_buf);

Parentheses around "kernel_buf" are unnecessary.

Quoted 4 lines

arch/loongarch/kernel/kexec_image.c line 26

Quoted 1 line
arch/loongarch/kernel/kexec_image.c new file +1 -0
+     if (!h || (kernel_len < sizeof(*h))) {

Comparisons have higher priority than logic operations, so this pair of parentheses is redundant, too.

But the kernel coding style suggest to use parentheses in this case.

Quoted 130 lines
Quoted 30 lines
arch/loongarch/kernel/kexec_image.c new file +29 -0
+             pr_err("No loongarch image header.\n");
+             return -EINVAL;
+     }
+
+     if (!loongarch_header_check_pe_sig(h)) {
+             pr_err("Bad loongarch PE image header.\n");
+             return -EINVAL;
+     }
+
+     return 0;
+}
+
+static void *image_load(struct kimage *image,
+                             char *kernel, unsigned long kernel_len,
+                             char *initrd, unsigned long initrd_len,
+                             char *cmdline, unsigned long cmdline_len)
+{
+     struct loongarch_image_header *h;
+     struct kexec_buf kbuf;
+     unsigned long text_offset, kernel_segment_number;
+     struct kexec_segment *kernel_segment;
+     int ret;
+
+     h = (struct loongarch_image_header *)kernel;
+     if (!h->image_size)
+             return ERR_PTR(-EINVAL);
+
+     /* Load the kernel */
+     kbuf.image = image;

arch/loongarch/kernel/kexec_image.c line 65

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+     kbuf.buf_min = 0;
+     kbuf.buf_max = ULONG_MAX;
+     kbuf.top_down = false;
+
+     kbuf.buffer = kernel;
+     kbuf.bufsz = kernel_len;
+     kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+     kbuf.memsz = le64_to_cpu(h->image_size);
+     text_offset = le64_to_cpu(h->text_offset);
+     kbuf.buf_align = SZ_2M;

I think this aligment is unnecessary for relocatable LoongArch kernels:
it should be enough to align to the page size. See also my comments below.

Quoted 24 lines
arch/loongarch/kernel/kexec_image.c new file +24 -0
+     kernel_segment_number = image->nr_segments;
+
+     /*
+      * The location of the kernel segment may make it impossible to satisfy
+      * the other segment requirements, so we try repeatedly to find a
+      * location that will work.
+      */
+     while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+             /* Try to load additional data */
+             kernel_segment = &image->segment[kernel_segment_number];
+             ret = load_other_segments(image, kernel_segment->mem,
+                                       kernel_segment->memsz, initrd,
+                                       initrd_len, cmdline, cmdline_len);
+             if (!ret)
+                     break;
+
+             /*
+              * We couldn't find space for the other segments; erase the
+              * kernel segment and try the next available hole.
+              */
+             image->nr_segments -= 1;
+             kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+             kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+     }

arch/loongarch/kernel/kexec_image.c line 100

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+
+     if (ret) {
+             pr_err("Could not find any suitable kernel location!");
+             return ERR_PTR(ret);
+     }
+
+     kernel_segment = &image->segment[kernel_segment_number];
+
+     /* Make sure the second kernel jumps to the correct "kernel_entry". */
+     image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

Quoted 16 lines
arch/loongarch/kernel/kexec_image.c new file +11 -0
+     kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                   kernel_segment->mem, kbuf.bufsz,
+                   kernel_segment->memsz);
+
+     return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+     .probe = image_probe,
+     .load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +0 -0
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)

...

Quoted 11 lines
arch/loongarch/kernel/machine_kexec.c +4 -3
-     if (!kimage->arch.cmdline_ptr) {
-             pr_err("Command line not included in the provided image\n");
-             return -EINVAL;
+             if (!kimage->arch.cmdline_ptr) {
+                     pr_err("Command line not included in the provided image\n");
+                     return -EINVAL;
+             }
      }
 
      /* kexec/kdump need a safe page to save reboot_code_buffer */

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 302

Quoted 6 lines
arch/loongarch/kernel/machine_kexec.c +2 -1
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
      local_irq_disable();
 
      pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-     pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+     pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+     pr_notice("Command line at %s\n", (char *)cmdline_ptr);

The printed message doesn't match meaning of the pointer: you're printing the content of cmdline_ptr, instead of its address, thus "Command line at" sounds confusing to me.

Quoted 3 lines

Furthermore, this chunk isn't related to "support for kexec_file", I think it's better to separate it into another patch (or even another series).

Separating is not necessary from my point of view, indeed I suggest to squash patches in this series.

Huacai

Quoted 7 lines

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 305

Quoted 4 lines
arch/loongarch/kernel/machine_kexec.c +0 -0
      pr_notice("System table at 0x%lx\n", systable_ptr);
      pr_notice("We will call new kernel at 0x%lx\n", start_addr);
      pr_notice("Bye ...\n");

Best regards,
Yao Zi

#11 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 60 lines · Huacai Chen
Quoted 59 lines · Yao Zi
Quoted 44 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
 arch/loongarch/Kconfig                     |   8 ++
 arch/loongarch/include/asm/image.h         |  18 ++++
 arch/loongarch/include/asm/kexec.h         |  12 +++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
 arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
 7 files changed, 219 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c
arch/loongarch/kernel/kexec_image.c new file +14 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)  "kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>

arch/loongarch/kernel/kexec_image.c line 24

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+     const struct loongarch_image_header *h =
+             (const struct loongarch_image_header *)(kernel_buf);

Parentheses around "kernel_buf" are unnecessary.

Quoted 5 lines
Quoted 4 lines

arch/loongarch/kernel/kexec_image.c line 26

Quoted 1 line
arch/loongarch/kernel/kexec_image.c new file +1 -0
+     if (!h || (kernel_len < sizeof(*h))) {

Comparisons have higher priority than logic operations, so this pair of parentheses is redundant, too.

But the kernel coding style suggest to use parentheses in this case.

Could you please quote the original text? I have read through Documentation/process/coding-style.rst again but didn't find similar suggestions...

And git grep '[[:alnum:]]\+ || [[:alnum:]_]\+ [<>]=\?' results in more than 7000 matches, including 25 in arch/loongarch...

Anyway, this is a little nitpick. I'm just pointing out the expression is equal to "!h || kernel_len < sizeof(*h)", and whether it's simplified is fine to me.

Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
arch/loongarch/kernel/kexec_image.c new file +11 -0
+             pr_err("No loongarch image header.\n");
+             return -EINVAL;
+     }
+
+     if (!loongarch_header_check_pe_sig(h)) {
+             pr_err("Bad loongarch PE image header.\n");
+             return -EINVAL;
+     }
+
+     return 0;
+}

...

Quoted 30 lines
Quoted 30 lines
Quoted 5 lines
arch/loongarch/kernel/machine_kexec.c +0 -0
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)

...

Quoted 11 lines
arch/loongarch/kernel/machine_kexec.c +4 -3
-     if (!kimage->arch.cmdline_ptr) {
-             pr_err("Command line not included in the provided image\n");
-             return -EINVAL;
+             if (!kimage->arch.cmdline_ptr) {
+                     pr_err("Command line not included in the provided image\n");
+                     return -EINVAL;
+             }
      }
 
      /* kexec/kdump need a safe page to save reboot_code_buffer */

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 302

Quoted 6 lines
arch/loongarch/kernel/machine_kexec.c +2 -1
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
      local_irq_disable();
 
      pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-     pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+     pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+     pr_notice("Command line at %s\n", (char *)cmdline_ptr);

The printed message doesn't match meaning of the pointer: you're printing the content of cmdline_ptr, instead of its address, thus "Command line at" sounds confusing to me.

Quoted 5 lines
Quoted 3 lines

Furthermore, this chunk isn't related to "support for kexec_file", I think it's better to separate it into another patch (or even another series).

Separating is not necessary from my point of view, indeed I suggest to squash patches in this series.

I realized this comment is a little nitpicking, too, so I'm going to say either is fine to me.

Quoted 1 line

Huacai

Best regards,
Yao Zi

Quoted 8 lines
Quoted 7 lines

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 305

Quoted 4 lines
arch/loongarch/kernel/machine_kexec.c +0 -0
      pr_notice("System table at 0x%lx\n", systable_ptr);
      pr_notice("We will call new kernel at 0x%lx\n", start_addr);
      pr_notice("Bye ...\n");

Best regards,
Yao Zi

#12 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

In reply to Yao Zi

Hi, Yao

Quoted 34 lines · Yao Zi
Quoted 23 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++
  arch/loongarch/include/asm/image.h         |  18 ++++
  arch/loongarch/include/asm/kexec.h         |  12 +++
  arch/loongarch/kernel/Makefile             |   1 +
  arch/loongarch/kernel/kexec_image.c        | 112 +++++++++++++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
  arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
  7 files changed, 219 insertions(+), 11 deletions(-)

create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

Quoted 8 lines
arch/loongarch/include/asm/image.h +0 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
  	uint32_t pe_header;
  };
 
Quoted 3 lines

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 40

Quoted 2 lines
arch/loongarch/include/asm/image.h +2 -0
+static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};

loongarch_pe_machtype isn't used at all.

It will be removed.

Quoted 48 lines
Quoted 5 lines
arch/loongarch/include/asm/image.h +4 -0
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
+ *

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 54

Quoted 10 lines
arch/loongarch/include/asm/image.h +10 -0
+ * Returns non-zero if 'MZ' signature is found.
+ */
+
+static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
+{
+	if (!h)
+		return 0;
+
+	return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+		&& h->pe_sig[1] == loongarch_image_pe_sig[1]);

This could be simplified with a memcmp(). Also, this check isn't strict
enough: PE files for any architectures, and even legacy MS-DOS COM executables all start with "MZ".

Quoted 4 lines
arch/loongarch/include/asm/image.h +2 -0
+}
+
  #endif /* __ASSEMBLY__ */
  #endif /* __ASM_IMAGE_H */

...

Quoted 23 lines
arch/loongarch/kernel/kexec_image.c new file +17 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)	"kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
Quoted 8 lines

arch/loongarch/kernel/kexec_image.c line 24

Quoted 7 lines
arch/loongarch/kernel/kexec_image.c new file +7 -0
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	const struct loongarch_image_header *h =
+		(const struct loongarch_image_header *)(kernel_buf);

Parentheses around "kernel_buf" are unnecessary.

It will be removed.

Quoted 4 lines

arch/loongarch/kernel/kexec_image.c line 26

Quoted 2 lines
arch/loongarch/kernel/kexec_image.c new file +1 -0
+	if (!h || (kernel_len < sizeof(*h))) {

Comparisons have higher priority than logic operations, so this pair of parentheses is redundant, too.

Yes, but the parentheses will be retained for greater readability.

Quoted 82 lines
Quoted 30 lines
arch/loongarch/kernel/kexec_image.c new file +29 -0
+		pr_err("No loongarch image header.\n");
+		return -EINVAL;
+	}
+
+	if (!loongarch_header_check_pe_sig(h)) {
+		pr_err("Bad loongarch PE image header.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *image_load(struct kimage *image,
+				char *kernel, unsigned long kernel_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	struct loongarch_image_header *h;
+	struct kexec_buf kbuf;
+	unsigned long text_offset, kernel_segment_number;
+	struct kexec_segment *kernel_segment;
+	int ret;
+
+	h = (struct loongarch_image_header *)kernel;
+	if (!h->image_size)
+		return ERR_PTR(-EINVAL);
+
+	/* Load the kernel */
+	kbuf.image = image;

arch/loongarch/kernel/kexec_image.c line 65

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+	kbuf.buf_min = 0;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.top_down = false;
+
+	kbuf.buffer = kernel;
+	kbuf.bufsz = kernel_len;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = le64_to_cpu(h->image_size);
+	text_offset = le64_to_cpu(h->text_offset);
+	kbuf.buf_align = SZ_2M;

I think this aligment is unnecessary for relocatable LoongArch kernels:
it should be enough to align to the page size. See also my comments below.

Quoted 24 lines
arch/loongarch/kernel/kexec_image.c new file +24 -0
+	kernel_segment_number = image->nr_segments;
+
+	/*
+	 * The location of the kernel segment may make it impossible to satisfy
+	 * the other segment requirements, so we try repeatedly to find a
+	 * location that will work.
+	 */
+	while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+		/* Try to load additional data */
+		kernel_segment = &image->segment[kernel_segment_number];
+		ret = load_other_segments(image, kernel_segment->mem,
+					  kernel_segment->memsz, initrd,
+					  initrd_len, cmdline, cmdline_len);
+		if (!ret)
+			break;
+
+		/*
+		 * We couldn't find space for the other segments; erase the
+		 * kernel segment and try the next available hole.
+		 */
+		image->nr_segments -= 1;
+		kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	}

arch/loongarch/kernel/kexec_image.c line 100

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+
+	if (ret) {
+		pr_err("Could not find any suitable kernel location!");
+		return ERR_PTR(ret);
+	}
+
+	kernel_segment = &image->segment[kernel_segment_number];
+
+	/* Make sure the second kernel jumps to the correct "kernel_entry". */
+	image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

Quoted 4 lines

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

LoongArch enables the relocation of the kernel when the kdump feature is enabled.

config ARCH_SELECTS_CRASH_DUMP
        def_bool y
        depends on CRASH_DUMP
        select RELOCATABLE

After enabling the relocation, LoongArch is the PIE kernel. For more details, please refer to commit d8da19fbdedd ("LoongArch:
Add support for kernel relocation")

Quoted 31 lines
Quoted 16 lines
arch/loongarch/kernel/kexec_image.c new file +11 -0
+	kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		      kernel_segment->mem, kbuf.bufsz,
+		      kernel_segment->memsz);
+
+	return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+	.probe = image_probe,
+	.load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +0 -0
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)

...

Quoted 13 lines
arch/loongarch/kernel/machine_kexec.c +4 -3
-	if (!kimage->arch.cmdline_ptr) {
-		pr_err("Command line not included in the provided image\n");
-		return -EINVAL;
+		if (!kimage->arch.cmdline_ptr) {
+			pr_err("Command line not included in the provided image\n");
+			return -EINVAL;
+		}
  	}
 
  	/* kexec/kdump need a safe page to save reboot_code_buffer */
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
  	local_irq_disable();
 
Quoted 7 lines

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 302

Quoted 4 lines
arch/loongarch/kernel/machine_kexec.c +2 -1
  	pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-	pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+	pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+	pr_notice("Command line at %s\n", (char *)cmdline_ptr);

The printed message doesn't match meaning of the pointer: you're printing the content of cmdline_ptr, instead of its address, thus "Command line at" sounds confusing to me.

I will correct it.

Thanks,
Youling.

Quoted 10 lines

Furthermore, this chunk isn't related to "support for kexec_file", I think it's better to separate it into another patch (or even another series).

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 305

Quoted 3 lines
arch/loongarch/kernel/machine_kexec.c +0 -0
  	pr_notice("System table at 0x%lx\n", systable_ptr);
  	pr_notice("We will call new kernel at 0x%lx\n", start_addr);
  	pr_notice("Bye ...\n");

Best regards,
Yao Zi

#13 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 195 lines · Youling Tang

Hi, Yao

Quoted 27 lines · Yao Zi
Quoted 24 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported, but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++ arch/loongarch/include/asm/image.h         |  18 ++++ arch/loongarch/include/asm/kexec.h         |  12 +++ arch/loongarch/kernel/Makefile             |   1 + arch/loongarch/kernel/kexec_image.c        | 112
+++++++++++++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++++-- arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++

  7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

Quoted 11 lines

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 40

Quoted 10 lines
arch/loongarch/include/asm/image.h +1 -0
index 1f090736e71d..829e1ecb1f5d 100644
@@ -36,5 +36,23 @@ struct loongarch_image_header {
       uint32_t pe_header;
   };
   +static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 
 0x0, 0x64, 0x62};

loongarch_pe_machtype isn't used at all.

It will be removed.

Quoted 51 lines
Quoted 11 lines
arch/loongarch/include/asm/image.h +3 -0
+
+/**
+ * loongarch_header_check_pe_sig - Helper to check the loongarch 

image header.
+ *
+ * Returns non-zero if 'MZ' signature is found.
+ */

arch/loongarch/include/asm/image.h +2 -0
+
+static inline int loongarch_header_check_pe_sig(const struct 

loongarch_image_header *h)

arch/loongarch/include/asm/image.h struct loongarch_image_header { · line 54

Quoted 6 lines
arch/loongarch/include/asm/image.h +6 -0
+{
+    if (!h)
+        return 0;
+
+    return (h->pe_sig[0] == loongarch_image_pe_sig[0]
+        && h->pe_sig[1] == loongarch_image_pe_sig[1]);

This could be simplified with a memcmp(). Also, this check isn't strict
enough: PE files for any architectures, and even legacy MS-DOS COM executables all start with "MZ".

Quoted 4 lines
arch/loongarch/include/asm/image.h +2 -0
+}
+

  #endif /* __ASSEMBLY__ */
  #endif /* __ASM_IMAGE_H */

...

Quoted 24 lines
arch/loongarch/kernel/kexec_image.c new file +18 -0
new file mode 100644
index 000000000000..fdd1845b4e2e
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <[email protected]>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt)    "kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
Quoted 8 lines
Quoted 7 lines
arch/loongarch/kernel/kexec_image.c new file +3 -0
+#include <asm/image.h>
+
+static int image_probe(const char *kernel_buf, unsigned long 

kernel_len)
+{
+    const struct loongarch_image_header *h =
+        (const struct loongarch_image_header *)(kernel_buf);

Parentheses around "kernel_buf" are unnecessary.

It will be removed.

Quoted 4 lines
Quoted 2 lines

+    if (!h || (kernel_len < sizeof(*h))) {

Comparisons have higher priority than logic operations, so this pair of parentheses is redundant, too.

Yes, but the parentheses will be retained for greater readability.

Quoted 85 lines
Quoted 30 lines

+        pr_err("No loongarch image header.\n");
+        return -EINVAL;
+    }

arch/loongarch/kernel/kexec_image.c new file +26 -0
+
+    if (!loongarch_header_check_pe_sig(h)) {
+        pr_err("Bad loongarch PE image header.\n");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static void *image_load(struct kimage *image,
+                char *kernel, unsigned long kernel_len,
+                char *initrd, unsigned long initrd_len,
+                char *cmdline, unsigned long cmdline_len)
+{
+    struct loongarch_image_header *h;
+    struct kexec_buf kbuf;
+    unsigned long text_offset, kernel_segment_number;
+    struct kexec_segment *kernel_segment;
+    int ret;
+
+    h = (struct loongarch_image_header *)kernel;
+    if (!h->image_size)
+        return ERR_PTR(-EINVAL);
+
+    /* Load the kernel */
+    kbuf.image = image;

arch/loongarch/kernel/kexec_image.c line 65

Quoted 10 lines
arch/loongarch/kernel/kexec_image.c new file +10 -0
+    kbuf.buf_min = 0;
+    kbuf.buf_max = ULONG_MAX;
+    kbuf.top_down = false;
+
+    kbuf.buffer = kernel;
+    kbuf.bufsz = kernel_len;
+    kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+    kbuf.memsz = le64_to_cpu(h->image_size);
+    text_offset = le64_to_cpu(h->text_offset);
+    kbuf.buf_align = SZ_2M;

I think this aligment is unnecessary for relocatable LoongArch kernels:
it should be enough to align to the page size. See also my comments below.

Quoted 34 lines

+    kernel_segment_number = image->nr_segments;
+
+    /*
+     * The location of the kernel segment may make it impossible to satisfy
+     * the other segment requirements, so we try repeatedly to find a +     * location that will work.
+     */
+    while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+        /* Try to load additional data */
+        kernel_segment = &image->segment[kernel_segment_number]; +        ret = load_other_segments(image, kernel_segment->mem, +                      kernel_segment->memsz, initrd,
+                      initrd_len, cmdline, cmdline_len);
+        if (!ret)
+            break;

arch/loongarch/kernel/kexec_image.c new file +18 -0
+
+        /*
+         * We couldn't find space for the other segments; erase the
+         * kernel segment and try the next available hole.
+         */
+        image->nr_segments -= 1;
+        kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+    }
+
+    if (ret) {
+        pr_err("Could not find any suitable kernel location!");
+        return ERR_PTR(ret);
+    }
+
+    kernel_segment = &image->segment[kernel_segment_number];
+
+    /* Make sure the second kernel jumps to the correct 
Quoted 3 lines

"kernel_entry". */
+    image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

Quoted 4 lines

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

Quoted 8 lines

LoongArch enables the relocation of the kernel when the kdump feature is enabled.

config ARCH_SELECTS_CRASH_DUMP
        def_bool y
        depends on CRASH_DUMP
        select RELOCATABLE

When enabling KEXEC_FILE, the RELOCATABLE configuration should also be enabled. Both kexec and kdump require this.

Youling.

Quoted 54 lines

After enabling the relocation, LoongArch is the PIE kernel. For more details, please refer to commit d8da19fbdedd ("LoongArch:
Add support for kernel relocation")

Quoted 29 lines
Quoted 16 lines

+    kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", +              kernel_segment->mem, kbuf.bufsz,
+              kernel_segment->memsz);

arch/loongarch/kernel/kexec_image.c new file +8 -0
+
+    return NULL;
+}
+
+const struct kexec_file_ops kexec_image_ops = {
+    .probe = image_probe,
+    .load = image_load,
+};
arch/loongarch/kernel/machine_kexec.c +0 -0
index f9381800e291..008f43e26120 100644
@@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)

...

Quoted 11 lines

-    if (!kimage->arch.cmdline_ptr) {
-        pr_err("Command line not included in the provided image\n"); -        return -EINVAL;
+        if (!kimage->arch.cmdline_ptr) {
+            pr_err("Command line not included in the provided image\n");
+            return -EINVAL;
+        }
      }
        /* kexec/kdump need a safe page to save reboot_code_buffer */

arch/loongarch/kernel/machine_kexec.c +0 -0
@@ -288,7 +298,8 @@ void machine_kexec(struct kimage *image)
Quoted 8 lines

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 302

Quoted 5 lines
arch/loongarch/kernel/machine_kexec.c +2 -1
       local_irq_disable();
         pr_notice("EFI boot flag 0x%lx\n", efi_boot);
-    pr_notice("Command line at 0x%lx\n", cmdline_ptr);
+    pr_notice("Command line addr at 0x%lx\n", cmdline_ptr);
+    pr_notice("Command line at %s\n", (char *)cmdline_ptr);

The printed message doesn't match meaning of the pointer: you're printing the content of cmdline_ptr, instead of its address, thus "Command line at" sounds confusing to me.

I will correct it.

Thanks,
Youling.

Quoted 10 lines

Furthermore, this chunk isn't related to "support for kexec_file", I think it's better to separate it into another patch (or even another series).

arch/loongarch/kernel/machine_kexec.c void machine_kexec(struct kimage *image) · line 305

Quoted 3 lines
arch/loongarch/kernel/machine_kexec.c +0 -0
       pr_notice("System table at 0x%lx\n", systable_ptr);
       pr_notice("We will call new kernel at 0x%lx\n", start_addr);
       pr_notice("Bye ...\n");

Best regards,
Yao Zi

#14 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 29 lines · Youling Tang
Quoted 28 lines · Youling Tang

Hi, Yao

Quoted 26 lines · Yao Zi
Quoted 25 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported,
but ELF format is not supported.

---
  arch/loongarch/Kconfig                     |   8 ++ arch/loongarch/include/asm/image.h         |  18 ++++ arch/loongarch/include/asm/kexec.h         |  12 +++ arch/loongarch/kernel/Makefile             |   1 + arch/loongarch/kernel/kexec_image.c        | 112
+++++++++++++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++++-- arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++

  7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
arch/loongarch/kernel/kexec_image.c new file +0 -0
new file mode 100644
index 000000000000..fdd1845b4e2e

...

Quoted 43 lines
Quoted 43 lines
Quoted 43 lines
Quoted 32 lines

+    /*
+     * The location of the kernel segment may make it impossible to satisfy
+     * the other segment requirements, so we try repeatedly to find a +     * location that will work.
+     */
+    while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+        /* Try to load additional data */
+        kernel_segment = &image->segment[kernel_segment_number]; +        ret = load_other_segments(image, kernel_segment->mem, +                      kernel_segment->memsz, initrd,
+                      initrd_len, cmdline, cmdline_len);
+        if (!ret)
+            break;

arch/loongarch/kernel/kexec_image.c new file +18 -0
+
+        /*
+         * We couldn't find space for the other segments; erase the
+         * kernel segment and try the next available hole.
+         */
+        image->nr_segments -= 1;
+        kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+    }
+
+    if (ret) {
+        pr_err("Could not find any suitable kernel location!");
+        return ERR_PTR(ret);
+    }
+
+    kernel_segment = &image->segment[kernel_segment_number];
+
+    /* Make sure the second kernel jumps to the correct
Quoted 3 lines

"kernel_entry". */
+    image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

Quoted 8 lines
Quoted 8 lines

LoongArch enables the relocation of the kernel when the kdump feature is enabled.

config ARCH_SELECTS_CRASH_DUMP
        def_bool y
        depends on CRASH_DUMP
        select RELOCATABLE

This only means the currently-running kernel is relocatable, not the one being exec'ed, right?

Quoted 2 lines

When enabling KEXEC_FILE, the RELOCATABLE configuration should also be enabled. Both kexec and kdump require this.

I'm not sure whether you're talking about the running kernel or the one that is going to be exec'ed. This method of kernel loading requires the exec'ed kernel being relocatable, not the currently running one.

And I think it's totally reasonable to use KEXEC_FILE for non-crash-dump purpose, for example, linuxboot. It'll be confusing to the user if the system just hangs after booting a non-relocatable kernel, which is hard to debug.

Thus IMHO we should ideally refuse to load non-relocatable kernels, or add a FIXME comment to indicate the situation that it's impossible to determine whether the exec'ed image is relocatable.

Quoted 4 lines

Youling.

Quoted 3 lines

After enabling the relocation, LoongArch is the PIE kernel. For more details, please refer to commit d8da19fbdedd ("LoongArch:
Add support for kernel relocation")

Best regards.
Yao Zi

#15 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Hi, Yao

Quoted 86 lines · Yao Zi
Quoted 29 lines · Youling Tang
Quoted 28 lines · Youling Tang

Hi, Yao

Quoted 26 lines · Yao Zi
Quoted 25 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported,
but ELF format is not supported.

---
   arch/loongarch/Kconfig                     |   8 ++
   arch/loongarch/include/asm/image.h         |  18 ++++
   arch/loongarch/include/asm/kexec.h         |  12 +++
   arch/loongarch/kernel/Makefile             |   1 +
   arch/loongarch/kernel/kexec_image.c        | 112
+++++++++++++++++++++
   arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
   arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
   7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
arch/loongarch/kernel/kexec_image.c new file +0 -0
new file mode 100644
index 000000000000..fdd1845b4e2e

...

Quoted 46 lines
Quoted 46 lines
Quoted 39 lines
Quoted 32 lines

+    /*
+     * The location of the kernel segment may make it impossible to satisfy
+     * the other segment requirements, so we try repeatedly to find a +     * location that will work.
+     */
+    while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+        /* Try to load additional data */
+        kernel_segment = &image->segment[kernel_segment_number]; +        ret = load_other_segments(image, kernel_segment->mem, +                      kernel_segment->memsz, initrd,
+                      initrd_len, cmdline, cmdline_len);
+        if (!ret)
+            break;

arch/loongarch/kernel/kexec_image.c new file +18 -0
+
+        /*
+         * We couldn't find space for the other segments; erase the
+         * kernel segment and try the next available hole.
+         */
+        image->nr_segments -= 1;
+        kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+    }
+
+    if (ret) {
+        pr_err("Could not find any suitable kernel location!");
+        return ERR_PTR(ret);
+    }
+
+    kernel_segment = &image->segment[kernel_segment_number];
+
+    /* Make sure the second kernel jumps to the correct
Quoted 3 lines

"kernel_entry". */
+    image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

Quoted 4 lines

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

LoongArch enables the relocation of the kernel when the kdump feature is enabled.

Quoted 7 lines
Quoted 5 lines
Quoted 5 lines

config ARCH_SELECTS_CRASH_DUMP
        def_bool y
        depends on CRASH_DUMP
        select RELOCATABLE

This only means the currently-running kernel is relocatable, not the one being exec'ed, right?

No.

Quoted 6 lines
Quoted 2 lines

When enabling KEXEC_FILE, the RELOCATABLE configuration should also be enabled. Both kexec and kdump require this.

I'm not sure whether you're talking about the running kernel or the one that is going to be exec'ed. This method of kernel loading requires the exec'ed kernel being relocatable, not the currently running one.

Quoted 8 lines

And I think it's totally reasonable to use KEXEC_FILE for non-crash-dump purpose, for example, linuxboot. It'll be confusing to the user if the system just hangs after booting a non-relocatable kernel, which is hard to debug.

Thus IMHO we should ideally refuse to load non-relocatable kernels, or add a FIXME comment to indicate the situation that it's impossible to determine whether the exec'ed image is relocatable.

The first kernel and the second kernel are generally the same kernel (the same image). When KEXEC_FILE is enabled and RELOCATEABLE is enabled by default, it has been forcibly guaranteed that both the first kernel and the second kernel are relocatable kernels regardless of kexec/kdump operations.

Unless the second kernel it loads is an older version of the kernel (the older version of the kernel does not use the default configuration, with CONFIG_KEXEC enabled but CONFIG_CRASH_DUMP disabled, this is not acorrect usage).

Thanks,
Youling.

Quoted 6 lines
Quoted 4 lines

Youling.

Quoted 3 lines

After enabling the relocation, LoongArch is the PIE kernel. For more details, please refer to commit d8da19fbdedd ("LoongArch:
Add support for kernel relocation")

Best regards.
Yao Zi

#16 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

Quoted 107 lines · Youling Tang

Hi, Yao

Quoted 86 lines · Yao Zi
Quoted 29 lines · Youling Tang
Quoted 28 lines · Youling Tang

Hi, Yao

Quoted 26 lines · Yao Zi
Quoted 25 lines · Youling Tang

From: Youling Tang <[email protected]>

This patch adds support for kexec_file on LoongArch.

The image_load() as two parts:
- the first part loads the kernel image (vmlinuz.efi or vmlinux.efi)
- the second part loads other segments (eg: initrd, cmdline)

Currently, pez(vmlinuz.efi) and pei(vmlinux.efi) format images are supported,
but ELF format is not supported.

---
   arch/loongarch/Kconfig                     |   8 ++
   arch/loongarch/include/asm/image.h         |  18 ++++
   arch/loongarch/include/asm/kexec.h         |  12 +++
   arch/loongarch/kernel/Makefile             |   1 +
   arch/loongarch/kernel/kexec_image.c        | 112
+++++++++++++++++++++
   arch/loongarch/kernel/machine_kexec.c      |  33 ++++--
   arch/loongarch/kernel/machine_kexec_file.c |  46 +++++++++
   7 files changed, 219 insertions(+), 11 deletions(-)

  create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

...

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
arch/loongarch/kernel/kexec_image.c new file +0 -0
new file mode 100644
index 000000000000..fdd1845b4e2e

...

Quoted 46 lines
Quoted 46 lines
Quoted 39 lines
Quoted 32 lines

+    /*
+     * The location of the kernel segment may make it impossible to satisfy
+     * the other segment requirements, so we try repeatedly to find a +     * location that will work.
+     */
+    while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+        /* Try to load additional data */
+        kernel_segment = &image->segment[kernel_segment_number]; +        ret = load_other_segments(image, kernel_segment->mem, +                      kernel_segment->memsz, initrd,
+                      initrd_len, cmdline, cmdline_len);
+        if (!ret)
+            break;

arch/loongarch/kernel/kexec_image.c new file +18 -0
+
+        /*
+         * We couldn't find space for the other segments; erase the
+         * kernel segment and try the next available hole.
+         */
+        image->nr_segments -= 1;
+        kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+    }
+
+    if (ret) {
+        pr_err("Could not find any suitable kernel location!");
+        return ERR_PTR(ret);
+    }
+
+    kernel_segment = &image->segment[kernel_segment_number];
+
+    /* Make sure the second kernel jumps to the correct
Quoted 3 lines

"kernel_entry". */
+    image->start = kernel_segment->mem + h->kernel_entry - text_offset;

A non-relocatable loongarch kernel cannot be loaded to arbitrary address. Thus this loading function seems to only work for relocatable kernels, maybe it's better to leave a comment indicating the limitation.

Quoted 4 lines

For now, we don't seem to have a way to find out whether the kernel is relocatable (for example, a flag in kernel image header), so it's impossible to point out whether the loaded kernel boots fine with arbitrary loading address...

LoongArch enables the relocation of the kernel when the kdump feature is enabled.

Quoted 7 lines
Quoted 5 lines
Quoted 5 lines

config ARCH_SELECTS_CRASH_DUMP
        def_bool y
        depends on CRASH_DUMP
        select RELOCATABLE

This only means the currently-running kernel is relocatable, not the one being exec'ed, right?

No.

Quoted 11 lines
Quoted 2 lines

When enabling KEXEC_FILE, the RELOCATABLE configuration should also be enabled. Both kexec and kdump require this.

I'm not sure whether you're talking about the running kernel or the one that is going to be exec'ed. This method of kernel loading requires the exec'ed kernel being relocatable, not the currently running one.

And I think it's totally reasonable to use KEXEC_FILE for non-crash-dump purpose, for example, linuxboot. It'll be confusing to the user if the system just hangs after booting a non-relocatable kernel, which is hard to debug.

Quoted 5 lines
Quoted 3 lines

Thus IMHO we should ideally refuse to load non-relocatable kernels, or add a FIXME comment to indicate the situation that it's impossible to determine whether the exec'ed image is relocatable.

The first kernel and the second kernel are generally the same kernel (the same image).

This isn't true. There're real-world cases using kexec-file to load and boot an unrelated kernel image. Please refer to petitboot[1] and linuxboot[2] which uses kexec to act as a bootloader.

Quoted 4 lines

When KEXEC_FILE is enabled and RELOCATEABLE
is enabled by default, it has been forcibly guaranteed that both the first kernel and the second kernel are relocatable kernels regardless of kexec/kdump operations.

This cannot be guaranteed since the first and second kernel could be completely unrelated. Please see my previous comment.

Quoted 5 lines

Unless the second kernel it loads is an older version of the kernel (the older version of the kernel does not use the default configuration, with CONFIG_KEXEC enabled but CONFIG_CRASH_DUMP disabled,

this is not acorrect usage).

This may be incorrect for kdump's use case, but kexec-file isn't only meant to be used with kdump: it just loads an arbitrary kernel image and executes it, no matter whether it's for capturing a dump, booting a newer or older kernel, or etc, and there's no guarantee about features enabled in the second kernel. It's incorrect to assume the user only loads relocatable images with kexec-file.

Quoted 9 lines

Thanks,
Youling.

Quoted 6 lines
Quoted 4 lines

Youling.

Quoted 3 lines

After enabling the relocation, LoongArch is the PIE kernel. For more details, please refer to commit d8da19fbdedd ("LoongArch:
Add support for kernel relocation")

Best regards.
Yao Zi

Thanks,
Yao Zi

[1]: https://github.com/open-power/petitboot
[2]: https://github.com/linuxboot/linuxboot

#17 lore raw

Re: [PATCH 2/6] LoongArch: Add kexec_file support

In reply to Youling Tang
kernel test robot noticed the following build warnings:

Hi Youling,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.17-rc1 next-20250815]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Youling-Tang/LoongArch-Add-struct-loongarch_image_header-for-kernel-image/20250811-174725
base:   linus/master
patch link:    https://lore.kernel.org/r/20250811092659.14903-3-youling.tang%40linux.dev
patch subject: [PATCH 2/6] LoongArch: Add kexec_file support
config: loongarch-randconfig-r121-20250816 (https://download.01.org/0day-ci/archive/20250816/[email protected]/config)
compiler: loongarch64-linux-gcc (GCC) 15.1.0
reproduce: (https://download.01.org/0day-ci/archive/20250816/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All warnings (new ones prefixed by >>):

In file included from arch/loongarch/kernel/kexec_image.c:19:

>> arch/loongarch/include/asm/image.h:40:22: warning: 'loongarch_pe_machtype' defined but not used [-Wunused-const-variable=]
      40 | static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
         |                      ^~~~~~~~~~~~~~~~~~~~~

sparse warnings: (new ones prefixed by >>)

>> arch/loongarch/kernel/kexec_image.c:63:22: sparse: sparse: cast to restricted __le64

arch/loongarch/kernel/kexec_image.c:64:23: sparse: sparse: cast to restricted __le64

vim +/loongarch_pe_machtype +40 arch/loongarch/include/asm/image.h

    38	
    39	static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
  > 40	static const uint8_t loongarch_pe_machtype[6] = {'P', 'E', 0x0, 0x0, 0x64, 0x62};
    41	
Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#18 lore raw

PATCH 3/6 LoongArch/kexec_file: Add initrd loading

In reply to Youling Tang

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

---
 arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
 1 file changed, 71 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +71 -0
index bc91ae0afa4c..e1240644f529 100644
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	return kexec_image_post_load_cleanup_default(image);
 }
 
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+				char *modified_cmdline, unsigned long initrd)
+{
+	int initrd_strlen;
+
+	initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",
+		initrd, image->initrd_buf_len);
+	*cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
 int load_other_segments(struct kimage *image,
 			unsigned long kernel_load_addr,
 			unsigned long kernel_size,
 			char *initrd, unsigned long initrd_len,
 			char *cmdline, unsigned long cmdline_len)
 {
+	struct kexec_buf kbuf;
+	unsigned long orig_segments = image->nr_segments;
+	char *modified_cmdline = NULL;
+	unsigned long cmdline_tmplen = 0;
+	unsigned long initrd_load_addr = 0;
+	int ret = 0;
+
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = kernel_load_addr + kernel_size;
+
+	modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+	if (!modified_cmdline)
+		return -EINVAL;
+
+	/* Ensure it's nul terminated */
+	modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+	/* load initrd */
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = 0;
+		/* within 1GB-aligned window of up to 32GB in size */
+		kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+						+ (unsigned long)SZ_1G * 32;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+		initrd_load_addr = kbuf.mem;
+
+		kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			      initrd_load_addr, kbuf.bufsz, kbuf.memsz);
+
+		/* Add the initrd=start,size parameter to the command line */
+		cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+	}
+
+	if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
+		pr_err("Appending kdump cmdline exceeds cmdline size\n");
+		ret = -EINVAL;
+		goto out_err;
+	}
+	memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
+	cmdline = modified_cmdline;
 	image->arch.cmdline_ptr = (unsigned long)cmdline;
 
 	return 0;
+
+out_err:
+	image->nr_segments = orig_segments;
+	kfree(modified_cmdline);
+	return ret;
 }
Signature · 1 line
2.34.1
maintainer
#19 lore raw

Re: [PATCH 3/6] LoongArch/kexec_file: Add initrd loading

Hi, Youling,

Quoted 5 lines · Youling Tang

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

I think Patch-3 and Patch-5 should be merged into Patch-2.

Huacai

Quoted 98 lines
---
 arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
 1 file changed, 71 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +71 -1
index bc91ae0afa4c..e1240644f529 100644
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
        return kexec_image_post_load_cleanup_default(image);
 }
 
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+                               char *modified_cmdline, unsigned long initrd)
+{
+       int initrd_strlen;
+
+       initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",
+               initrd, image->initrd_buf_len);
+       *cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
 int load_other_segments(struct kimage *image,
                        unsigned long kernel_load_addr,
                        unsigned long kernel_size,
                        char *initrd, unsigned long initrd_len,
                        char *cmdline, unsigned long cmdline_len)
 {
+       struct kexec_buf kbuf;
+       unsigned long orig_segments = image->nr_segments;
+       char *modified_cmdline = NULL;
+       unsigned long cmdline_tmplen = 0;
+       unsigned long initrd_load_addr = 0;
+       int ret = 0;
+
+
+       kbuf.image = image;
+       /* not allocate anything below the kernel */
+       kbuf.buf_min = kernel_load_addr + kernel_size;
+
+       modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+       if (!modified_cmdline)
+               return -EINVAL;
+
+       /* Ensure it's nul terminated */
+       modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+       /* load initrd */
+       if (initrd) {
+               kbuf.buffer = initrd;
+               kbuf.bufsz = initrd_len;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+               kbuf.memsz = initrd_len;
+               kbuf.buf_align = 0;
+               /* within 1GB-aligned window of up to 32GB in size */
+               kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+                                               + (unsigned long)SZ_1G * 32;
+               kbuf.top_down = false;
+
+               ret = kexec_add_buffer(&kbuf);
+               if (ret)
+                       goto out_err;
+               initrd_load_addr = kbuf.mem;
+
+               kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                             initrd_load_addr, kbuf.bufsz, kbuf.memsz);
+
+               /* Add the initrd=start,size parameter to the command line */
+               cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+       }
+
+       if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
+               pr_err("Appending kdump cmdline exceeds cmdline size\n");
+               ret = -EINVAL;
+               goto out_err;
+       }
+       memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
+       cmdline = modified_cmdline;
        image->arch.cmdline_ptr = (unsigned long)cmdline;
 
        return 0;
+
+out_err:
+       image->nr_segments = orig_segments;
+       kfree(modified_cmdline);
+       return ret;
 }
--

2.34.1

#20 lore raw

Re: [PATCH 3/6] LoongArch/kexec_file: Add initrd loading

Hi, Huacai

Quoted 8 lines · Huacai Chen

Hi, Youling,

Quoted 4 lines · Youling Tang

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

I think Patch-3 and Patch-5 should be merged into Patch-2.

Not all cases require loading initrd, so Patch-2 is a runnable basic patch. Separating it into different patches makes it easier to understand and review the code.

Patch-5 coming out separately can better illustrate the role of "mem" parameters in capturing the kernel.

Youling.

Quoted 100 lines

Huacai

Quoted 97 lines
---
  arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
  1 file changed, 71 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +71 -1
index bc91ae0afa4c..e1240644f529 100644
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
         return kexec_image_post_load_cleanup_default(image);
  }
 
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+                               char *modified_cmdline, unsigned long initrd)
+{
+       int initrd_strlen;
+
+       initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",
+               initrd, image->initrd_buf_len);
+       *cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
  int load_other_segments(struct kimage *image,
                         unsigned long kernel_load_addr,
                         unsigned long kernel_size,
                         char *initrd, unsigned long initrd_len,
                         char *cmdline, unsigned long cmdline_len)
  {
+       struct kexec_buf kbuf;
+       unsigned long orig_segments = image->nr_segments;
+       char *modified_cmdline = NULL;
+       unsigned long cmdline_tmplen = 0;
+       unsigned long initrd_load_addr = 0;
+       int ret = 0;
+
+
+       kbuf.image = image;
+       /* not allocate anything below the kernel */
+       kbuf.buf_min = kernel_load_addr + kernel_size;
+
+       modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+       if (!modified_cmdline)
+               return -EINVAL;
+
+       /* Ensure it's nul terminated */
+       modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+       /* load initrd */
+       if (initrd) {
+               kbuf.buffer = initrd;
+               kbuf.bufsz = initrd_len;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+               kbuf.memsz = initrd_len;
+               kbuf.buf_align = 0;
+               /* within 1GB-aligned window of up to 32GB in size */
+               kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+                                               + (unsigned long)SZ_1G * 32;
+               kbuf.top_down = false;
+
+               ret = kexec_add_buffer(&kbuf);
+               if (ret)
+                       goto out_err;
+               initrd_load_addr = kbuf.mem;
+
+               kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                             initrd_load_addr, kbuf.bufsz, kbuf.memsz);
+
+               /* Add the initrd=start,size parameter to the command line */
+               cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+       }
+
+       if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
+               pr_err("Appending kdump cmdline exceeds cmdline size\n");
+               ret = -EINVAL;
+               goto out_err;
+       }
+       memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
+       cmdline = modified_cmdline;
         image->arch.cmdline_ptr = (unsigned long)cmdline;
 
         return 0;
+
+out_err:
+       image->nr_segments = orig_segments;
+       kfree(modified_cmdline);
+       return ret;
  }
--

2.34.1

maintainer
#21 lore raw

Re: [PATCH 3/6] LoongArch/kexec_file: Add initrd loading

Quoted 6 lines · Youling Tang

Hi, Huacai

Quoted 3 lines · Huacai Chen

Hi, Youling,

On Mon, Aug 11, 2025 at 5:28 PM Youling Tang <[email protected]> wrote:

Quoted 8 lines
Quoted 5 lines
Quoted 4 lines

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

I think Patch-3 and Patch-5 should be merged into Patch-2.

Not all cases require loading initrd, so Patch-2 is a runnable basic patch. Separating it into different patches makes it easier to understand and review the code.

Unnecessary, without separating the code is clear enough.

Quoted 3 lines

Patch-5 coming out separately can better illustrate the role of "mem" parameters in capturing the kernel.

Emm, Patch-5 should be squashed to Patch-4, not Patch-2.

Huacai

Quoted 102 lines

Youling.

Quoted 100 lines

Huacai

Quoted 97 lines
---
  arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
  1 file changed, 71 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +71 -1
index bc91ae0afa4c..e1240644f529 100644
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
         return kexec_image_post_load_cleanup_default(image);
  }
 
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+                               char *modified_cmdline, unsigned long initrd)
+{
+       int initrd_strlen;
+
+       initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",
+               initrd, image->initrd_buf_len);
+       *cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
  int load_other_segments(struct kimage *image,
                         unsigned long kernel_load_addr,
                         unsigned long kernel_size,
                         char *initrd, unsigned long initrd_len,
                         char *cmdline, unsigned long cmdline_len)
  {
+       struct kexec_buf kbuf;
+       unsigned long orig_segments = image->nr_segments;
+       char *modified_cmdline = NULL;
+       unsigned long cmdline_tmplen = 0;
+       unsigned long initrd_load_addr = 0;
+       int ret = 0;
+
+
+       kbuf.image = image;
+       /* not allocate anything below the kernel */
+       kbuf.buf_min = kernel_load_addr + kernel_size;
+
+       modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+       if (!modified_cmdline)
+               return -EINVAL;
+
+       /* Ensure it's nul terminated */
+       modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+       /* load initrd */
+       if (initrd) {
+               kbuf.buffer = initrd;
+               kbuf.bufsz = initrd_len;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+               kbuf.memsz = initrd_len;
+               kbuf.buf_align = 0;
+               /* within 1GB-aligned window of up to 32GB in size */
+               kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+                                               + (unsigned long)SZ_1G * 32;
+               kbuf.top_down = false;
+
+               ret = kexec_add_buffer(&kbuf);
+               if (ret)
+                       goto out_err;
+               initrd_load_addr = kbuf.mem;
+
+               kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                             initrd_load_addr, kbuf.bufsz, kbuf.memsz);
+
+               /* Add the initrd=start,size parameter to the command line */
+               cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+       }
+
+       if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
+               pr_err("Appending kdump cmdline exceeds cmdline size\n");
+               ret = -EINVAL;
+               goto out_err;
+       }
+       memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
+       cmdline = modified_cmdline;
         image->arch.cmdline_ptr = (unsigned long)cmdline;
 
         return 0;
+
+out_err:
+       image->nr_segments = orig_segments;
+       kfree(modified_cmdline);
+       return ret;
  }
--

2.34.1

#22 lore raw

Re: [PATCH 3/6] LoongArch/kexec_file: Add initrd loading

In reply to Youling Tang
Quoted 4 lines · Youling Tang

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

I think This won't work if the exec'ed kernel enables CONFIG_CMDLINE_FORCE. Is it possible to mimic libstub's behavior of installing a configuration table LINUX_EFI_INITRD_MEDIA_GUID?

Quoted 11 lines
---
 arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
 1 file changed, 71 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +0 -0
index bc91ae0afa4c..e1240644f529 100644

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 43

Quoted 10 lines
arch/loongarch/kernel/machine_kexec_file.c +7 -0
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	return kexec_image_post_load_cleanup_default(image);
 }
 
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+				char *modified_cmdline, unsigned long initrd)
+{
+	int initrd_strlen;
+
+	initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",

modified_cmdline is allocated as COMMAND_LINE_SIZE bytes, thus I think it's possible to overflow the buffer.

Quoted 49 lines
arch/loongarch/kernel/machine_kexec_file.c +43 -0
+		initrd, image->initrd_buf_len);
+	*cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
 int load_other_segments(struct kimage *image,
 			unsigned long kernel_load_addr,
 			unsigned long kernel_size,
 			char *initrd, unsigned long initrd_len,
 			char *cmdline, unsigned long cmdline_len)
 {
+	struct kexec_buf kbuf;
+	unsigned long orig_segments = image->nr_segments;
+	char *modified_cmdline = NULL;
+	unsigned long cmdline_tmplen = 0;
+	unsigned long initrd_load_addr = 0;
+	int ret = 0;
+
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = kernel_load_addr + kernel_size;
+
+	modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+	if (!modified_cmdline)
+		return -EINVAL;
+
+	/* Ensure it's nul terminated */
+	modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+	/* load initrd */
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = 0;
+		/* within 1GB-aligned window of up to 32GB in size */
+		kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+						+ (unsigned long)SZ_1G * 32;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 102

Quoted 10 lines
arch/loongarch/kernel/machine_kexec_file.c +10 -0
+		initrd_load_addr = kbuf.mem;
+
+		kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			      initrd_load_addr, kbuf.bufsz, kbuf.memsz);
+
+		/* Add the initrd=start,size parameter to the command line */
+		cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+	}
+
+	if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {

It's too later to check for overflowing here, where the data after modified_cmdline may already be overwritten.

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 103

Quoted 1 line
arch/loongarch/kernel/machine_kexec_file.c +1 -0
+		pr_err("Appending kdump cmdline exceeds cmdline size\n");

I think load_other_segments could be invoked without kdump involved. If that's correct, this message is inaccurate.

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 106

Quoted 3 lines
arch/loongarch/kernel/machine_kexec_file.c +3 -0
+		ret = -EINVAL;
+		goto out_err;
+	}

Regards,
Yao Zi

Quoted 15 lines
arch/loongarch/kernel/machine_kexec_file.c +7 -0
+	memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
+	cmdline = modified_cmdline;
 	image->arch.cmdline_ptr = (unsigned long)cmdline;
 
 	return 0;
+
+out_err:
+	image->nr_segments = orig_segments;
+	kfree(modified_cmdline);
+	return ret;
 }
Signature · 1 line
2.34.1
#23 lore raw

Re: [PATCH 3/6] LoongArch/kexec_file: Add initrd loading

Hi, Yao

Quoted 8 lines · Yao Zi
Quoted 4 lines · Youling Tang

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

I think This won't work if the exec'ed kernel enables CONFIG_CMDLINE_FORCE. Is it possible to mimic libstub's behavior of installing a configuration table LINUX_EFI_INITRD_MEDIA_GUID?

The command line passed by kexec to the second kernel has no effect if CONFIG_CMDLINE_FORCE is enabled, which is not quite suitable for the kexec scenario.

Currently, the initrd, elfcorehdr, and mem parameters will all be passed through the command line to maintain consistency with the implementation behavior of kexec-tools. It is possible that the content of systab will be modified in the future and some parts will be integrated into systab (the current cmdline mode will be better compatible with the elf kernel).

Quoted 14 lines
Quoted 14 lines
---
  arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
  1 file changed, 71 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +0 -0
index bc91ae0afa4c..e1240644f529 100644
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
  	return kexec_image_post_load_cleanup_default(image);
  }
 
Quoted 9 lines

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 43

Quoted 7 lines
arch/loongarch/kernel/machine_kexec_file.c +7 -0
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+				char *modified_cmdline, unsigned long initrd)
+{
+	int initrd_strlen;
+
+	initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",

modified_cmdline is allocated as COMMAND_LINE_SIZE bytes, thus I think it's possible to overflow the buffer.

At this point, modified_cmdline can clearly know that it only stores the additional commands we add (initrd,mem,elfcorehdr), and will not exceed COMMAND_LINE_SIZE.

Quoted 54 lines
Quoted 54 lines
arch/loongarch/kernel/machine_kexec_file.c +47 -0
+		initrd, image->initrd_buf_len);
+	*cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
  int load_other_segments(struct kimage *image,
  			unsigned long kernel_load_addr,
  			unsigned long kernel_size,
  			char *initrd, unsigned long initrd_len,
  			char *cmdline, unsigned long cmdline_len)
  {
+	struct kexec_buf kbuf;
+	unsigned long orig_segments = image->nr_segments;
+	char *modified_cmdline = NULL;
+	unsigned long cmdline_tmplen = 0;
+	unsigned long initrd_load_addr = 0;
+	int ret = 0;
+
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = kernel_load_addr + kernel_size;
+
+	modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+	if (!modified_cmdline)
+		return -EINVAL;
+
+	/* Ensure it's nul terminated */
+	modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+	/* load initrd */
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = 0;
+		/* within 1GB-aligned window of up to 32GB in size */
+		kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+						+ (unsigned long)SZ_1G * 32;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+		initrd_load_addr = kbuf.mem;
+
+		kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			      initrd_load_addr, kbuf.bufsz, kbuf.memsz);
Quoted 8 lines

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 102

Quoted 6 lines
arch/loongarch/kernel/machine_kexec_file.c +6 -0
+
+		/* Add the initrd=start,size parameter to the command line */
+		cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+	}
+
+	if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {

It's too later to check for overflowing here, where the data after modified_cmdline may already be overwritten.

At this point, we append the original command line to modified_cmdline, so it is appropriate to determine whether the command line length exceeds the limit.

Quoted 4 lines

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 103

Quoted 2 lines
arch/loongarch/kernel/machine_kexec_file.c +1 -0
+		pr_err("Appending kdump cmdline exceeds cmdline size\n");

I think load_other_segments could be invoked without kdump involved. If that's correct, this message is inaccurate.

Yes, it should be corrected.

Thanks,
Youling.

Quoted 22 lines

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 106

Quoted 4 lines
arch/loongarch/kernel/machine_kexec_file.c +3 -0
+		ret = -EINVAL;
+		goto out_err;
+	}

Regards,
Yao Zi

Quoted 15 lines
arch/loongarch/kernel/machine_kexec_file.c +7 -0
+	memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
+	cmdline = modified_cmdline;
  	image->arch.cmdline_ptr = (unsigned long)cmdline;
 
  	return 0;
+
+out_err:
+	image->nr_segments = orig_segments;
+	kfree(modified_cmdline);
+	return ret;
  }
Signature · 1 line
2.34.1
#24 lore raw

Re: [PATCH 3/6] LoongArch/kexec_file: Add initrd loading

Quoted 106 lines · Youling Tang

Hi, Yao

Quoted 8 lines · Yao Zi
Quoted 4 lines · Youling Tang

From: Youling Tang <[email protected]>

Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.

I think This won't work if the exec'ed kernel enables CONFIG_CMDLINE_FORCE. Is it possible to mimic libstub's behavior of installing a configuration table LINUX_EFI_INITRD_MEDIA_GUID?

The command line passed by kexec to the second kernel has no effect if CONFIG_CMDLINE_FORCE is enabled, which is not quite suitable for the kexec scenario.

Currently, the initrd, elfcorehdr, and mem parameters will all be passed through the command line to maintain consistency with the implementation behavior of kexec-tools. It is possible that the content of systab will be modified in the future and some parts will be integrated into systab (the current cmdline mode will be better compatible with the elf kernel).

Quoted 6 lines
Quoted 6 lines
---
  arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++
  1 file changed, 71 insertions(+)
Quoted 16 lines
Quoted 5 lines
arch/loongarch/kernel/machine_kexec_file.c +0 -0
index bc91ae0afa4c..e1240644f529 100644

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 42

Quoted 9 lines
arch/loongarch/kernel/machine_kexec_file.c +7 -0
@@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
  	return kexec_image_post_load_cleanup_default(image);
  }
+/* Adds the "initrd=start,size" command line parameter to command line. */
+static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
+				char *modified_cmdline, unsigned long initrd)
+{
+	int initrd_strlen;
+
+	initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",

modified_cmdline is allocated as COMMAND_LINE_SIZE bytes, thus I think it's possible to overflow the buffer.

At this point, modified_cmdline can clearly know that it only stores the additional commands we add (initrd,mem,elfcorehdr), and will not exceed COMMAND_LINE_SIZE.

Quoted 54 lines
Quoted 54 lines
arch/loongarch/kernel/machine_kexec_file.c +47 -0
+		initrd, image->initrd_buf_len);
+	*cmdline_tmplen += initrd_strlen;
+}
+
+/*
+ * Tries to add the initrd to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
  int load_other_segments(struct kimage *image,
  			unsigned long kernel_load_addr,
  			unsigned long kernel_size,
  			char *initrd, unsigned long initrd_len,
  			char *cmdline, unsigned long cmdline_len)
  {
+	struct kexec_buf kbuf;
+	unsigned long orig_segments = image->nr_segments;
+	char *modified_cmdline = NULL;
+	unsigned long cmdline_tmplen = 0;
+	unsigned long initrd_load_addr = 0;
+	int ret = 0;
+
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = kernel_load_addr + kernel_size;
+
+	modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
+	if (!modified_cmdline)
+		return -EINVAL;
+
+	/* Ensure it's nul terminated */
+	modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+
+	/* load initrd */
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = 0;
+		/* within 1GB-aligned window of up to 32GB in size */
+		kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
+						+ (unsigned long)SZ_1G * 32;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+		initrd_load_addr = kbuf.mem;
+
+		kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			      initrd_load_addr, kbuf.bufsz, kbuf.memsz);
Quoted 8 lines

arch/loongarch/kernel/machine_kexec_file.c int arch_kimage_file_post_load_cleanup(struct kimage *image) · line 102

Quoted 6 lines
arch/loongarch/kernel/machine_kexec_file.c +6 -0
+
+		/* Add the initrd=start,size parameter to the command line */
+		cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
+	}
+
+	if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {

It's too later to check for overflowing here, where the data after modified_cmdline may already be overwritten.

Quoted 3 lines

At this point, we append the original command line to modified_cmdline, so it is appropriate to determine whether the command line length exceeds the limit.

Thanks, I misunderstood the code logic: before cmdline_add_initrd appends new arguments, modified_cmdline is empty instead of containing a copy of cmdline, so this is fine. Sorry for the noise.

Best regards,
Yao Zi

#25 lore raw

PATCH 4/6 LoongArch/kexec_file: Add crash dump support

In reply to Youling Tang

From: Youling Tang <[email protected]>

Enabling crash dump (kdump) includes:
- prepare contents of ELF header of a core dump file, /proc/vmcore, using crash_prepare_elf64_headers().
- add "elfcorehdr=size@start" to command line.

---
 arch/loongarch/kernel/machine_kexec_file.c | 93 ++++++++++++++++++++++
 1 file changed, 93 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +93 -0
index e1240644f529..06def654cc09 100644
@@ -34,6 +34,63 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	return kexec_image_post_load_cleanup_default(image);
 }
 
+#ifdef CONFIG_CRASH_DUMP
+
+static int prepare_elf_headers(void **addr, unsigned long *sz)
+{
+	struct crash_mem *cmem;
+	unsigned int nr_ranges;
+	int ret;
+	u64 i;
+	phys_addr_t start, end;
+
+	nr_ranges = 2; /* for exclusion of crashkernel region */
+	for_each_mem_range(i, &start, &end)
+		nr_ranges++;
+
+	cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
+	if (!cmem)
+		return -ENOMEM;
+
+	cmem->max_nr_ranges = nr_ranges;
+	cmem->nr_ranges = 0;
+	for_each_mem_range(i, &start, &end) {
+		cmem->ranges[cmem->nr_ranges].start = start;
+		cmem->ranges[cmem->nr_ranges].end = end - 1;
+		cmem->nr_ranges++;
+	}
+
+	/* Exclude crashkernel region */
+	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+	if (ret)
+		goto out;
+
+	if (crashk_low_res.end) {
+		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		if (ret)
+			goto out;
+	}
+
+	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
+
+out:
+	kfree(cmem);
+	return ret;
+}
+
+/* Adds the "elfcorehdr=size@start" command line parameter to command line. */
+static void cmdline_add_elfcorehdr(struct kimage *image, unsigned long *cmdline_tmplen,
+				char *modified_cmdline, unsigned long elfcorehdr_sz)
+{
+	int elfcorehdr_strlen = 0;
+
+	elfcorehdr_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "elfcorehdr=0x%lx@0x%lx ",
+		elfcorehdr_sz, image->elf_load_addr);
+	*cmdline_tmplen += elfcorehdr_strlen;
+}
+
+#endif
+
 /* Adds the "initrd=start,size" command line parameter to command line. */
 static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
 				char *modified_cmdline, unsigned long initrd)
@@ -75,6 +132,42 @@ int load_other_segments(struct kimage *image,
 	/* Ensure it's nul terminated */
 	modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
 
+#ifdef CONFIG_CRASH_DUMP
+	/* load elf core header */
+	void *headers;
+	unsigned long headers_sz;
+	if (image->type == KEXEC_TYPE_CRASH) {
+		ret = prepare_elf_headers(&headers, &headers_sz);
+		if (ret) {
+			pr_err("Preparing elf core header failed\n");
+			goto out_err;
+		}
+
+		kbuf.buffer = headers;
+		kbuf.bufsz = headers_sz;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = headers_sz;
+		kbuf.buf_align = SZ_64K; /* largest supported page size */
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = true;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret) {
+			vfree(headers);
+			goto out_err;
+		}
+		image->elf_headers = headers;
+		image->elf_load_addr = kbuf.mem;
+		image->elf_headers_sz = headers_sz;
+
+		kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			      image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
+
+		/* Add the elfcorehdr=size@start parameter to the command line */
+		cmdline_add_elfcorehdr(image, &cmdline_tmplen, modified_cmdline, headers_sz);
+	}
+#endif
+
 	/* load initrd */
 	if (initrd) {
 		kbuf.buffer = initrd;
Signature · 1 line
2.34.1
#26 lore raw

PATCH 5/6 LoongArch/kexec_file: Add "mem" parameter to limit memory usage of kdump kernel

In reply to Youling Tang

From: Youling Tang <[email protected]>

Add the "mem=size@start" parameter to the cmdline and pass it to the capture kernel. Limit the runtime memory area for capturing the kernel to avoid disrupting the production kernel site.

---
 arch/loongarch/kernel/machine_kexec_file.c | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
arch/loongarch/kernel/machine_kexec_file.c +24 -0
index 06def654cc09..7da88c80cace 100644
@@ -89,6 +89,26 @@ static void cmdline_add_elfcorehdr(struct kimage *image, unsigned long *cmdline_
 	*cmdline_tmplen += elfcorehdr_strlen;
 }
 
+/*
+ * Adds the "mem=size@start" command line parameter to command line, indicating the
+ * memory region the new kernel can use to boot into.
+ */
+static void cmdline_add_mem(struct kimage *image, unsigned long *cmdline_tmplen,
+				char *modified_cmdline)
+{
+	int mem_strlen = 0;
+
+	mem_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "mem=0x%llx@0x%llx ",
+		crashk_res.end - crashk_res.start + 1, crashk_res.start);
+	*cmdline_tmplen += mem_strlen;
+
+	if (crashk_low_res.end) {
+		mem_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "mem=0x%llx@0x%llx ",
+			crashk_low_res.end - crashk_low_res.start + 1, crashk_low_res.start);
+		*cmdline_tmplen += mem_strlen;
+	}
+}
+
 #endif
 
 /* Adds the "initrd=start,size" command line parameter to command line. */
@@ -136,6 +156,7 @@ int load_other_segments(struct kimage *image,
 	/* load elf core header */
 	void *headers;
 	unsigned long headers_sz;
+
 	if (image->type == KEXEC_TYPE_CRASH) {
 		ret = prepare_elf_headers(&headers, &headers_sz);
 		if (ret) {
@@ -165,6 +186,9 @@ int load_other_segments(struct kimage *image,
 
 		/* Add the elfcorehdr=size@start parameter to the command line */
 		cmdline_add_elfcorehdr(image, &cmdline_tmplen, modified_cmdline, headers_sz);
+
+		/* Add the mem=size@start parameter to the command line */
+		cmdline_add_mem(image, &cmdline_tmplen, modified_cmdline);
 	}
 #endif
 
Signature · 1 line
2.34.1
#27 lore raw

PATCH 6/6 LoongArch: Enable CONFIG_KEXEC_FILE

In reply to Youling Tang

From: Youling Tang <[email protected]>

This patch enables config KEXEC_FILE by default in the loongson3_defconfig, so that user-space tools like kexec-tools can use the same as the default interface for kexec/kdump on LoongArch.

---
 arch/loongarch/configs/loongson3_defconfig | 1 +
 1 file changed, 1 insertion(+)
arch/loongarch/configs/loongson3_defconfig +1 -0
index 34eaee0384c9..6cfea2f37cc0 100644
@@ -45,6 +45,7 @@ CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_PERF_EVENTS=y
 CONFIG_KEXEC=y
+CONFIG_KEXEC_FILE=y
 CONFIG_CRASH_DUMP=y
 CONFIG_LOONGARCH=y
 CONFIG_64BIT=y
Signature · 1 line
2.34.1
#28 lore raw
In reply to Youling Tang

Hi Youling,

Quoted 19 lines · Youling Tang

From: Youling Tang <[email protected]>

This patchset implement kexec_file_load() support on LoongArch.

This patch series enables us to load the LoongArch vmlinuz.efi or vmlinux.efi by specifying its file decriptor, instead of user-filled buffer via kexec_load() syscall.

To use kexec_file_load() system call, instead of kexec_load(), at kexec command, '-s' options must be specified. kexec-tools needs to apply the corresponding patches. These patches can be found in repository [1] and will be submitted to the kexec-tools community later.

The basic usage of kexec_file is:
1) Load second kernel image:

 # kexec -s -l vmlinuz.efi --initrd=initrd.img --reuse-cmdline

2) Startup second kernel:

Quoted 9 lines
 # kexec -e

For kdump:
1) Load capture kernel image:

 # kexec -s -p vmlinuz.efi --initrd=initrd.img --reuse-cmdline

2) Do something to crash, like:

 # echo c > /proc/sysrq-trigger

I am new to this feature but I am interested to test this feature, How do I get the second kernel or capture image vmlinux.efi and initrd.img, do I need to build them separately and how?

Quoted 29 lines

Link:
[1] https://github.com/tangyouling/kexec-tools/commits/main/

Youling Tang (6):
LoongArch: Add struct loongarch_image_header for kernel image
LoongArch: Add kexec_file support
LoongArch/kexec_file: Add initrd loading LoongArch/kexec_file: Add crash dump support LoongArch/kexec_file: Add "mem" parameter to limit memory usage of
kdump kernel
LoongArch: Enable CONFIG_KEXEC_FILE

 arch/loongarch/Kconfig                     |   8 +
 arch/loongarch/configs/loongson3_defconfig |   1 +
 arch/loongarch/include/asm/image.h         |  58 +++++
 arch/loongarch/include/asm/kexec.h         |  12 ++
 arch/loongarch/kernel/Makefile             |   1 +
 arch/loongarch/kernel/kexec_image.c        | 112 ++++++++++
 arch/loongarch/kernel/machine_kexec.c      |  33 ++-
 arch/loongarch/kernel/machine_kexec_file.c | 234 +++++++++++++++++++++
 8 files changed, 448 insertions(+), 11 deletions(-)
 create mode 100644 arch/loongarch/include/asm/image.h
 create mode 100644 arch/loongarch/kernel/kexec_image.c
 create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

--
2.34.1

#29 lore raw

Hi, Vincent

Quoted 27 lines · Vincent Li

Hi Youling,

Quoted 24 lines · Youling Tang

From: Youling Tang <[email protected]>

This patchset implement kexec_file_load() support on LoongArch.

This patch series enables us to load the LoongArch vmlinuz.efi or vmlinux.efi by specifying its file decriptor, instead of user-filled buffer via kexec_load() syscall.

To use kexec_file_load() system call, instead of kexec_load(), at kexec command, '-s' options must be specified. kexec-tools needs to apply the corresponding patches. These patches can be found in repository [1] and will be submitted to the kexec-tools community later.

The basic usage of kexec_file is:
1) Load second kernel image:

  # kexec -s -l vmlinuz.efi --initrd=initrd.img --reuse-cmdline

2) Startup second kernel:

  # kexec -e

For kdump:
1) Load capture kernel image:

  # kexec -s -p vmlinuz.efi --initrd=initrd.img --reuse-cmdline
Quoted 6 lines
Quoted 3 lines

2) Do something to crash, like:

  # echo c > /proc/sysrq-trigger

I am new to this feature but I am interested to test this feature, How do I get the second kernel or capture image vmlinux.efi and initrd.img, do I need to build them separately and how?

There is no need to build separately. The kernel images and initrd of the first kernel and the second kernel can be the same (because LoongArch is a PIE kernel when RELOCATABLE is enabled).

Thanks,
Youling.

Quoted 30 lines
Quoted 30 lines

Link:
[1] https://github.com/tangyouling/kexec-tools/commits/main/

Youling Tang (6):
LoongArch: Add struct loongarch_image_header for kernel image
LoongArch: Add kexec_file support
LoongArch/kexec_file: Add initrd loading LoongArch/kexec_file: Add crash dump support LoongArch/kexec_file: Add "mem" parameter to limit memory usage of
kdump kernel
LoongArch: Enable CONFIG_KEXEC_FILE

  arch/loongarch/Kconfig                     |   8 +
  arch/loongarch/configs/loongson3_defconfig |   1 +
  arch/loongarch/include/asm/image.h         |  58 +++++
  arch/loongarch/include/asm/kexec.h         |  12 ++
  arch/loongarch/kernel/Makefile             |   1 +
  arch/loongarch/kernel/kexec_image.c        | 112 ++++++++++
  arch/loongarch/kernel/machine_kexec.c      |  33 ++-
  arch/loongarch/kernel/machine_kexec_file.c | 234 +++++++++++++++++++++
  8 files changed, 448 insertions(+), 11 deletions(-)

create mode 100644 arch/loongarch/include/asm/image.h create mode 100644 arch/loongarch/kernel/kexec_image.c create mode 100644 arch/loongarch/kernel/machine_kexec_file.c

--
2.34.1