[PATCH 2/6] LoongArch: Add kexec_file support

Youling Tang posted 6 patches 1 month, 3 weeks ago
There is a newer version of this series
[PATCH 2/6] LoongArch: Add kexec_file support
Posted by Youling Tang 1 month, 3 weeks ago
From: Youling Tang <tangyouling@kylinos.cn>

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.

Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
---
 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

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index f0abc38c40ac..fd50c83f7827 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -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
 
diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
index 1f090736e71d..829e1ecb1f5d 100644
--- a/arch/loongarch/include/asm/image.h
+++ b/arch/loongarch/include/asm/image.h
@@ -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 */
diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
index cf95cd3eb2de..3ef8517a3670 100644
--- a/arch/loongarch/include/asm/kexec.h
+++ b/arch/loongarch/include/asm/kexec.h
@@ -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,
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 6f5a4574a911..bd9405ee3888 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -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
diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
new file mode 100644
index 000000000000..fdd1845b4e2e
--- /dev/null
+++ b/arch/loongarch/kernel/kexec_image.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader for LoongArch
+
+ * Author: Youling Tang <tangyouling@kylinos.cn>
+ * 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,
+};
diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
index f9381800e291..008f43e26120 100644
--- a/arch/loongarch/kernel/machine_kexec.c
+++ b/arch/loongarch/kernel/machine_kexec.c
@@ -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");
diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
new file mode 100644
index 000000000000..bc91ae0afa4c
--- /dev/null
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for LoongArch
+ *
+ * Author: Youling Tang <tangyouling@kylinos.cn>
+ * 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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by kernel test robot 1 month, 2 weeks ago
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/202508161329.M5Axl1XA-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 15.1.0
reproduce: (https://download.01.org/0day-ci/archive/20250816/202508161329.M5Axl1XA-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508161329.M5Axl1XA-lkp@intel.com/

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	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Yao Zi 1 month, 3 weeks ago
On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
> From: Youling Tang <tangyouling@kylinos.cn>
> 
> 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.
> 
> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> ---
>  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

...

> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
> index 1f090736e71d..829e1ecb1f5d 100644
> --- a/arch/loongarch/include/asm/image.h
> +++ b/arch/loongarch/include/asm/image.h
> @@ -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.

> +
> +/**
> + * 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]);

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".

> +}
> +
>  #endif /* __ASSEMBLY__ */
>  #endif /* __ASM_IMAGE_H */

...

> diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
> new file mode 100644
> index 000000000000..fdd1845b4e2e
> --- /dev/null
> +++ b/arch/loongarch/kernel/kexec_image.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kexec image loader for LoongArch
> +
> + * Author: Youling Tang <tangyouling@kylinos.cn>
> + * 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);

Parentheses around "kernel_buf" are unnecessary.

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

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

> +		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;

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.

> +	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;

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...

> +	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,
> +};
> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> index f9381800e291..008f43e26120 100644
> --- a/arch/loongarch/kernel/machine_kexec.c
> +++ b/arch/loongarch/kernel/machine_kexec.c
> @@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)

...

> -	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);

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).

