[PATCH 2/4] RISC-V: Enable kexec_file_load syscall

Björn Töpel
2025-04-09T20:14:58Z

From: Li Zhengyu <lizhengyu3@huawei.com>

Create prepare_kexec_file_options() function to prepare the options
to kexec_file_load syscall, and it would be used in elf_riscv_load()
or the future image_riscv_load().

The patch comes from the RISC-V Linux kernel_file_load support[1],
So its author should be Li Zhengyu.

[1]: https://lore.kernel.org/all/20220408100914.150110-1-lizhengyu3@huawei.com/

Signed-off-by: Song Shuai <songshuaishuai@tinylab.org>
---
kexec/arch/riscv/kexec-elf-riscv.c | 5 ++--
kexec/arch/riscv/kexec-riscv.c | 39 ++++++++++++++++++++++++++++++
kexec/arch/riscv/kexec-riscv.h | 1 +
kexec/kexec-syscall.h | 3 +++
4 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/kexec/arch/riscv/kexec-elf-riscv.c b/kexec/arch/riscv/kexec-elf-riscv.c
index f3c011c4c1dc..2b9f66d782af 100644
--- a/kexec/arch/riscv/kexec-elf-riscv.c
+++ b/kexec/arch/riscv/kexec-elf-riscv.c
@@ -112,6 +112,7 @@ void elf_riscv_usage(void)
{
}

+
int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
@@ -127,9 +128,7 @@ int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
int ret = 0;

if (info->file_mode) {
- fprintf(stderr, "kexec_file not supported on this "
- "architecture\n");
- return -EINVAL;
+ return prepare_kexec_file_options(info);
}

/* Parse the ELF file */
diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
index 38d9a394aadd..bbc25c5cba41 100644
--- a/kexec/arch/riscv/kexec-riscv.c
+++ b/kexec/arch/riscv/kexec-riscv.c
@@ -17,6 +17,12 @@
#include "kexec-riscv.h"
#include "iomem.h"
#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif

const struct arch_map_entry arches[] = {
{ "riscv32", KEXEC_ARCH_RISCV },
@@ -141,6 +147,39 @@ void arch_usage(void)
printf(riscv_opts_usage);
}

+int prepare_kexec_file_options(struct kexec_info *info)
+{
+ int fd;
+ ssize_t result;
+ struct stat stats;
+
+ if (arch_options.cmdline) {
+ info->command_line = (char *)arch_options.cmdline;
+ info->command_line_len = strlen(info->command_line) + 1;
+ }
+
+ if (!arch_options.initrd_path) {
+ info->initrd_fd = -1;
+ return 0;
+ }
+
+ fd = open(arch_options.initrd_path, O_RDONLY | _O_BINARY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open `%s': %s\n", arch_options.initrd_path,
+ strerror(errno));
+ return -EINVAL;
+ }
+ result = fstat(fd, &stats);
+ if (result < 0) {
+ close(fd);
+ fprintf(stderr, "Cannot stat: %s: %s\n", arch_options.initrd_path,
+ strerror(errno));
+ return -EINVAL;
+ }
+ info->initrd_fd = fd;
+ return 0;
+}
+
int arch_process_options(int argc, char **argv)
{
static const struct option options[] = {
diff --git a/kexec/arch/riscv/kexec-riscv.h b/kexec/arch/riscv/kexec-riscv.h
index c4323a65dacf..f136c7eab561 100644
--- a/kexec/arch/riscv/kexec-riscv.h
+++ b/kexec/arch/riscv/kexec-riscv.h
@@ -23,6 +23,7 @@ extern struct memory_range elfcorehdr_mem;
int load_elfcorehdr(struct kexec_info *info);

/* kexec-riscv.c */
+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);

diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h
index 89591ad17e7d..9b1757877a85 100644
--- a/kexec/kexec-syscall.h
+++ b/kexec/kexec-syscall.h
@@ -80,6 +80,9 @@
#ifdef __hppa__
#define __NR_kexec_file_load 355
#endif
+#if defined(__riscv__) || defined(__riscv)
+#define __NR_kexec_file_load 294
+#endif

#ifndef __NR_kexec_file_load
/* system call not available for the arch */