272 lines
7.4 KiB
Diff
272 lines
7.4 KiB
Diff
From b257f311f5f0d32969f58098b03458b5bd728419 Mon Sep 17 00:00:00 2001
|
|
From: Song Shuai <songshuaishuai@tinylab.org>
|
|
Date: Tue, 22 Apr 2025 18:23:00 +0200
|
|
Subject: [PATCH] RISC-V: Support loading Image binary file
|
|
|
|
Add image-riscv file_type to probe/load Image file type,
|
|
|
|
As for kexec_load, find the pbase aligned text_offset from image header
|
|
and prepare segments for this syscall.
|
|
|
|
for kexec_file_load, setup the related options and let kernel part to
|
|
deal with the Image.
|
|
|
|
Signed-off-by: Song Shuai <songshuaishuai@tinylab.org>
|
|
Signed-off-by: Simon Horman <horms@kernel.org>
|
|
---
|
|
kexec/arch/riscv/Makefile | 2 +
|
|
kexec/arch/riscv/image-header.h | 88 ++++++++++++++++++++++++++
|
|
kexec/arch/riscv/kexec-image-riscv.c | 95 ++++++++++++++++++++++++++++
|
|
kexec/arch/riscv/kexec-riscv.c | 1 +
|
|
kexec/arch/riscv/kexec-riscv.h | 7 ++
|
|
5 files changed, 193 insertions(+)
|
|
create mode 100644 kexec/arch/riscv/image-header.h
|
|
create mode 100644 kexec/arch/riscv/kexec-image-riscv.c
|
|
|
|
diff --git a/kexec/arch/riscv/Makefile b/kexec/arch/riscv/Makefile
|
|
index 9937fbb5..18a997b0 100644
|
|
--- a/kexec/arch/riscv/Makefile
|
|
+++ b/kexec/arch/riscv/Makefile
|
|
@@ -3,6 +3,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-riscv.c
|
|
|
|
riscv_DT_OPS += kexec/dt-ops.c
|
|
@@ -14,6 +15,7 @@ riscv_ARCH_REUSE_INITRD =
|
|
riscv_CPPFLAGS += -I $(srcdir)/kexec/
|
|
|
|
dist += $(riscv_KEXEC_SRCS) \
|
|
+ kexec/arch/riscv/image-header.h \
|
|
kexec/arch/riscv/include/arch/options.h \
|
|
kexec/arch/riscv/iomem.h \
|
|
kexec/arch/riscv/kexec-riscv.h \
|
|
diff --git a/kexec/arch/riscv/image-header.h b/kexec/arch/riscv/image-header.h
|
|
new file mode 100644
|
|
index 00000000..a6775462
|
|
--- /dev/null
|
|
+++ b/kexec/arch/riscv/image-header.h
|
|
@@ -0,0 +1,88 @@
|
|
+/*
|
|
+ * RISCV64 binary image header.
|
|
+ * token from arm64/image-header.h
|
|
+ */
|
|
+
|
|
+#if !defined(__RISCV_IMAGE_HEADER_H)
|
|
+#define __RISCV_IMAGE_HEADER_H
|
|
+
|
|
+#include <endian.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+/**
|
|
+ * struct riscv_image_header - riscv kernel image header.
|
|
+ *
|
|
+ **/
|
|
+struct riscv_image_header {
|
|
+ uint32_t code0;
|
|
+ uint32_t code1;
|
|
+ uint64_t text_offset;
|
|
+ uint64_t image_size;
|
|
+ uint64_t flags;
|
|
+ uint32_t version;
|
|
+ uint32_t res1;
|
|
+ uint64_t res2;
|
|
+ uint64_t magic;
|
|
+ uint32_t magic2;
|
|
+ uint32_t res3;
|
|
+};
|
|
+
|
|
+#define RISCV_IMAGE_MAGIC 0x5643534952
|
|
+#define RISCV_IMAGE_MAGIC2 0x05435352
|
|
+
|
|
+#define RISCV_HEADER_VERSION_MAJOR 0
|
|
+#define RISCV_HEADER_VERSION_MINOR 2
|
|
+
|
|
+#define RISCV_HEADER_VERSION (RISCV_HEADER_VERSION_MAJOR << 16 | \
|
|
+ RISCV_HEADER_VERSION_MINOR)
|
|
+
|
|
+
|
|
+static const uint64_t riscv_image_flag_be = (1UL << 0);
|
|
+
|
|
+/**
|
|
+ * riscv_header_check_magic - Helper to check the riscv image header.
|
|
+ *
|
|
+ * Returns non-zero if header is OK.
|
|
+ */
|
|
+
|
|
+static inline int riscv_header_check_magic(const struct riscv_image_header *h)
|
|
+{
|
|
+ if (!h)
|
|
+ return 0;
|
|
+
|
|
+ return (h->version >= RISCV_HEADER_VERSION && h->magic2 == RISCV_IMAGE_MAGIC2);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * riscv_header_check_endiannes - Helper to check the riscv image header.
|
|
+ *
|
|
+ * Returns non-zero if the image was built as big endian.
|
|
+ */
|
|
+
|
|
+static inline int riscv_header_check_endiannes(const struct riscv_image_header *h)
|
|
+{
|
|
+ if (!h)
|
|
+ return 0;
|
|
+
|
|
+ return (le64toh(h->flags) & riscv_image_flag_be) >> 0;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+static inline uint64_t riscv_header_text_offset(const struct riscv_image_header *h)
|
|
+{
|
|
+ if (!h)
|
|
+ return 0;
|
|
+
|
|
+ return le64toh(h->text_offset);
|
|
+}
|
|
+
|
|
+static inline uint64_t riscv_header_image_size(const struct riscv_image_header *h)
|
|
+{
|
|
+ if (!h)
|
|
+ return 0;
|
|
+
|
|
+ return le64toh(h->image_size);
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/kexec/arch/riscv/kexec-image-riscv.c b/kexec/arch/riscv/kexec-image-riscv.c
|
|
new file mode 100644
|
|
index 00000000..6ae7e579
|
|
--- /dev/null
|
|
+++ b/kexec/arch/riscv/kexec-image-riscv.c
|
|
@@ -0,0 +1,95 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * RISC-V kexec binary image support.
|
|
+ *
|
|
+ * Author: Song Shuai <songhshuaishuai@tinylab.org>
|
|
+ */
|
|
+
|
|
+#define _GNU_SOURCE
|
|
+
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <limits.h>
|
|
+#include "image-header.h"
|
|
+#include "kexec.h"
|
|
+#include "kexec-riscv.h"
|
|
+#include "kexec-syscall.h"
|
|
+#include "arch/options.h"
|
|
+
|
|
+int image_riscv_probe(const char *kernel_buf, off_t kernel_size)
|
|
+{
|
|
+ const struct riscv_image_header *h;
|
|
+
|
|
+ if (kernel_size < sizeof(struct riscv_image_header)) {
|
|
+ dbgprintf("%s: No riscv image header.\n", __func__);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ h = (const struct riscv_image_header *)(kernel_buf);
|
|
+
|
|
+ if (!riscv_header_check_magic(h)) {
|
|
+ dbgprintf("%s: Bad riscv image header.\n", __func__);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int image_riscv_load(int argc, char **argv, const char *kernel_buf,
|
|
+ off_t kernel_size, struct kexec_info *info)
|
|
+{
|
|
+ const struct riscv_image_header *h;
|
|
+ unsigned long text_offset, image_size;
|
|
+ off_t new_base_addr = 0;
|
|
+
|
|
+ int ret;
|
|
+
|
|
+ if (info->file_mode) {
|
|
+ return prepare_kexec_file_options(info);
|
|
+ }
|
|
+
|
|
+ h = (const struct riscv_image_header *)(kernel_buf);
|
|
+
|
|
+ /* Check header */
|
|
+ if (!h->image_size){
|
|
+ dbgprintf("Kernel image size is NULL\n");
|
|
+ ret = EFAILED;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if(riscv_header_check_endiannes(h)){
|
|
+ dbgprintf("Kernel image was built as big endian\n");
|
|
+ ret = EFAILED;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ text_offset = riscv_header_text_offset(h);
|
|
+ image_size = riscv_header_image_size(h);
|
|
+
|
|
+ /* Setup the entry and segments */
|
|
+
|
|
+ ret = riscv_find_pbase(info, &new_base_addr, image_size, text_offset);
|
|
+ if (ret < 0) {
|
|
+ fprintf(stderr, "Could not find a memory region for the "
|
|
+ "provided Image\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ info->entry = (void *) new_base_addr;
|
|
+ dbgprintf("Entry point for the Image: 0x%lX\n", new_base_addr);
|
|
+
|
|
+ add_segment(info, kernel_buf, kernel_size, new_base_addr, image_size);
|
|
+
|
|
+ ret = load_extra_segments(info, text_offset, image_size, ULONG_MAX);
|
|
+exit:
|
|
+ if (ret)
|
|
+ fprintf(stderr, "kexec: load failed.\n");
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void image_riscv_usage(void)
|
|
+{
|
|
+ printf(
|
|
+" An RISC-V binary image, uncompressed, little endian.\n"
|
|
+" Typically an Image file.\n\n");
|
|
+}
|
|
diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
|
|
index 63165930..f34b4683 100644
|
|
--- a/kexec/arch/riscv/kexec-riscv.c
|
|
+++ b/kexec/arch/riscv/kexec-riscv.c
|
|
@@ -33,6 +33,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},
|
|
};
|
|
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 61809929..cfb03779 100644
|
|
--- a/kexec/arch/riscv/kexec-riscv.h
|
|
+++ b/kexec/arch/riscv/kexec-riscv.h
|
|
@@ -40,7 +40,14 @@ int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
|
|
int riscv_find_pbase(struct kexec_info *info, off_t *addr,
|
|
off_t size, off_t align);
|
|
|
|
+/* kexec-elf-riscv.c */
|
|
int elf_riscv_probe(const char *buf, off_t len);
|
|
void elf_riscv_usage(void);
|
|
int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
|
|
struct kexec_info *info);
|
|
+
|
|
+/* kexec-image-riscv.c */
|
|
+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);
|