>  	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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Youling Tang 1 month, 3 weeks ago
Hi, Yao
On 2025/8/12 01:06, Yao Zi wrote:
> On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
>> From: Youling Tang <tangyouling@kylinos.cn>
>>
>> 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.
>>
>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>> ---
>>   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
> ...
>
>> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
>> index 1f090736e71d..829e1ecb1f5d 100644
>> --- a/arch/loongarch/include/asm/image.h
>> +++ b/arch/loongarch/include/asm/image.h
>> @@ -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.
>
>> +
>> +/**
>> + * 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]);
> 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".
>
>> +}
>> +
>>   #endif /* __ASSEMBLY__ */
>>   #endif /* __ASM_IMAGE_H */
> ...
>
>> diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
>> new file mode 100644
>> index 000000000000..fdd1845b4e2e
>> --- /dev/null
>> +++ b/arch/loongarch/kernel/kexec_image.c
>> @@ -0,0 +1,112 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Kexec image loader for LoongArch
>> +
>> + * Author: Youling Tang <tangyouling@kylinos.cn>
>> + * 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);
> Parentheses around "kernel_buf" are unnecessary.
It will be removed.
>
>> +	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.
>
>> +		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;
> 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.
>
>> +	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;
> 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...
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")
>> +	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,
>> +};
>> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
>> index f9381800e291..008f43e26120 100644
>> --- a/arch/loongarch/kernel/machine_kexec.c
>> +++ b/arch/loongarch/kernel/machine_kexec.c
>> @@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
> ...
>
>> -	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);
> 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.
>
> 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).
>
>>   	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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Youling Tang 1 month, 3 weeks ago
On 2025/8/12 14:15, Youling Tang wrote:
> Hi, Yao
> On 2025/8/12 01:06, Yao Zi wrote:
>> On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>
>>> 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.
>>>
>>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>>> ---
>>>   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
>> ...
>>
>>> diff --git a/arch/loongarch/include/asm/image.h 
>>> b/arch/loongarch/include/asm/image.h
>>> index 1f090736e71d..829e1ecb1f5d 100644
>>> --- a/arch/loongarch/include/asm/image.h
>>> +++ b/arch/loongarch/include/asm/image.h
>>> @@ -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.
>>
>>> +
>>> +/**
>>> + * 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]);
>> 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".
>>
>>> +}
>>> +
>>>   #endif /* __ASSEMBLY__ */
>>>   #endif /* __ASM_IMAGE_H */
>> ...
>>
>>> diff --git a/arch/loongarch/kernel/kexec_image.c 
>>> b/arch/loongarch/kernel/kexec_image.c
>>> new file mode 100644
>>> index 000000000000..fdd1845b4e2e
>>> --- /dev/null
>>> +++ b/arch/loongarch/kernel/kexec_image.c
>>> @@ -0,0 +1,112 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Kexec image loader for LoongArch
>>> +
>>> + * Author: Youling Tang <tangyouling@kylinos.cn>
>>> + * 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);
>> Parentheses around "kernel_buf" are unnecessary.
> It will be removed.
>>
>>> +    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.
>>
>>> +        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;
>> 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.
>>
>>> +    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;
>> 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...
> 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.
> After enabling the relocation, LoongArch is the PIE kernel. For
> more details, please refer to commit d8da19fbdedd ("LoongArch:
> Add support for kernel relocation")
>>> +    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,
>>> +};
>>> diff --git a/arch/loongarch/kernel/machine_kexec.c 
>>> b/arch/loongarch/kernel/machine_kexec.c
>>> index f9381800e291..008f43e26120 100644
>>> --- a/arch/loongarch/kernel/machine_kexec.c
>>> +++ b/arch/loongarch/kernel/machine_kexec.c
>>> @@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
>> ...
>>
>>> -    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);
>> 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.
>>
>> 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).
>>
>>>       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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Yao Zi 1 month, 3 weeks ago
On Tue, Aug 12, 2025 at 03:06:23PM +0800, Youling Tang wrote:
> On 2025/8/12 14:15, Youling Tang wrote:
> > Hi, Yao
> > On 2025/8/12 01:06, Yao Zi wrote:
> > > On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
> > > > From: Youling Tang <tangyouling@kylinos.cn>
> > > > 
> > > > 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.
> > > > 
> > > > Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> > > > ---
> > > >   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

...

> > > > diff --git a/arch/loongarch/kernel/kexec_image.c
> > > > b/arch/loongarch/kernel/kexec_image.c
> > > > new file mode 100644
> > > > index 000000000000..fdd1845b4e2e
> > > > --- /dev/null
> > > > +++ b/arch/loongarch/kernel/kexec_image.c

...

