summaryrefslogtreecommitdiff
path: root/kexec/arch/arm64/kexec-elf-arm64.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/arm64/kexec-elf-arm64.c')
-rw-r--r--kexec/arch/arm64/kexec-elf-arm64.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c
new file mode 100644
index 0000000..5d8e124
--- /dev/null
+++ b/kexec/arch/arm64/kexec-elf-arm64.c
@@ -0,0 +1,129 @@
+/*
+ * ARM64 kexec elf support.
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <libfdt.h>
+
+#include <linux/elf.h>
+
+#include "dt-ops.h"
+#include "crashdump-arm64.h"
+#include "kexec-arm64.h"
+#include "fs2dt.h"
+#include "kexec-syscall.h"
+#include "arch/options.h"
+
+#ifndef EM_AARCH64
+#define EM_AARCH64 183
+#define R_AARCH64_ABS64 257
+#endif
+
+
+int elf_arm64_probe(const char *kernel_buf, off_t kernel_size)
+{
+ int result;
+ struct mem_ehdr ehdr;
+
+ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0);
+
+ if (result < 0) {
+ dbgprintf("%s: Not an ELF executable.\n", __func__);
+ goto on_exit;
+ }
+
+ if (ehdr.e_machine != EM_AARCH64) {
+ dbgprintf("%s: Not an AARCH64 ELF executable.\n", __func__);
+ result = -EINVAL;
+ goto on_exit;
+ }
+
+ result = 0;
+
+on_exit:
+ free_elf_info(&ehdr);
+ return result;
+}
+
+int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
+ off_t kernel_size, struct kexec_info *info)
+{
+ int result;
+ struct mem_ehdr ehdr;
+ bool found_header;
+ int i;
+
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ fprintf(stderr, "kexec: kdump not yet supported on arm64\n");
+ return -EINVAL;
+ }
+
+ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0);
+
+ if (result < 0) {
+ dbgprintf("%s: build_elf_exec_info failed\n", __func__);
+ goto exit;
+ }
+
+ /* Find and process the arm64 image header. */
+
+ for (i = 0, found_header = false; i < ehdr.e_phnum; i++) {
+ struct mem_phdr *phdr = &ehdr.e_phdr[i];
+ const struct arm64_image_header *h;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ h = (const struct arm64_image_header *)(kernel_buf
+ + phdr->p_offset);
+
+ if (arm64_process_image_header(h))
+ continue;
+
+ found_header = true;
+
+ arm64_mem.page_offset = phdr->p_vaddr - arm64_mem.text_offset;
+
+ dbgprintf("%s: PE format: %s\n", __func__,
+ (arm64_header_check_pe_sig(h) ? "yes" : "no"));
+ dbgprintf("p_vaddr: %016llx\n", phdr->p_vaddr);
+
+ break;
+ }
+
+ if (!found_header) {
+ fprintf(stderr, "kexec: Bad arm64 image header.\n");
+ result = -EINVAL;
+ goto exit;
+ }
+
+ result = elf_exec_load(&ehdr, info);
+
+ if (result) {
+ fprintf(stderr, "kexec: Elf load failed.\n");
+ goto exit;
+ }
+
+ dbgprintf("%s: text_offset: %016lx\n", __func__, arm64_mem.text_offset);
+ dbgprintf("%s: image_size: %016lx\n", __func__, arm64_mem.image_size);
+ dbgprintf("%s: page_offset: %016lx\n", __func__, arm64_mem.page_offset);
+ dbgprintf("%s: memstart: %016lx\n", __func__, arm64_mem.memstart);
+ dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__,
+ ehdr.e_entry, virt_to_phys(ehdr.e_entry));
+
+ result = arm64_load_other_segments(info, virt_to_phys(ehdr.e_entry));
+exit:
+ free_elf_info(&ehdr);
+ return result;
+}
+
+void elf_arm64_usage(void)
+{
+ printf(
+" An arm64 ELF file, big or little endian.\n"
+" Typically vmlinux or a stripped version of vmlinux.\n\n");
+}