[PATCH 3/3] riscv: kexec: reserve the PMD-aligned kernel image range

"Yufan Dou" <[email protected]> Thu, 6 Aug 2026 15:22:56 +0800
Newsgroups org.infradead.lists.linux-riscv,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
When strict kernel permissions are enabled, the next kernel extends
its image reservation from _start to the PMD-aligned address following
_end. If kexec only reserves the exact image range, a later segment can
be placed in this aligned tail and overlap the next kernel's
reservation.

For a flat Image, extend the decoded image size to the next PMD
boundary.

An ELF image contains multiple PT_LOAD segments. Extending every
segment can make an intermediate segment overlap the following one.
Find the PT_LOAD segment with the highest physical end address and
extend only that segment to the next PMD boundary. Align the extent
searched by elf_find_pbase() as well, so that the expanded tail stays
within the range validated against the available memory.

This reserves the range expected by the next kernel without changing
the layout of intermediate ELF segments.

Fixes: 6261586e0c91 ("RISC-V: Add kexec_file support")
Fixes: 809a11eea8e8 ("riscv: kexec_file: Support loading Image binary file")
Cc: [email protected]
Co-developed-by: Yicong Yang <[email protected]>
Signed-off-by: Yicong Yang <[email protected]>
Signed-off-by: Yufan Dou <[email protected]>
---
 arch/riscv/kernel/kexec_elf.c   | 21 +++++++++++++++++++--
 arch/riscv/kernel/kexec_image.c |  7 ++++++-
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/kernel/kexec_elf.c b/arch/riscv/kernel/kexec_elf.c
index d84548f9d289..da5679bf1d0c 100644
--- a/arch/riscv/kernel/kexec_elf.c
+++ b/arch/riscv/kernel/kexec_elf.c
@@ -28,6 +28,15 @@ static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
 	int ret = 0;
 	struct kexec_buf kbuf = {};
 	const struct elf_phdr *phdr;
+	unsigned long highest_paddr = 0;
+
+	/* Find the highest physical end address of the kernel image. */
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		phdr = &elf_info->proghdrs[i];
+		if (phdr->p_type == PT_LOAD)
+			highest_paddr = max(highest_paddr,
+					    (unsigned long)(phdr->p_paddr + phdr->p_memsz));
+	}
 
 	kbuf.image = image;
 
@@ -41,6 +50,13 @@ static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
 		kbuf.buf_align = phdr->p_align;
 		kbuf.mem = phdr->p_paddr - old_pbase + new_pbase;
 		kbuf.memsz = phdr->p_memsz;
+		/*
+		 * The next kernel aligns its image reservation on PMD_SIZE, as
+		 * explained by a comment in setup_bootmem(). Reserve that tail
+		 * so subsequent segments do not overlap it.
+		 */
+		if (phdr->p_paddr + phdr->p_memsz == highest_paddr)
+			kbuf.memsz = ALIGN(kbuf.mem + phdr->p_memsz, PMD_SIZE) - kbuf.mem;
 		kbuf.top_down = false;
 		ret = kexec_add_buffer(&kbuf);
 		if (ret)
@@ -95,9 +111,10 @@ static int elf_find_pbase(struct kimage *image, struct elfhdr *ehdr,
 	/*
 	 * The segments are added at fixed addresses later on, which makes
 	 * kexec_add_buffer() skip the memory hole check, so the range searched
-	 * here has to cover the whole extent the image occupies in memory.
+	 * here has to cover the whole extent the image occupies in memory,
+	 * including the PMD-aligned tail of the last segment.
 	 */
-	kbuf.memsz = ALIGN(highest_paddr - lowest_paddr, PAGE_SIZE);
+	kbuf.memsz = ALIGN(highest_paddr - lowest_paddr, PMD_SIZE);
 	kbuf.cma = NULL;
 	kbuf.top_down = false;
 	ret = arch_kexec_locate_mem_hole(&kbuf);
diff --git a/arch/riscv/kernel/kexec_image.c b/arch/riscv/kernel/kexec_image.c
index 51dc89259f16..52678b3044fd 100644
--- a/arch/riscv/kernel/kexec_image.c
+++ b/arch/riscv/kernel/kexec_image.c
@@ -69,7 +69,12 @@ static void *image_load(struct kimage *image,
 	kbuf.buffer = kernel;
 	kbuf.bufsz = kernel_len;
 	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
-	kbuf.memsz = le64_to_cpu(h->image_size);
+	/*
+	 * The next kernel aligns its image reservation on PMD_SIZE, as
+	 * explained by a comment in setup_bootmem(). Reserve that tail so
+	 * subsequent segments do not overlap it.
+	 */
+	kbuf.memsz = ALIGN(le64_to_cpu(h->image_size), PMD_SIZE);
 	kbuf.buf_align = le64_to_cpu(h->text_offset);
 
 	ret = kexec_add_buffer(&kbuf);
-- 
2.34.1

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv