[PATCH v7 14/15] LoongArch: kexec_file: Use kexec_load_other_segments() to simplify code

From: Jinjie Ruan

Date: Mon Oct 26 2026 - 03:56:06 EST


Replace the local copy with the common helper. The retry loop stays
and the command line is built in the setup hook.

Cc: Huacai Chen <chenhuacai@xxxxxxxxxx>
Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: Baoquan He <baoquan.he@xxxxxxxxx>
Cc: Mike Rapoport <rppt@xxxxxxxxxx>
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
arch/loongarch/include/asm/kexec.h | 4 -
arch/loongarch/kernel/kexec_efi.c | 12 ++-
arch/loongarch/kernel/kexec_elf.c | 11 ++-
arch/loongarch/kernel/machine_kexec_file.c | 94 ++++------------------
4 files changed, 32 insertions(+), 89 deletions(-)

diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
index 6be136e9f0a0..e58cf7e282a9 100644
--- a/arch/loongarch/include/asm/kexec.h
+++ b/arch/loongarch/include/asm/kexec.h
@@ -49,10 +49,6 @@ extern const struct kexec_file_ops kexec_elf_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,
diff --git a/arch/loongarch/kernel/kexec_efi.c b/arch/loongarch/kernel/kexec_efi.c
index d42711b895a2..1362e51e9171 100644
--- a/arch/loongarch/kernel/kexec_efi.c
+++ b/arch/loongarch/kernel/kexec_efi.c
@@ -44,6 +44,12 @@ static void *efi_kexec_load(struct kimage *image,
unsigned long text_offset, kernel_segment_number;
struct kexec_buf kbuf = {};
struct kexec_segment *kernel_segment;
+ struct kexec_load_params params = {
+ .initrd = initrd,
+ .initrd_len = initrd_len,
+ .cmdline = cmdline,
+ .cmdline_len = cmdline_len,
+ };
struct loongarch_image_header *h;

h = (struct loongarch_image_header *)kernel;
@@ -76,9 +82,9 @@ static void *efi_kexec_load(struct kimage *image,
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);
+ params.kernel_load_addr = kernel_segment->mem;
+ params.kernel_size = kernel_segment->memsz;
+ ret = kexec_load_other_segments(image, &params, false);
if (!ret)
break;

diff --git a/arch/loongarch/kernel/kexec_elf.c b/arch/loongarch/kernel/kexec_elf.c
index 1b6b64744c7f..47272cfa990d 100644
--- a/arch/loongarch/kernel/kexec_elf.c
+++ b/arch/loongarch/kernel/kexec_elf.c
@@ -62,6 +62,12 @@ static void *elf_kexec_load(struct kimage *image,
struct kexec_buf kbuf = {};
struct kexec_elf_info elf_info;
struct kexec_segment *kernel_segment;
+ struct kexec_load_params params = {
+ .initrd = initrd,
+ .initrd_len = initrd_len,
+ .cmdline = cmdline,
+ .cmdline_len = cmdline_len,
+ };

ret = kexec_build_elf_info(kernel, kernel_len, &ehdr, &elf_info);
if (ret < 0)
@@ -83,8 +89,9 @@ static void *elf_kexec_load(struct kimage *image,

/* 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);
+ params.kernel_load_addr = kernel_segment->mem;
+ params.kernel_size = kernel_segment->memsz;
+ ret = kexec_load_other_segments(image, &params, false);
if (ret < 0)
goto out;

diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
index c0a799f0d240..d65cb40ef047 100644
--- a/arch/loongarch/kernel/machine_kexec_file.c
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -110,112 +110,46 @@ static void cmdline_add_elfcorehdr(struct kimage *image, unsigned long *cmdline_

#endif

-/*
- * Try to add the initrd to the image. If it is not possible to find valid
- * locations, this function will undo changes to the image and return non zero.
- */
-int load_other_segments(struct kimage *image,
- unsigned long kernel_load_addr, unsigned long kernel_size,
- char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len)
+int arch_kexec_setup_other_segments(struct kimage *image,
+ struct kexec_load_params *params,
+ unsigned long initrd_load_addr)
{
- int ret = 0;
unsigned long cmdline_tmplen = 0;
- unsigned long initrd_load_addr = 0;
- unsigned long orig_segments = image->nr_segments;
- char *modified_cmdline = NULL;
- struct kexec_buf kbuf = {
- .image = image,
- /* Don't allocate anything below the kernel */
- .buf_min = kernel_load_addr + kernel_size,
- .buf_max = ULONG_MAX,
- };
+ unsigned long cmdline_len = params->cmdline_len;
+ const char *cmdline = params->cmdline;
+ char *modified_cmdline;

modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
if (!modified_cmdline)
- return -EINVAL;
+ return -ENOMEM;

cmdline_add_loader(&cmdline_tmplen, modified_cmdline);
/* Ensure it's null terminated */
modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';

#ifdef CONFIG_CRASH_DUMP
- /* Load elf core header */
if (image->type == KEXEC_TYPE_CRASH) {
- ret = crash_prepare_headers(true, &kbuf.buffer, &kbuf.bufsz, NULL);
- if (ret < 0) {
- pr_err("Preparing elf core header failed\n");
- goto out_err;
- }
-
- if (unlikely(image->elf_headers))
- vfree(image->elf_headers);
-
- image->elf_headers = kbuf.buffer;
- image->elf_headers_sz = kbuf.bufsz;
-
- kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
- kbuf.memsz = kbuf.bufsz;
- kbuf.buf_align = SZ_64K; /* largest supported page size */
- kbuf.top_down = true;
-
- ret = kexec_add_buffer(&kbuf);
- if (ret < 0)
- goto out_err;
-
- image->elf_load_addr = kbuf.mem;
-
- kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
- image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
-
/* Add the mem=size@start parameter to the command line */
cmdline_add_mem(&cmdline_tmplen, modified_cmdline);

/* Add the elfcorehdr=size@start parameter to the command line */
- cmdline_add_elfcorehdr(image, &cmdline_tmplen, modified_cmdline, kbuf.bufsz);
+ cmdline_add_elfcorehdr(image, &cmdline_tmplen, modified_cmdline,
+ image->elf_headers_sz);
}
#endif

- /* Load initrd */
- if (initrd) {
- kbuf.buffer = initrd;
- kbuf.bufsz = initrd_len;
- kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
- kbuf.memsz = initrd_len;
- kbuf.buf_align = 0;
- /* within 1GB-aligned window of up to 32GB in size */
- kbuf.buf_max = round_down(kernel_load_addr, SZ_1G) + (unsigned long)SZ_1G * 32;
- kbuf.top_down = false;
-
- ret = kexec_add_buffer(&kbuf);
- if (ret < 0)
- goto out_err;
- initrd_load_addr = kbuf.mem;
-
- kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
- initrd_load_addr, kbuf.bufsz, kbuf.memsz);
-
- /* Add the initrd=start,size parameter to the command line */
+ /* Add the initrd=start,size parameter to the command line */
+ if (initrd_load_addr)
cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
- }

if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
pr_err("Appending command line exceeds COMMAND_LINE_SIZE\n");
- ret = -EINVAL;
- goto out_err;
+ kfree(modified_cmdline);
+ return -EINVAL;
}

memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
- cmdline = modified_cmdline;
- image->arch.cmdline_ptr = (unsigned long)cmdline;
+ image->arch.cmdline_ptr = (unsigned long)modified_cmdline;

return 0;
-
-out_err:
- while (image->nr_segments > orig_segments) {
- kexec_free_segment_cma(image, image->nr_segments - 1);
- image->nr_segments--;
- }
-
- kfree(modified_cmdline);
- return ret;
}
--
2.34.1