[PATCH 1/2] fixup! arm64: Add arm64 kexec support
AKASHI Takahiro
takahiro.akashi at linaro.org
Mon Aug 29 01:28:40 PDT 2016
Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
---
kexec/arch/arm64/kexec-arm64.c | 22 +++++++++--
kexec/arch/arm64/kexec-arm64.h | 1 +
kexec/arch/arm64/kexec-elf-arm64.c | 79 ++++++++++++++++++++++----------------
3 files changed, 64 insertions(+), 38 deletions(-)
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
index be3f964..253affa 100644
--- a/kexec/arch/arm64/kexec-arm64.c
+++ b/kexec/arch/arm64/kexec-arm64.c
@@ -300,16 +300,30 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line)
return result;
}
+unsigned long arm64_locate_kernel_segment(struct kexec_info *info)
+{
+ unsigned long image_base;
+
+ image_base = locate_hole(info,
+ arm64_mem.text_offset + arm64_mem.image_size,
+ MiB(2), 0, ULONG_MAX, 1);
+ if (image_base == ULONG_MAX) {
+ dbgprintf("%s: locate_hole failed\n", __func__);
+ }
+
+ return image_base;
+}
+
/**
* arm64_load_other_segments - Prepare the dtb, initrd and purgatory segments.
*/
int arm64_load_other_segments(struct kexec_info *info,
- uint64_t kernel_entry)
+ unsigned long kernel_entry)
{
int result;
- uint64_t dtb_base;
- uint64_t image_base;
+ unsigned long dtb_base;
+ unsigned long image_base;
unsigned long hole_min;
unsigned long hole_max;
char *initrd_buf = NULL;
@@ -343,7 +357,7 @@ int arm64_load_other_segments(struct kexec_info *info,
/* Put the other segments after the image. */
- image_base = arm64_mem.phys_offset + arm64_mem.text_offset;
+ image_base = kernel_entry;
hole_min = image_base + arm64_mem.image_size;
hole_max = ULONG_MAX;
diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h
index c40e383..e4bc6d0 100644
--- a/kexec/arch/arm64/kexec-arm64.h
+++ b/kexec/arch/arm64/kexec-arm64.h
@@ -64,6 +64,7 @@ static inline void set_phys_offset(uint64_t v)
}
int arm64_process_image_header(const struct arm64_image_header *h);
+unsigned long arm64_locate_kernel_segment(struct kexec_info *info);
int arm64_load_other_segments(struct kexec_info *info,
uint64_t kernel_entry);
diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c
index 2635d29..18aca3c 100644
--- a/kexec/arch/arm64/kexec-elf-arm64.c
+++ b/kexec/arch/arm64/kexec-elf-arm64.c
@@ -5,6 +5,7 @@
#define _GNU_SOURCE
#include <errno.h>
+#include <limits.h>
#include <stdlib.h>
#include <linux/elf.h>
@@ -42,6 +43,8 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
struct mem_ehdr ehdr;
int result;
int i;
+ const struct arm64_image_header *h = NULL;
+ unsigned long image_base;
if (info->kexec_flags & KEXEC_ON_CRASH) {
fprintf(stderr, "kexec: kdump not yet supported on arm64\n");
@@ -59,7 +62,6 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
for (i = 0; i < ehdr.e_phnum; i++) {
struct mem_phdr *phdr = &ehdr.e_phdr[i];
- const struct arm64_image_header *h;
unsigned long header_offset;
if (phdr->p_type != PT_LOAD)
@@ -76,45 +78,54 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
h = (const struct arm64_image_header *)(
kernel_buf + phdr->p_offset + header_offset);
- if (arm64_process_image_header(h))
- continue;
+ if (!arm64_process_image_header(h)) {
+ dbgprintf("%s: e_entry: %016llx\n", __func__,
+ ehdr.e_entry);
+ dbgprintf("%s: p_vaddr: %016llx\n", __func__,
+ phdr->p_vaddr);
+ dbgprintf("%s: header_offset: %016lx\n", __func__,
+ header_offset);
- arm64_mem.vp_offset = ehdr.e_entry - arm64_mem.text_offset;
-
- dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__,
- ehdr.e_entry,
- virt_to_phys(ehdr.e_entry));
- dbgprintf("%s: p_vaddr: %016llx -> %016lx\n", __func__,
- phdr->p_vaddr,
- virt_to_phys(phdr->p_vaddr));
- dbgprintf("%s: header_offset: %016lx\n", __func__,
- header_offset);
- dbgprintf("%s: text_offset: %016lx\n", __func__,
- arm64_mem.text_offset);
- dbgprintf("%s: image_size: %016lx\n", __func__,
- arm64_mem.image_size);
- dbgprintf("%s: phys_offset: %016lx\n", __func__,
- arm64_mem.phys_offset);
- dbgprintf("%s: vp_offset: %016lx\n", __func__,
- arm64_mem.vp_offset);
- dbgprintf("%s: PE format: %s\n", __func__,
- (arm64_header_check_pe_sig(h) ? "yes" : "no"));
-
- result = elf_exec_load(&ehdr, info);
-
- if (result) {
- dbgprintf("%s: elf_exec_load failed\n", __func__);
- goto exit;
+ break;
}
+ }
+ if (i == ehdr.e_phnum) {
+ dbgprintf("%s: Valid arm64 header not found\n", __func__);
+ result = -EFAILED;
+ goto exit;
+ }
+
+ image_base = arm64_locate_kernel_segment(info);
+ if (image_base == ULONG_MAX) {
+ dbgprintf("%s: Kernel segment is not allocated\n", __func__);
+ result = -EFAILED;
+ goto exit;
+ }
- result = arm64_load_other_segments(info,
- virt_to_phys(ehdr.e_entry));
+ arm64_mem.vp_offset = _ALIGN_DOWN(ehdr.e_entry, MiB(2));
+ arm64_mem.vp_offset -= image_base - get_phys_offset();
+
+ dbgprintf("%s: image_base: %016lx\n", __func__, image_base);
+ dbgprintf("%s: text_offset: %016lx\n", __func__,
+ arm64_mem.text_offset);
+ dbgprintf("%s: image_size: %016lx\n", __func__,
+ arm64_mem.image_size);
+ dbgprintf("%s: phys_offset: %016lx\n", __func__,
+ arm64_mem.phys_offset);
+ dbgprintf("%s: vp_offset: %016lx\n", __func__,
+ arm64_mem.vp_offset);
+ dbgprintf("%s: PE format: %s\n", __func__,
+ (arm64_header_check_pe_sig(h) ? "yes" : "no"));
+
+ /* load the kernel */
+ result = elf_exec_load(&ehdr, info);
+ if (result) {
+ dbgprintf("%s: elf_exec_load failed\n", __func__);
goto exit;
}
- dbgprintf("%s: Bad arm64 image header\n", __func__);
- result = -EFAILED;
- goto exit;
+ result = arm64_load_other_segments(info,
+ image_base + arm64_mem.text_offset);
exit:
reset_vp_offset();
--
2.9.0
More information about the kexec
mailing list