> > > > +    /*
> > > > +     * 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;
> > > 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...
> > 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?

> 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.

> Youling.
> > 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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Youling Tang 1 month, 3 weeks ago
Hi, Yao
On 2025/8/12 17:43, Yao Zi wrote:
> On Tue, Aug 12, 2025 at 03:06:23PM +0800, Youling Tang wrote:
>> On 2025/8/12 14:15, Youling Tang wrote:
>>> Hi, Yao
>>> On 2025/8/12 01:06, Yao Zi wrote:
>>>> On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
>>>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>>>
>>>>> 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.
>>>>>
>>>>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>>>>> ---
>>>>>    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
> ...
>
>>>>> diff --git a/arch/loongarch/kernel/kexec_image.c
>>>>> b/arch/loongarch/kernel/kexec_image.c
>>>>> new file mode 100644
>>>>> index 000000000000..fdd1845b4e2e
>>>>> --- /dev/null
>>>>> +++ b/arch/loongarch/kernel/kexec_image.c
> ...
>
>>>>> +    /*
>>>>> +     * 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;
>>>> 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...
>>> 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?
No.
>> 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.
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.
>> Youling.
>>> 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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Yao Zi 1 month, 3 weeks ago
On Wed, Aug 13, 2025 at 10:18:12AM +0800, Youling Tang wrote:
> Hi, Yao
> On 2025/8/12 17:43, Yao Zi wrote:
> > On Tue, Aug 12, 2025 at 03:06:23PM +0800, Youling Tang wrote:
> > > On 2025/8/12 14:15, Youling Tang wrote:
> > > > Hi, Yao
> > > > On 2025/8/12 01:06, Yao Zi wrote:
> > > > > On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
> > > > > > From: Youling Tang <tangyouling@kylinos.cn>
> > > > > > 
> > > > > > 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.
> > > > > > 
> > > > > > Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> > > > > > ---
> > > > > >    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
> > ...
> > 
> > > > > > diff --git a/arch/loongarch/kernel/kexec_image.c
> > > > > > b/arch/loongarch/kernel/kexec_image.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..fdd1845b4e2e
> > > > > > --- /dev/null
> > > > > > +++ b/arch/loongarch/kernel/kexec_image.c
> > ...
> > 
> > > > > > +    /*
> > > > > > +     * 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;
> > > > > 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...
> > > > 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?
> No.
> > > 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.
> 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.

> 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.

> 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.

> Thanks,
> Youling.
> > > Youling.
> > > > 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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Huacai Chen 1 month, 3 weeks ago
On Tue, Aug 12, 2025 at 1:09 AM Yao Zi <ziyao@disroot.org> wrote:
>
> On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
> > From: Youling Tang <tangyouling@kylinos.cn>
> >
> > 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.
> >
> > Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> > ---
> >  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
>
> ...
>
> > diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
> > index 1f090736e71d..829e1ecb1f5d 100644
> > --- a/arch/loongarch/include/asm/image.h
> > +++ b/arch/loongarch/include/asm/image.h
> > @@ -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.
>
> > +
> > +/**
> > + * 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]);
>
> 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".
>
> > +}
> > +
> >  #endif /* __ASSEMBLY__ */
> >  #endif /* __ASM_IMAGE_H */
>
> ...
>
> > diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
> > new file mode 100644
> > index 000000000000..fdd1845b4e2e
> > --- /dev/null
> > +++ b/arch/loongarch/kernel/kexec_image.c
> > @@ -0,0 +1,112 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Kexec image loader for LoongArch
> > +
> > + * Author: Youling Tang <tangyouling@kylinos.cn>
> > + * 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);
>
> Parentheses around "kernel_buf" are unnecessary.
>
> > +     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.

>
> > +             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;
>
> 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.
>
> > +     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;
>
> 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...
>
> > +     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,
> > +};
> > diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> > index f9381800e291..008f43e26120 100644
> > --- a/arch/loongarch/kernel/machine_kexec.c
> > +++ b/arch/loongarch/kernel/machine_kexec.c
> > @@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
>
> ...
>
> > -     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);
>
> 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).
Separating is not necessary from my point of view, indeed I suggest to
squash patches in this series.

