[PATCH 3/4] RISC-V: Separate elf_riscv_find_pbase out

Björn Töpel
2025-04-09T20:15:01Z

From: Song Shuai <songshuaishuai@tinylab.org>

The is the preparative patch for RISC-V kexec Image file support.

Separate the elf_riscv_find_pbase() function out to
allow kernel_load syscall load Image binary file.

Signed-off-by: Song Shuai <songshuaishuai@tinylab.org>
---
kexec/arch/riscv/kexec-elf-riscv.c | 72 +-----------------------------
kexec/arch/riscv/kexec-riscv.c | 55 +++++++++++++++++++++++
kexec/arch/riscv/kexec-riscv.h | 13 ++++++
3 files changed, 69 insertions(+), 71 deletions(-)

diff --git a/kexec/arch/riscv/kexec-elf-riscv.c b/kexec/arch/riscv/kexec-elf-riscv.c
index 2b9f66d782af..434873cf9f08 100644
--- a/kexec/arch/riscv/kexec-elf-riscv.c
+++ b/kexec/arch/riscv/kexec-elf-riscv.c
@@ -12,76 +12,6 @@
#include "kexec-syscall.h" /* For KEXEC_ON_CRASH */
#include "kexec-riscv.h"

-
-/*********\
-* HELPERS *
-\*********/
-
-/*
- * Go through the available physical memory regions and
- * find one that can hold an image of the specified size.
- * Note: This is called after get_memory_ranges so
- * info->memory_range[] should be populated. Also note that
- * memory ranges are sorted, so we'll return the first region
- * that's big enough for holding the image.
- */
-static int elf_riscv_find_pbase(struct kexec_info *info, off_t *addr,
- off_t size)
-{
- int i = 0;
- off_t start = 0;
- off_t end = 0;
- int ret = 0;
-
- /*
- * If this image is for a crash kernel, use the region
- * the primary kernel has already reserved for us.
- */
- if (info->kexec_flags & KEXEC_ON_CRASH) {
- ret = get_crash_kernel_load_range((uint64_t *) &start,
- (uint64_t *) &end);
- if (!ret) {
- /*
- * Kernel should be aligned to the nearest
- * hugepage (2MB for RV64, 4MB for RV32).
- */
-#if __riscv_xlen == 64
- start = _ALIGN_UP(start, 0x200000);
-#else
- start = _ALIGN_UP(start, 0x400000);
-#endif
- if (end > start && ((end - start) >= size)) {
- *addr = start;
- return 0;
- }
-
- return -EFBIG;
- } else
- return ENOCRASHKERNEL;
- }
-
- for (i = 0; i < info->memory_ranges; i++) {
- if (info->memory_range[i].type != RANGE_RAM)
- continue;
-
- start = info->memory_range[i].start;
- end = info->memory_range[i].end;
-
-#if __riscv_xlen == 64
- start = _ALIGN_UP(start, 0x200000);
-#else
- start = _ALIGN_UP(start, 0x400000);
-#endif
-
- if (end > start && ((end - start) >= size)) {
- *addr = start;
- return 0;
- }
- }
-
- return -EFBIG;
-}
-
/**************\
* ENTRY POINTS *
\**************/
@@ -182,7 +112,7 @@ int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
kernel_size / 1024, old_base_addr, old_start_addr);

/* Get a continuous physical region that can hold the kernel */
- ret = elf_riscv_find_pbase(info, &new_base_addr, kernel_size);
+ ret = riscv_find_pbase(info, &new_base_addr, kernel_size, KERNEL_ALIGN);
if (ret < 0) {
fprintf(stderr, "Could not find a memory region for the "
"provided ELF image\n");
diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
index bbc25c5cba41..631659301749 100644
--- a/kexec/arch/riscv/kexec-riscv.c
+++ b/kexec/arch/riscv/kexec-riscv.c
@@ -50,6 +50,61 @@ static struct fdt_image provided_fdt = {0};
* COMMON HELPERS *
\****************/

+/*
+ * Go through the available physical memory regions and
+ * find one that can hold an image of the specified size
+ * and start address should be aligned up with `align`.
+ * Note: This is called after get_memory_ranges so
+ * info->memory_range[] should be populated. Also note that
+ * memory ranges are sorted, so we'll return the first region
+ * that's big enough for holding the image.
+ */
+int riscv_find_pbase(struct kexec_info *info, off_t *addr,
+ off_t size, off_t align)
+{
+ int i = 0;
+ off_t start = 0;
+ off_t end = 0;
+ int ret = 0;
+
+ /*
+ * If this image is for a crash kernel, use the region
+ * the primary kernel has already reserved for us.
+ */
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ ret = get_crash_kernel_load_range((uint64_t *) &start,
+ (uint64_t *) &end);
+ if (!ret) {
+ start = _ALIGN_UP(start, align);
+
+ if (end > start && ((end - start) >= size)) {
+ *addr = start;
+ return 0;
+ }
+
+ return -EFBIG;
+ } else
+ return ENOCRASHKERNEL;
+ }
+
+ for (i = 0; i < info->memory_ranges; i++) {
+ if (info->memory_range[i].type != RANGE_RAM)
+ continue;
+
+ start = info->memory_range[i].start;
+ end = info->memory_range[i].end;
+
+ start = _ALIGN_UP(start, align);
+
+ if (end > start && ((end - start) >= size)) {
+ *addr = start;
+ return 0;
+ }
+ }
+
+ return -EFBIG;
+}
+
int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
uint64_t kernel_size, uint64_t max_addr)
{
diff --git a/kexec/arch/riscv/kexec-riscv.h b/kexec/arch/riscv/kexec-riscv.h
index f136c7eab561..618099291117 100644
--- a/kexec/arch/riscv/kexec-riscv.h
+++ b/kexec/arch/riscv/kexec-riscv.h
@@ -4,6 +4,17 @@
* Nick Kossifidis <mick@ics.forth.gr>
*/

+/*
+ * Kernel should be aligned to the nearest
+ * hugepage (2MB for RV64, 4MB for RV32).
+ */
+
+#if __riscv_xlen == 64
+#define KERNEL_ALIGN 0x200000
+#else
+#define KERNEL_ALIGN 0x400000
+#endif
+
struct fdt_image {
char *buf;
off_t size;
@@ -26,6 +37,8 @@ int load_elfcorehdr(struct kexec_info *info);
int prepare_kexec_file_options(struct kexec_info *info);
int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
uint64_t kernel_size, uint64_t max_addr);
+int riscv_find_pbase(struct kexec_info *info, off_t *addr,
+ off_t size, off_t align);

int elf_riscv_probe(const char *buf, off_t len);
void elf_riscv_usage(void);