public inbox for linux-riscv@lists.infradead.org
 help / color / mirror / Atom feed
From: "Björn Töpel" <bjorn@kernel.org>
To: Simon Horman <horms@kernel.org>,
	Simon Horman <horms@verge.net.au>,
	Nick Kossifidis <mick@ics.forth.gr>,
	Song Shuai <songshuaishuai@tinylab.org>,
	Li Zhengyu <lizhengyu3@huawei.com>,
	kexec@lists.infradead.org
Cc: Dave Young <dyoung@redhat.com>, Yixun Lan <yixun.lan@gmail.com>,
	Xianting Tian <xianting.tian@linux.alibaba.com>,
	linux-riscv@lists.infradead.org
Subject: [PATCH 4/4] RISC-V: Support loading Image binary file
Date: Wed,  9 Apr 2025 22:14:26 +0200	[thread overview]
Message-ID: <20250409201428.648717-5-bjorn@kernel.org> (raw)
In-Reply-To: <20250409201428.648717-1-bjorn@kernel.org>

From: Song Shuai <songshuaishuai@tinylab.org>

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>
---
 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 f26cc9025e77..37ef7603fc38 100644
--- a/kexec/arch/riscv/Makefile
+++ b/kexec/arch/riscv/Makefile
@@ -3,6 +3,7 @@
 #
 riscv_KEXEC_SRCS =  kexec/arch/riscv/kexec-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/crashdump-riscv.c
 
 riscv_MEM_REGIONS = kexec/mem_regions.c
@@ -15,6 +16,7 @@ riscv_CPPFLAGS += -I $(srcdir)/kexec/
 
 dist += kexec/arch/riscv/Makefile $(riscv_KEXEC_SRCS)			\
 	kexec/arch/riscv/kexec-riscv.h					\
+	kexec/arch/riscv/image-header.h					\
 	kexec/arch/riscv/include/arch/options.h
 
 ifdef HAVE_LIBFDT
diff --git a/kexec/arch/riscv/image-header.h b/kexec/arch/riscv/image-header.h
new file mode 100644
index 000000000000..a6775462358e
--- /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 000000000000..6ae7e579fd16
--- /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 631659301749..f34b46831160 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 618099291117..cfb03779a022 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);
-- 
2.45.2


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

  parent reply	other threads:[~2025-04-09 20:15 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-09 20:14 [PATCH 0/4] kexec-tools RISC-V port Björn Töpel
2025-04-09 20:14 ` [PATCH 1/4] RISC-V: Add support for riscv kexec/kdump on kexec-tools Björn Töpel
2025-04-22 10:48   ` Simon Horman
2025-04-22 12:07     ` Björn Töpel
2025-04-22 13:54       ` Simon Horman
2025-04-09 20:14 ` [PATCH 2/4] RISC-V: Enable kexec_file_load syscall Björn Töpel
2025-04-09 20:14 ` [PATCH 3/4] RISC-V: Separate elf_riscv_find_pbase out Björn Töpel
2025-04-09 20:14 ` Björn Töpel [this message]
2025-04-14  8:40 ` [PATCH 0/4] kexec-tools RISC-V port Simon Horman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250409201428.648717-5-bjorn@kernel.org \
    --to=bjorn@kernel.org \
    --cc=dyoung@redhat.com \
    --cc=horms@kernel.org \
    --cc=horms@verge.net.au \
    --cc=kexec@lists.infradead.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=lizhengyu3@huawei.com \
    --cc=mick@ics.forth.gr \
    --cc=songshuaishuai@tinylab.org \
    --cc=xianting.tian@linux.alibaba.com \
    --cc=yixun.lan@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox