Signed-off-by: AKASHI Takahiro <[email protected]>
---
 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


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to