[PATCH v8 02/11] kexec: Add helpers to load the elf core header, initrd and FDT
Jinjie Ruan
ruanjinjie at huawei.com
Thu Nov 12 05:34:09 PST 2026
x86, arm64, LoongArch, RISC-V and powerpc all build an elf core header,
load the initrd by hand before loading the kdump kernel, while arm64 and
RISC-V also duplicate the code that builds the device tree for the kexec
kernel
Add the following 4 helpers for reuse:
- kexec_prepare_elf_core_header() builds the header once per image and
returns the number of memory ranges, which x86 needs to reserve room
for the crash hotplug updates.
- kexec_add_elf_core_header() places the prepared header as a segment.
The caller provides the kexec_buf with its placement policy and the
size to reserve. On success it also records the segment index that
the crash hotplug code uses to find the header.
- kexec_add_initrd() places the initrd from the image with the placement
policy the caller put into the kexec_buf.
- kexec_add_fdt() builds the device tree for the kexec kernel, packs
it and places it with the kexec_buf the caller passes in.
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Baoquan He <baoquan.he at linux.dev>
Cc: Mike Rapoport <rppt at kernel.org>
Link: https://lore.kernel.org/all/179430504583.425130.15302016434972990362.b4-review@b4/
Suggested-by: Mike Rapoport <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
include/linux/kexec.h | 11 +++++
kernel/kexec_file.c | 104 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 115 insertions(+)
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index bac11e940e74..89cb47521d6d 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -258,6 +258,17 @@ int kexec_kernel_verify_pe_sig(const char *kernel, unsigned long kernel_len);
extern int kexec_add_buffer(struct kexec_buf *kbuf);
int kexec_locate_mem_hole(struct kexec_buf *kbuf);
+int kexec_add_initrd(struct kimage *image, struct kexec_buf *kbuf);
+#ifdef CONFIG_CRASH_DUMP
+int kexec_prepare_elf_core_header(struct kimage *image, bool need_kernel_map,
+ unsigned long *nr_ranges);
+int kexec_add_elf_core_header(struct kimage *image, struct kexec_buf *kbuf);
+#endif
+#if defined(CONFIG_OF) && defined(CONFIG_OF_FLATTREE)
+int kexec_add_fdt(struct kimage *image, struct kexec_buf *kbuf,
+ unsigned long initrd_load_addr, const char *cmdline,
+ void **fdt);
+#endif
#ifndef arch_kexec_apply_relocations_add
/*
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 1f128c6e6fa3..25c9bef639d2 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -14,7 +14,9 @@
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/kexec.h>
+#include <linux/libfdt.h>
#include <linux/memblock.h>
+#include <linux/of.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/fs.h>
@@ -109,6 +111,108 @@ static void kexec_free_elf_headers(struct kimage *image)
image->elf_headers_sz = 0;
}
+#ifdef CONFIG_CRASH_DUMP
+int kexec_prepare_elf_core_header(struct kimage *image, bool need_kernel_map,
+ unsigned long *nr_ranges)
+{
+ int ret;
+
+ if (image->elf_headers)
+ return 0;
+
+ ret = crash_prepare_headers(need_kernel_map, &image->elf_headers,
+ &image->elf_headers_sz, nr_ranges);
+ if (ret)
+ pr_err("Preparing elf core header failed\n");
+
+ return ret;
+}
+
+int kexec_add_elf_core_header(struct kimage *image, struct kexec_buf *kbuf)
+{
+ unsigned long memsz = kbuf->memsz;
+ int ret;
+
+ kbuf->buffer = image->elf_headers;
+ kbuf->bufsz = image->elf_headers_sz;
+ kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
+
+ ret = kexec_add_buffer(kbuf);
+ if (ret)
+ return ret;
+
+ image->elf_load_addr = kbuf->mem;
+
+ /* The crash hotplug reservation can exceed the header size. */
+ if (memsz > image->elf_headers_sz) {
+ image->elf_headers_sz = memsz;
+#ifdef CONFIG_CRASH_HOTPLUG
+ image->elfcorehdr_index = image->nr_segments - 1;
+#endif
+ }
+
+ kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+ image->elf_load_addr, kbuf->bufsz, kbuf->memsz);
+
+ return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
+
+int kexec_add_initrd(struct kimage *image, struct kexec_buf *kbuf)
+{
+ int ret;
+
+ kbuf->buffer = image->initrd_buf;
+ kbuf->bufsz = kbuf->memsz = image->initrd_buf_len;
+ kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
+
+ ret = kexec_add_buffer(kbuf);
+ if (ret)
+ return ret;
+
+ kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+ kbuf->mem, kbuf->bufsz, kbuf->memsz);
+
+ return 0;
+}
+
+#if defined(CONFIG_OF) && defined(CONFIG_OF_FLATTREE)
+int kexec_add_fdt(struct kimage *image, struct kexec_buf *kbuf,
+ unsigned long initrd_load_addr, const char *cmdline,
+ void **fdt)
+{
+ void *new_fdt;
+ int ret;
+
+ new_fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr,
+ image->initrd_buf_len,
+ cmdline, 0);
+ if (!new_fdt) {
+ pr_err("Preparing for new dtb failed\n");
+ return -EINVAL;
+ }
+
+ fdt_pack(new_fdt);
+
+ kbuf->buffer = new_fdt;
+ kbuf->bufsz = kbuf->memsz = fdt_totalsize(new_fdt);
+ kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
+
+ ret = kexec_add_buffer(kbuf);
+ if (ret) {
+ kvfree(new_fdt);
+ return ret;
+ }
+
+ *fdt = new_fdt;
+
+ kexec_dprintk("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+ kbuf->mem, kbuf->bufsz, kbuf->memsz);
+
+ return 0;
+}
+#endif /* CONFIG_OF && CONFIG_OF_FLATTREE */
+
/*
* Free up memory used by kernel, initrd, and command line. This is temporary
* memory allocation which is not needed any more after these buffers have
--
2.34.1
More information about the linux-riscv
mailing list