Blame SOURCES/kexec-tools-2.0.14-arm64-kdump-set-up-kernel-image-segment.patch

766e0d
From af338a51df9012f1b1dca87ddd27a5c66db5b80b Mon Sep 17 00:00:00 2001
766e0d
Message-Id: <af338a51df9012f1b1dca87ddd27a5c66db5b80b.1489676829.git.panand@redhat.com>
766e0d
In-Reply-To: <f85183096d31d865c97565614535d84943b12908.1489676829.git.panand@redhat.com>
766e0d
References: <f85183096d31d865c97565614535d84943b12908.1489676829.git.panand@redhat.com>
766e0d
From: AKASHI Takahiro <takahiro.akashi@linaro.org>
766e0d
Date: Wed, 15 Mar 2017 18:38:21 +0900
766e0d
Subject: [PATCH 07/10] arm64: kdump: set up kernel image segment
766e0d
766e0d
On arm64, we can use the same kernel image as 1st kernel, but
766e0d
we have to modify the entry point as well as segments' addresses
766e0d
in the kernel's elf header in order to load them into correct places.
766e0d
766e0d
Minor conflicts was resolved in kexec/arch/arm64/crashdump-arm64.c because
766e0d
get_crash_kernel_load_range() is not yet backported.
766e0d
766e0d
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
766e0d
---
766e0d
 kexec/arch/arm64/crashdump-arm64.c | 23 +++++++++++++++++++++++
766e0d
 kexec/arch/arm64/crashdump-arm64.h |  1 +
766e0d
 kexec/arch/arm64/kexec-arm64.c     | 25 ++++++++++++++++++++-----
766e0d
 kexec/arch/arm64/kexec-elf-arm64.c | 10 +++++++++-
766e0d
 4 files changed, 53 insertions(+), 6 deletions(-)
766e0d
766e0d
diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c
766e0d
index 83461312d412..9517329e1086 100644
766e0d
--- a/kexec/arch/arm64/crashdump-arm64.c
766e0d
+++ b/kexec/arch/arm64/crashdump-arm64.c
766e0d
@@ -213,3 +213,26 @@ int load_crashdump_segments(struct kexec_info *info)
766e0d
 
766e0d
 	return 0;
766e0d
 }
766e0d
+
766e0d
+/*
766e0d
+ * e_entry and p_paddr are actually in virtual address space.
766e0d
+ * Those values will be translated to physcal addresses by
766e0d
+ * using virt_to_phys().
766e0d
+ * So let's get ready for later use so the memory base (phys_offset)
766e0d
+ * will be correctly replaced with crash_reserved_mem.start.
766e0d
+ */
766e0d
+void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr)
766e0d
+{
766e0d
+	struct mem_phdr *phdr;
766e0d
+	int i;
766e0d
+
766e0d
+	ehdr->e_entry += - arm64_mem.phys_offset + crash_reserved_mem.start;
766e0d
+
766e0d
+	for (i = 0; i < ehdr->e_phnum; i++) {
766e0d
+		phdr = &ehdr->e_phdr[i];
766e0d
+		if (phdr->p_type != PT_LOAD)
766e0d
+			continue;
766e0d
+		phdr->p_paddr +=
766e0d
+			(-arm64_mem.phys_offset + crash_reserved_mem.start);
766e0d
+	}
766e0d
+}
766e0d
diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h
766e0d
index da75a2d0c5f1..382f57154f2a 100644
766e0d
--- a/kexec/arch/arm64/crashdump-arm64.h
766e0d
+++ b/kexec/arch/arm64/crashdump-arm64.h
766e0d
@@ -21,5 +21,6 @@ extern struct memory_range crash_reserved_mem;
766e0d
 extern struct memory_range elfcorehdr_mem;
766e0d
 
766e0d
 extern int load_crashdump_segments(struct kexec_info *info);
766e0d
+extern void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr);
766e0d
 
766e0d
 #endif /* CRASHDUMP_ARM64_H */
766e0d
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
766e0d
index d02b9dac3d33..5a1da2ec1a34 100644
766e0d
--- a/kexec/arch/arm64/kexec-arm64.c
766e0d
+++ b/kexec/arch/arm64/kexec-arm64.c
766e0d
@@ -307,12 +307,27 @@ unsigned long arm64_locate_kernel_segment(struct kexec_info *info)
766e0d
 {
766e0d
 	unsigned long hole;
766e0d
 
766e0d
-	hole = locate_hole(info,
766e0d
-		arm64_mem.text_offset + arm64_mem.image_size,
766e0d
-		MiB(2), 0, ULONG_MAX, 1);
766e0d
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
766e0d
+		unsigned long hole_end;
766e0d
+
766e0d
+		hole = (crash_reserved_mem.start < mem_min ?
766e0d
+				mem_min : crash_reserved_mem.start);
766e0d
+		hole = _ALIGN_UP(hole, MiB(2));
766e0d
+		hole_end = hole + arm64_mem.text_offset + arm64_mem.image_size;
766e0d
+
766e0d
+		if ((hole_end > mem_max) ||
766e0d
+		    (hole_end > crash_reserved_mem.end)) {
766e0d
+			dbgprintf("%s: Crash kernel out of range\n", __func__);
766e0d
+			hole = ULONG_MAX;
766e0d
+		}
766e0d
+	} else {
766e0d
+		hole = locate_hole(info,
766e0d
+			arm64_mem.text_offset + arm64_mem.image_size,
766e0d
+			MiB(2), 0, ULONG_MAX, 1);
766e0d
 
766e0d
-	if (hole == ULONG_MAX)
766e0d
-		dbgprintf("%s: locate_hole failed\n", __func__);
766e0d
+		if (hole == ULONG_MAX)
766e0d
+			dbgprintf("%s: locate_hole failed\n", __func__);
766e0d
+	}
766e0d
 
766e0d
 	return hole;
766e0d
 }
766e0d
diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c
766e0d
index c70a37ae7732..842ce21e2387 100644
766e0d
--- a/kexec/arch/arm64/kexec-elf-arm64.c
766e0d
+++ b/kexec/arch/arm64/kexec-elf-arm64.c
766e0d
@@ -9,6 +9,7 @@
766e0d
 #include <stdlib.h>
766e0d
 #include <linux/elf.h>
766e0d
 
766e0d
+#include "crashdump-arm64.h"
766e0d
 #include "kexec-arm64.h"
766e0d
 #include "kexec-elf.h"
766e0d
 #include "kexec-syscall.h"
766e0d
@@ -105,7 +106,8 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
766e0d
 	}
766e0d
 
766e0d
 	arm64_mem.vp_offset = _ALIGN_DOWN(ehdr.e_entry, MiB(2));
766e0d
-	arm64_mem.vp_offset -= kernel_segment - get_phys_offset();
766e0d
+	if (!(info->kexec_flags & KEXEC_ON_CRASH))
766e0d
+		arm64_mem.vp_offset -= kernel_segment - get_phys_offset();
766e0d
 
766e0d
 	dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment);
766e0d
 	dbgprintf("%s: text_offset:    %016lx\n", __func__,
766e0d
@@ -127,6 +129,12 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
766e0d
 								__func__);
766e0d
 			goto exit;
766e0d
 		}
766e0d
+
766e0d
+		/*
766e0d
+		 * offset addresses in order to fit vmlinux
766e0d
+		 * (elf_exec) into crash kernel's memory
766e0d
+		 */
766e0d
+		modify_ehdr_for_crashdump(&ehdr);
766e0d
 	}
766e0d
 
766e0d
 	/* load the kernel */
766e0d
-- 
766e0d
2.9.3
766e0d