From 2495ccfc52069ecec46031587c94b03ae66ed5d2 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Thu, 14 Sep 2023 16:50:00 +0800 Subject: [PATCH 4/4] zboot: add loongarch kexec_load support Copy arm64 code and change for loongarch so that the kexec -c can load a zboot image. Note: probe zboot image first otherwise the pei-loongarch file type will be used. Signed-off-by: Dave Young Signed-off-by: Simon Horman --- kexec/arch/loongarch/Makefile | 1 + kexec/arch/loongarch/image-header.h | 1 + kexec/arch/loongarch/kexec-loongarch.c | 1 + kexec/arch/loongarch/kexec-loongarch.h | 4 + kexec/arch/loongarch/kexec-pez-loongarch.c | 90 ++++++++++++++++++++++ 5 files changed, 97 insertions(+) create mode 100644 kexec/arch/loongarch/kexec-pez-loongarch.c diff --git a/kexec/arch/loongarch/Makefile b/kexec/arch/loongarch/Makefile index 3b33b96..cee7e56 100644 --- a/kexec/arch/loongarch/Makefile +++ b/kexec/arch/loongarch/Makefile @@ -6,6 +6,7 @@ loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-elf-loongarch.c loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-pei-loongarch.c loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-elf-rel-loongarch.c loongarch_KEXEC_SRCS += kexec/arch/loongarch/crashdump-loongarch.c +loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-pez-loongarch.c loongarch_MEM_REGIONS = kexec/mem_regions.c diff --git a/kexec/arch/loongarch/image-header.h b/kexec/arch/loongarch/image-header.h index 3b75765..223d81f 100644 --- a/kexec/arch/loongarch/image-header.h +++ b/kexec/arch/loongarch/image-header.h @@ -33,6 +33,7 @@ struct loongarch_image_header { }; static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'}; +static const uint8_t loongarch_pe_machtype[6] = {'P','E', 0x0, 0x0, 0x64, 0x62}; /** * loongarch_header_check_pe_sig - Helper to check the loongarch image header. diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c index f47c998..62ff8fd 100644 --- a/kexec/arch/loongarch/kexec-loongarch.c +++ b/kexec/arch/loongarch/kexec-loongarch.c @@ -165,6 +165,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges, struct file_type file_type[] = { {"elf-loongarch", elf_loongarch_probe, elf_loongarch_load, elf_loongarch_usage}, + {"pez-loongarch", pez_loongarch_probe, pez_loongarch_load, pez_loongarch_usage}, {"pei-loongarch", pei_loongarch_probe, pei_loongarch_load, pei_loongarch_usage}, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); diff --git a/kexec/arch/loongarch/kexec-loongarch.h b/kexec/arch/loongarch/kexec-loongarch.h index 5120a26..2c7624f 100644 --- a/kexec/arch/loongarch/kexec-loongarch.h +++ b/kexec/arch/loongarch/kexec-loongarch.h @@ -27,6 +27,10 @@ int pei_loongarch_probe(const char *buf, off_t len); int pei_loongarch_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void pei_loongarch_usage(void); +int pez_loongarch_probe(const char *kernel_buf, off_t kernel_size); +int pez_loongarch_load(int argc, char **argv, const char *buf, off_t len, + struct kexec_info *info); +void pez_loongarch_usage(void); int loongarch_process_image_header(const struct loongarch_image_header *h); diff --git a/kexec/arch/loongarch/kexec-pez-loongarch.c b/kexec/arch/loongarch/kexec-pez-loongarch.c new file mode 100644 index 0000000..942a47c --- /dev/null +++ b/kexec/arch/loongarch/kexec-pez-loongarch.c @@ -0,0 +1,90 @@ +/* + * LoongArch PE compressed Image (vmlinuz, ZBOOT) support. + * Based on arm64 code + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "kexec.h" +#include "kexec-loongarch.h" +#include +#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_loongarch_probe(const char *kernel_buf, off_t kernel_size) +{ + int ret = -1; + const struct loongarch_image_header *h; + char *buf; + off_t buf_sz; + + buf = (char *)kernel_buf; + buf_sz = kernel_size; + if (!buf) + return -1; + h = (const struct loongarch_image_header *)buf; + + dbgprintf("%s: PROBE.\n", __func__); + if (buf_sz < sizeof(struct loongarch_image_header)) { + dbgprintf("%s: Not large enough to be a PE image.\n", __func__); + return -1; + } + if (!loongarch_header_check_pe_sig(h)) { + dbgprintf("%s: Not an PE image.\n", __func__); + return -1; + } + + if (buf_sz < sizeof(struct loongarch_image_header) + h->pe_header) { + dbgprintf("%s: PE image offset larger than image.\n", __func__); + return -1; + } + + if (memcmp(&buf[h->pe_header], + loongarch_pe_machtype, sizeof(loongarch_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); + + /* Fixme: add sanity check of the decompressed kernel before return */ + return ret; +} + +int pez_loongarch_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; + + info->kernel_fd = kernel_fd; + /* + * slurp_fd will close kernel_fd, but it is safe here + * due to no kexec_file_load support. + */ + kbuf = slurp_fd(kernel_fd, NULL, decompressed_size, &nread); + if (!kbuf || nread != decompressed_size) { + dbgprintf("%s: slurp_fd failed.\n", __func__); + return -1; + } + return pei_loongarch_load(argc, argv, kbuf, decompressed_size, info); + } + + dbgprintf("%s: wrong kernel file descriptor.\n", __func__); + return -1; +} + +void pez_loongarch_usage(void) +{ + printf( +" An LoongArch vmlinuz, PE image of a compressed, little endian.\n" +" kernel, built with ZBOOT enabled.\n\n"); +} -- 2.41.0