[kexec-tools][PATCH] RISC-V: add kexec_load support for vmlinuz
Tao Liu
ltao at redhat.com
Mon May 25 21:58:07 PDT 2026
Copy arm64 code and change for riscv so that the kexec -c can load
a vmlinuz image.
Signed-off-by: Tao Liu <ltao at redhat.com>
---
kexec/arch/riscv/Makefile | 1 +
kexec/arch/riscv/image-header.h | 12 +++
kexec/arch/riscv/kexec-riscv.c | 1 +
kexec/arch/riscv/kexec-riscv.h | 6 ++
kexec/arch/riscv/kexec-vmlinuz-riscv.c | 112 +++++++++++++++++++++++++
5 files changed, 132 insertions(+)
create mode 100644 kexec/arch/riscv/kexec-vmlinuz-riscv.c
diff --git a/kexec/arch/riscv/Makefile b/kexec/arch/riscv/Makefile
index 18a997b..6ba8976 100644
--- a/kexec/arch/riscv/Makefile
+++ b/kexec/arch/riscv/Makefile
@@ -4,6 +4,7 @@
riscv_KEXEC_SRCS = kexec/arch/riscv/crashdump-riscv.c
riscv_KEXEC_SRCS += kexec/arch/riscv/kexec-elf-riscv.c
riscv_KEXEC_SRCS += kexec/arch/riscv/kexec-image-riscv.c
+riscv_KEXEC_SRCS += kexec/arch/riscv/kexec-vmlinuz-riscv.c
riscv_KEXEC_SRCS += kexec/arch/riscv/kexec-riscv.c
riscv_DT_OPS += kexec/dt-ops.c
diff --git a/kexec/arch/riscv/image-header.h b/kexec/arch/riscv/image-header.h
index a677546..7e950ee 100644
--- a/kexec/arch/riscv/image-header.h
+++ b/kexec/arch/riscv/image-header.h
@@ -85,4 +85,16 @@ static inline uint64_t riscv_header_image_size(const struct riscv_image_header *
return le64toh(h->image_size);
}
+static const uint8_t riscv_image_pe_sig[2] = {'M', 'Z'};
+static const uint8_t riscv_pe_machtype[6] = {'P','E', 0x0, 0x0, 0x64, 0x50};
+
+static inline int riscv_header_check_pe_sig(const struct riscv_image_header *h)
+{
+ if (!h)
+ return 0;
+
+ return (*((char *)&(h->code0)) == riscv_image_pe_sig[0] &&
+ *((char *)&(h->code0) + 1) == riscv_image_pe_sig[1]);
+}
+
#endif
diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
index a5a12a0..a7188ac 100644
--- a/kexec/arch/riscv/kexec-riscv.c
+++ b/kexec/arch/riscv/kexec-riscv.c
@@ -34,6 +34,7 @@ const struct arch_map_entry arches[] = {
struct file_type file_type[] = {
{"elf-riscv", elf_riscv_probe, elf_riscv_load, elf_riscv_usage},
{"image-riscv", image_riscv_probe, image_riscv_load, image_riscv_usage},
+ {"vmlinuz-riscv", pez_riscv_probe, pez_riscv_load, pez_riscv_usage},
};
int file_types = sizeof(file_type) / sizeof(file_type[0]);
diff --git a/kexec/arch/riscv/kexec-riscv.h b/kexec/arch/riscv/kexec-riscv.h
index cfb0377..f487b27 100644
--- a/kexec/arch/riscv/kexec-riscv.h
+++ b/kexec/arch/riscv/kexec-riscv.h
@@ -51,3 +51,9 @@ int image_riscv_probe(const char *buf, off_t len);
void image_riscv_usage(void);
int image_riscv_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info);
+
+/* kexec-vmlinuz-riscv.c */
+int pez_riscv_probe(const char *buf, off_t len);
+void pez_riscv_usage(void);
+int pez_riscv_load(int argc, char **argv, const char *buf, off_t len,
+ struct kexec_info *info);
diff --git a/kexec/arch/riscv/kexec-vmlinuz-riscv.c b/kexec/arch/riscv/kexec-vmlinuz-riscv.c
new file mode 100644
index 0000000..6430e37
--- /dev/null
+++ b/kexec/arch/riscv/kexec-vmlinuz-riscv.c
@@ -0,0 +1,112 @@
+/*
+ * RISC-V PE compressed Image (vmlinuz, ZBOOT) support.
+ * Based on arm64 code
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "kexec.h"
+#include "kexec-riscv.h"
+#include "image-header.h"
+#include <kexec-pe-zboot.h>
+#include "arch/options.h"
+
+static int kernel_fd = -1;
+static off_t decompressed_size;
+
+/* Returns:
+ * -1 : in case of error/invalid format (not a valid PE+compressed ZBOOT format.
+ */
+int pez_riscv_probe(const char *kernel_buf, off_t kernel_size)
+{
+ int ret = -1;
+ const struct riscv_image_header *h;
+ char *buf;
+ off_t buf_sz;
+
+ buf = (char *)kernel_buf;
+ buf_sz = kernel_size;
+ if (!buf)
+ return -1;
+ h = (const struct riscv_image_header *)buf;
+
+ dbgprintf("%s: PROBE.\n", __func__);
+ if (buf_sz < sizeof(struct riscv_image_header)) {
+ dbgprintf("%s: Not large enough to be a PE image.\n", __func__);
+ return -1;
+ }
+ if (!riscv_header_check_pe_sig(h)) {
+ dbgprintf("%s: Not an PE image.\n", __func__);
+ return -1;
+ }
+
+ if (buf_sz < sizeof(struct riscv_image_header) + h->res3) {
+ dbgprintf("%s: PE image offset larger than image.\n", __func__);
+ return -1;
+ }
+
+ if (memcmp(&buf[h->res3],
+ riscv_pe_machtype, sizeof(riscv_pe_machtype))) {
+ dbgprintf("%s: PE header doesn't match machine type.\n", __func__);
+ return -1;
+ }
+
+ ret = pez_prepare(buf, buf_sz, &kernel_fd, &decompressed_size);
+
+ if (!ret) {
+ /* validate the riscv specific header */
+ struct riscv_image_header hdr_check;
+ if (read(kernel_fd, &hdr_check, sizeof(hdr_check)) != sizeof(hdr_check))
+ goto bad_header;
+
+ lseek(kernel_fd, 0, SEEK_SET);
+
+ if (!riscv_header_check_magic(&hdr_check)) {
+ dbgprintf("%s: Bad riscv image header.\n", __func__);
+ goto bad_header;
+ }
+ }
+
+ return ret;
+bad_header:
+ close(kernel_fd);
+ free(buf);
+ return -1;
+}
+
+int pez_riscv_load(int argc, char **argv, const char *buf, off_t len,
+ struct kexec_info *info)
+{
+ if (kernel_fd > 0 && decompressed_size > 0) {
+ char *kbuf;
+ off_t nread;
+ int fd;
+
+ if (info->kernel_fd > 0)
+ close(info->kernel_fd);
+ info->kernel_fd = kernel_fd;
+ fd = dup(kernel_fd);
+ if (fd < 0) {
+ dbgprintf("%s: dup fd failed.\n", __func__);
+ return -1;
+ }
+ kbuf = slurp_fd(fd, NULL, decompressed_size, &nread);
+ if (!kbuf || nread != decompressed_size) {
+ dbgprintf("%s: slurp_fd failed.\n", __func__);
+ return -1;
+ }
+ return image_riscv_load(argc, argv, kbuf, decompressed_size, info);
+ }
+
+ dbgprintf("%s: wrong kernel file descriptor.\n", __func__);
+ return -1;
+}
+
+void pez_riscv_usage(void)
+{
+ printf(
+" An RISC-V vmlinuz, PE image of a compressed, little endian.\n"
+" kernel, built with ZBOOT enabled.\n\n");
+}
--
2.47.0
More information about the kexec
mailing list