Huacai

>
> >       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
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Yao Zi 1 month, 3 weeks ago
On Tue, Aug 12, 2025 at 10:39:59AM +0800, Huacai Chen wrote:
> On Tue, Aug 12, 2025 at 1:09 AM Yao Zi <ziyao@disroot.org> wrote:
> >
> > On Mon, Aug 11, 2025 at 05:26:55PM +0800, Youling Tang wrote:
> > > From: Youling Tang <tangyouling@kylinos.cn>
> > >
> > > 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.
> > >
> > > Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> > > ---
> > >  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
> >
> > > diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
> > > new file mode 100644
> > > index 000000000000..fdd1845b4e2e
> > > --- /dev/null
> > > +++ b/arch/loongarch/kernel/kexec_image.c
> > > @@ -0,0 +1,112 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Kexec image loader for LoongArch
> > > +
> > > + * Author: Youling Tang <tangyouling@kylinos.cn>
> > > + * 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);
> >
> > Parentheses around "kernel_buf" are unnecessary.
> >
> > > +     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.

> >
> > > +             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;
> > > +}

...

> > > diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> > > index f9381800e291..008f43e26120 100644
> > > --- a/arch/loongarch/kernel/machine_kexec.c
> > > +++ b/arch/loongarch/kernel/machine_kexec.c
> > > @@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
> >
> > ...
> >
> > > -     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);
> >
> > 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).
> 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.

> Huacai

Best regards,
Yao Zi

> >
> > >       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
> 
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Huacai Chen 1 month, 3 weeks ago
Hi, Youling,

On Mon, Aug 11, 2025 at 5:28 PM Youling Tang <youling.tang@linux.dev> wrote:
>
> From: Youling Tang <tangyouling@kylinos.cn>
>
> 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.
>
> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> ---
>  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
>
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index f0abc38c40ac..fd50c83f7827 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -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
>
> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
> index 1f090736e71d..829e1ecb1f5d 100644
> --- a/arch/loongarch/include/asm/image.h
> +++ b/arch/loongarch/include/asm/image.h
> @@ -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 */
> diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
> index cf95cd3eb2de..3ef8517a3670 100644
> --- a/arch/loongarch/include/asm/kexec.h
> +++ b/arch/loongarch/include/asm/kexec.h
> @@ -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);
I think the RISC-V naming "load_extra_segments" is better.

