diff options
Diffstat (limited to 'kexec/arch/loongarch/kexec-pei-loongarch.c')
-rw-r--r-- | kexec/arch/loongarch/kexec-pei-loongarch.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/kexec/arch/loongarch/kexec-pei-loongarch.c b/kexec/arch/loongarch/kexec-pei-loongarch.c new file mode 100644 index 0000000..f86ac61 --- /dev/null +++ b/kexec/arch/loongarch/kexec-pei-loongarch.c @@ -0,0 +1,117 @@ +/* + * LoongArch kexec PE format binary image support. + * + * Copyright (C) 2022 Loongson Technology Corporation Limited. + * Youling Tang <tangyouling@loongson.cn> + * + * derived from kexec-image-arm64.c + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#define _GNU_SOURCE + +#include <limits.h> +#include <errno.h> +#include <elf.h> + +#include "kexec.h" +#include "kexec-elf.h" +#include "image-header.h" +#include "kexec-syscall.h" +#include "crashdump-loongarch.h" +#include "kexec-loongarch.h" +#include "arch/options.h" + +int pei_loongarch_probe(const char *kernel_buf, off_t kernel_size) +{ + const struct loongarch_image_header *h; + + if (kernel_size < sizeof(struct loongarch_image_header)) { + dbgprintf("%s: No loongarch image header.\n", __func__); + return -1; + } + + h = (const struct loongarch_image_header *)(kernel_buf); + + if (!loongarch_header_check_pe_sig(h)) { + dbgprintf("%s: Bad loongarch PE image header.\n", __func__); + return -1; + } + + return 0; +} + +int pei_loongarch_load(int argc, char **argv, const char *buf, + off_t len, struct kexec_info *info) +{ + int result; + unsigned long hole_min = 0; + unsigned long kernel_segment, kernel_entry; + const struct loongarch_image_header *header; + + header = (const struct loongarch_image_header *)(buf); + + if (loongarch_process_image_header(header)) + return EFAILED; + + kernel_segment = loongarch_locate_kernel_segment(info); + + if (kernel_segment == ULONG_MAX) { + dbgprintf("%s: Kernel segment is not allocated\n", __func__); + result = EFAILED; + goto exit; + } + + kernel_entry = virt_to_phys(loongarch_header_kernel_entry(header)); + + dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); + dbgprintf("%s: kernel_entry: %016lx\n", __func__, kernel_entry); + dbgprintf("%s: image_size: %016lx\n", __func__, + loongarch_mem.image_size); + dbgprintf("%s: text_offset: %016lx\n", __func__, + loongarch_mem.text_offset); + dbgprintf("%s: phys_offset: %016lx\n", __func__, + loongarch_mem.phys_offset); + dbgprintf("%s: PE format: %s\n", __func__, + (loongarch_header_check_pe_sig(header) ? "yes" : "no")); + + /* Get kernel entry point */ + info->entry = (void *)kernel_entry; + + hole_min = kernel_segment + loongarch_mem.image_size; + + /* Create and initialize elf core header segment */ + if (info->kexec_flags & KEXEC_ON_CRASH) { + result = load_crashdump_segments(info); + if (result) { + dbgprintf("%s: Creating eflcorehdr failed.\n", + __func__); + goto exit; + } + } + + /* Load the kernel */ + add_segment(info, buf, len, kernel_segment, loongarch_mem.image_size); + + /* Prepare and load dtb and initrd data */ + result = loongarch_load_other_segments(info, hole_min); + if (result) { + fprintf(stderr, "kexec: Load dtb and initrd segments failed.\n"); + goto exit; + } + +exit: + if (result) + fprintf(stderr, "kexec: load failed.\n"); + + return result; +} + +void pei_loongarch_usage(void) +{ + printf( +" An LoongArch PE format binary image, uncompressed, little endian.\n" +" Typically a vmlinux.efi file.\n\n"); +} |