Copy arm64 code and change for riscv so that the kexec -c can load
a vmlinuz image.

Signed-off-by: Tao Liu <[email protected]>
---
 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


Reply via email to