> +#endif
> +
>  typedef void (*do_kexec_t)(unsigned long efi_boot,
>                            unsigned long cmdline_ptr,
>                            unsigned long systable_ptr,
> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
> index 6f5a4574a911..bd9405ee3888 100644
> --- a/arch/loongarch/kernel/Makefile
> +++ b/arch/loongarch/kernel/Makefile
> @@ -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

>  obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
>
>  obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
> diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
> new file mode 100644
> index 000000000000..fdd1845b4e2e
> --- /dev/null
> +++ b/arch/loongarch/kernel/kexec_image.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kexec image loader for LoongArch
> +
> + * Author: Youling Tang <tangyouling@kylinos.cn>
> + * 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,
> +};
> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> index f9381800e291..008f43e26120 100644
> --- a/arch/loongarch/kernel/machine_kexec.c
> +++ b/arch/loongarch/kernel/machine_kexec.c
> @@ -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");
> diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
> new file mode 100644
> index 000000000000..bc91ae0afa4c
> --- /dev/null
> +++ b/arch/loongarch/kernel/machine_kexec_file.c
> @@ -0,0 +1,46 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * kexec_file for LoongArch
> + *
> + * Author: Youling Tang <tangyouling@kylinos.cn>
> + * 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
>
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Youling Tang 1 month, 3 weeks ago
Hi, Huacai
On 2025/8/11 22:07, Huacai Chen wrote:
> Hi, Youling,
>
> On Mon, Aug 11, 2025 at 5:28 PM Youling Tang <youling.tang@linux.dev> wrote:
>> From: Youling Tang <tangyouling@kylinos.cn>
>>
>> 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.
>>
>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>> ---
>>   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
>>
>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>> index f0abc38c40ac..fd50c83f7827 100644
>> --- a/arch/loongarch/Kconfig
>> +++ b/arch/loongarch/Kconfig
>> @@ -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
>>
>> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
>> index 1f090736e71d..829e1ecb1f5d 100644
>> --- a/arch/loongarch/include/asm/image.h
>> +++ b/arch/loongarch/include/asm/image.h
>> @@ -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 */
>> diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
>> index cf95cd3eb2de..3ef8517a3670 100644
>> --- a/arch/loongarch/include/asm/kexec.h
>> +++ b/arch/loongarch/include/asm/kexec.h
>> @@ -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);
> 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.
>
>> +#endif
>> +
>>   typedef void (*do_kexec_t)(unsigned long efi_boot,
>>                             unsigned long cmdline_ptr,
>>                             unsigned long systable_ptr,
>> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
>> index 6f5a4574a911..bd9405ee3888 100644
>> --- a/arch/loongarch/kernel/Makefile
>> +++ b/arch/loongarch/kernel/Makefile
>> @@ -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.
I hope it is separated and consistent with other architectures.
For instance, arm64 only supports one type.

Youling.
>
> Huacai
>
>>   obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
>>
>>   obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
>> diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
>> new file mode 100644
>> index 000000000000..fdd1845b4e2e
>> --- /dev/null
>> +++ b/arch/loongarch/kernel/kexec_image.c
>> @@ -0,0 +1,112 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Kexec image loader for LoongArch
>> +
>> + * Author: Youling Tang <tangyouling@kylinos.cn>
>> + * 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,
>> +};
>> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
>> index f9381800e291..008f43e26120 100644
>> --- a/arch/loongarch/kernel/machine_kexec.c
>> +++ b/arch/loongarch/kernel/machine_kexec.c
>> @@ -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");
>> diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
>> new file mode 100644
>> index 000000000000..bc91ae0afa4c
>> --- /dev/null
>> +++ b/arch/loongarch/kernel/machine_kexec_file.c
>> @@ -0,0 +1,46 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * kexec_file for LoongArch
>> + *
>> + * Author: Youling Tang <tangyouling@kylinos.cn>
>> + * 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
>>
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Huacai Chen 1 month, 3 weeks ago
On Tue, Aug 12, 2025 at 9:22 AM Youling Tang <youling.tang@linux.dev> wrote:
>
> Hi, Huacai
> On 2025/8/11 22:07, Huacai Chen wrote:
> > Hi, Youling,
> >
> > On Mon, Aug 11, 2025 at 5:28 PM Youling Tang <youling.tang@linux.dev> wrote:
> >> From: Youling Tang <tangyouling@kylinos.cn>
> >>
> >> 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.
> >>
> >> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
> >> ---
> >>   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
> >>
> >> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> >> index f0abc38c40ac..fd50c83f7827 100644
> >> --- a/arch/loongarch/Kconfig
> >> +++ b/arch/loongarch/Kconfig
> >> @@ -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
> >>
> >> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
> >> index 1f090736e71d..829e1ecb1f5d 100644
> >> --- a/arch/loongarch/include/asm/image.h
> >> +++ b/arch/loongarch/include/asm/image.h
> >> @@ -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 */
> >> diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
> >> index cf95cd3eb2de..3ef8517a3670 100644
> >> --- a/arch/loongarch/include/asm/kexec.h
> >> +++ b/arch/loongarch/include/asm/kexec.h
> >> @@ -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);
> > 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.
OK, then you can keep your original name.

