summaryrefslogtreecommitdiffstats
path: root/kexec/arch/loongarch/kexec-pei-loongarch.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/loongarch/kexec-pei-loongarch.c')
-rw-r--r--kexec/arch/loongarch/kexec-pei-loongarch.c117
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 00000000..f86ac61e
--- /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");
+}