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