> >
> >> +#endif
> >> +
> >>   typedef void (*do_kexec_t)(unsigned long efi_boot,
> >>                             unsigned long cmdline_ptr,
> >>                             unsigned long systable_ptr,
> >> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
> >> index 6f5a4574a911..bd9405ee3888 100644
> >> --- a/arch/loongarch/kernel/Makefile
> >> +++ b/arch/loongarch/kernel/Makefile
> >> @@ -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.
> 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

>
> Youling.
> >
> > Huacai
> >
> >>   obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
> >>
> >>   obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
> >> diff --git a/arch/loongarch/kernel/kexec_image.c b/arch/loongarch/kernel/kexec_image.c
> >> new file mode 100644
> >> index 000000000000..fdd1845b4e2e
> >> --- /dev/null
> >> +++ b/arch/loongarch/kernel/kexec_image.c
> >> @@ -0,0 +1,112 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Kexec image loader for LoongArch
> >> +
> >> + * Author: Youling Tang <tangyouling@kylinos.cn>
> >> + * 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,
> >> +};
> >> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> >> index f9381800e291..008f43e26120 100644
> >> --- a/arch/loongarch/kernel/machine_kexec.c
> >> +++ b/arch/loongarch/kernel/machine_kexec.c
> >> @@ -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");
> >> diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
> >> new file mode 100644
> >> index 000000000000..bc91ae0afa4c
> >> --- /dev/null
> >> +++ b/arch/loongarch/kernel/machine_kexec_file.c
> >> @@ -0,0 +1,46 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * kexec_file for LoongArch
> >> + *
> >> + * Author: Youling Tang <tangyouling@kylinos.cn>
> >> + * 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
> >>
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Yanteng Si 1 month, 3 weeks ago
在 8/12/25 9:21 AM, Youling Tang 写道:
> Hi, Huacai
> On 2025/8/11 22:07, Huacai Chen wrote:
>> Hi, Youling,
>>
>> On Mon, Aug 11, 2025 at 5:28 PM Youling Tang <youling.tang@linux.dev> wrote:
>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>
>>> 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.
>>>
>>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>>> ---
>>>   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
>>>
>>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>>> index f0abc38c40ac..fd50c83f7827 100644
>>> --- a/arch/loongarch/Kconfig
>>> +++ b/arch/loongarch/Kconfig
>>> @@ -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
>>>
>>> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
>>> index 1f090736e71d..829e1ecb1f5d 100644
>>> --- a/arch/loongarch/include/asm/image.h
>>> +++ b/arch/loongarch/include/asm/image.h
>>> @@ -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 */
>>> diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
>>> index cf95cd3eb2de..3ef8517a3670 100644
>>> --- a/arch/loongarch/include/asm/kexec.h
>>> +++ b/arch/loongarch/include/asm/kexec.h
>>> @@ -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);
>> 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.
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.


>>
>>> +#endif
>>> +
>>>   typedef void (*do_kexec_t)(unsigned long efi_boot,
>>>                             unsigned long cmdline_ptr,
>>>                             unsigned long systable_ptr,
>>> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
>>> index 6f5a4574a911..bd9405ee3888 100644
>>> --- a/arch/loongarch/kernel/Makefile
>>> +++ b/arch/loongarch/kernel/Makefile
>>> @@ -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.
> 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
>
> Youling.
>>
>> Huacai
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Youling Tang 1 month, 3 weeks ago
Hi, Yanteng
On 2025/8/12 09:53, Yanteng Si wrote:
> 在 8/12/25 9:21 AM, Youling Tang 写道:
>> Hi, Huacai
>> On 2025/8/11 22:07, Huacai Chen wrote:
>>> Hi, Youling,
>>>
>>> On Mon, Aug 11, 2025 at 5:28 PM Youling Tang 
>>> <youling.tang@linux.dev> wrote:
>>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>>
>>>> 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.
>>>>
>>>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>>>> ---
>>>>   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
>>>>
>>>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>>>> index f0abc38c40ac..fd50c83f7827 100644
>>>> --- a/arch/loongarch/Kconfig
>>>> +++ b/arch/loongarch/Kconfig
>>>> @@ -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
>>>>
>>>> diff --git a/arch/loongarch/include/asm/image.h 
>>>> b/arch/loongarch/include/asm/image.h
>>>> index 1f090736e71d..829e1ecb1f5d 100644
>>>> --- a/arch/loongarch/include/asm/image.h
>>>> +++ b/arch/loongarch/include/asm/image.h
>>>> @@ -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 */
>>>> diff --git a/arch/loongarch/include/asm/kexec.h 
>>>> b/arch/loongarch/include/asm/kexec.h
>>>> index cf95cd3eb2de..3ef8517a3670 100644
>>>> --- a/arch/loongarch/include/asm/kexec.h
>>>> +++ b/arch/loongarch/include/asm/kexec.h
>>>> @@ -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);
>>> 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.
> 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.
>
>
>>>
>>>> +#endif
>>>> +
>>>>   typedef void (*do_kexec_t)(unsigned long efi_boot,
>>>>                             unsigned long cmdline_ptr,
>>>>                             unsigned long systable_ptr,
>>>> diff --git a/arch/loongarch/kernel/Makefile 
>>>> b/arch/loongarch/kernel/Makefile
>>>> index 6f5a4574a911..bd9405ee3888 100644
>>>> --- a/arch/loongarch/kernel/Makefile
>>>> +++ b/arch/loongarch/kernel/Makefile
>>>> @@ -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.
>> 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.
>
>
> Thanks,
> Yanteng
>>
>> Youling.
>>>
>>> Huacai
Re: [PATCH 2/6] LoongArch: Add kexec_file support
Posted by Yanteng Si 1 month, 3 weeks ago
在 8/12/25 5:32 PM, Youling Tang 写道:
> Hi, Yanteng
> On 2025/8/12 09:53, Yanteng Si wrote:
>> 在 8/12/25 9:21 AM, Youling Tang 写道:
>>> Hi, Huacai
>>> On 2025/8/11 22:07, Huacai Chen wrote:
>>>> Hi, Youling,
>>>>
>>>> On Mon, Aug 11, 2025 at 5:28 PM Youling Tang <youling.tang@linux.dev> wrote:
>>>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>>>
>>>>> 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.
>>>>>
>>>>> Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
>>>>> ---
>>>>>   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
>>>>>
>>>>> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
>>>>> index f0abc38c40ac..fd50c83f7827 100644
>>>>> --- a/arch/loongarch/Kconfig
>>>>> +++ b/arch/loongarch/Kconfig
>>>>> @@ -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
>>>>>
>>>>> diff --git a/arch/loongarch/include/asm/image.h b/arch/loongarch/include/asm/image.h
>>>>> index 1f090736e71d..829e1ecb1f5d 100644
>>>>> --- a/arch/loongarch/include/asm/image.h
>>>>> +++ b/arch/loongarch/include/asm/image.h
>>>>> @@ -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 */
>>>>> diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
>>>>> index cf95cd3eb2de..3ef8517a3670 100644
>>>>> --- a/arch/loongarch/include/asm/kexec.h
>>>>> +++ b/arch/loongarch/include/asm/kexec.h
>>>>> @@ -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);
>>>> 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.
>> 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.
>>
>>
>>>>
>>>>> +#endif
>>>>> +
>>>>>   typedef void (*do_kexec_t)(unsigned long efi_boot,
>>>>>                             unsigned long cmdline_ptr,
>>>>>                             unsigned long systable_ptr,
>>>>> diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
>>>>> index 6f5a4574a911..bd9405ee3888 100644
>>>>> --- a/arch/loongarch/kernel/Makefile
>>>>> +++ b/arch/loongarch/kernel/Makefile
>>>>> @@ -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.
>>> 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

>
> Thanks,
> Youling.
>>
>>
>> Thanks,
>> Yanteng
>>>
>>> Youling.
>>>>
>>>> Huacai