All of lore.kernel.org
 help / color / mirror / Atom feed
From: Varad Gautam <vrd@amazon.de>
To: kexec@lists.infradead.org
Cc: Varad Gautam <vrd@amazon.de>, David Woodhouse <dwmw@amazon.co.uk>
Subject: [PATCH 2/3] elf: Support ELF loading with relocation
Date: Tue, 21 May 2019 09:32:27 +0200	[thread overview]
Message-ID: <1558423948-24583-2-git-send-email-vrd@amazon.de> (raw)
In-Reply-To: <1558423948-24583-1-git-send-email-vrd@amazon.de>

Add a helper to allow loading an image within specified address range.
This will be used to load multiboot2 images later.

Signed-off-by: Varad Gautam <vrd@amazon.de>
---
 kexec/kexec-elf-exec.c | 199 +++++++++++++++++++++++++++++++++----------------
 kexec/kexec-elf.h      |   7 ++
 2 files changed, 141 insertions(+), 65 deletions(-)

diff --git a/kexec/kexec-elf-exec.c b/kexec/kexec-elf-exec.c
index a9329ac..bea7b3e 100644
--- a/kexec/kexec-elf-exec.c
+++ b/kexec/kexec-elf-exec.c
@@ -11,6 +11,84 @@
 
 static const int probe_debug = 0;
 
+static void load_elf_segments(struct mem_ehdr *ehdr, struct kexec_info *info, unsigned long base)
+{
+	size_t i;
+
+	/* Read in the PT_LOAD segments */
+	for(i = 0; i < ehdr->e_phnum; i++) {
+		struct mem_phdr *phdr;
+		size_t size;
+		phdr = &ehdr->e_phdr[i];
+		if (phdr->p_type != PT_LOAD) {
+			continue;
+		}
+		size = phdr->p_filesz;
+		if (size > phdr->p_memsz) {
+			size = phdr->p_memsz;
+		}
+		add_segment(info, phdr->p_data, size,
+					phdr->p_paddr + base, phdr->p_memsz);
+	}
+}
+
+static int get_elf_exec_load_base(struct mem_ehdr *ehdr, struct kexec_info *info,
+				  unsigned long min, unsigned long max,
+				  unsigned long align, unsigned long *base)
+{
+	unsigned long first, last;
+	size_t i;
+
+	/* Note on arm64:
+	 * arm64's vmlinux has virtual address in physical address
+	 * field of PT_LOAD segments. So the following validity check
+	 * and relocation makes no sense on arm64.
+	 */
+	if (ehdr->e_machine == EM_AARCH64)
+		return 0;
+
+	first = ULONG_MAX;
+	last  = 0;
+	for(i = 0; i < ehdr->e_phnum; i++) {
+		unsigned long start, stop;
+		struct mem_phdr *phdr;
+		phdr = &ehdr->e_phdr[i];
+		if ((phdr->p_type != PT_LOAD) ||
+			(phdr->p_memsz == 0))
+		{
+			continue;
+		}
+		start = phdr->p_paddr;
+		stop  = start + phdr->p_memsz;
+		if (first > start) {
+			first = start;
+		}
+		if (last < stop) {
+			last = stop;
+		}
+		if (align < phdr->p_align) {
+			align = phdr->p_align;
+		}
+	}
+
+	if ((max - min) < (last - first))
+		return -1;
+
+	if (!valid_memory_range(info, min > first ? min : first, max < last ? max : last)) {
+		unsigned long hole;
+		hole = locate_hole(info, last - first + 1, align, min, max, 1);
+		if (hole == ULONG_MAX)
+			return -1;
+
+		/* Base is the value that when added
+		 * to any virtual address in the file
+		 * yields it's load virtual address.
+		 */
+		*base = hole - first;
+	}
+	return 0;
+}
+
 int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
 				uint32_t flags)
 {
@@ -53,7 +131,6 @@ int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info)
 {
 	unsigned long base;
 	int result;
-	size_t i;
 
 	if (!ehdr->e_phdr) {
 		fprintf(stderr, "No program header?\n");
@@ -63,75 +140,48 @@ int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info)
 
 	/* If I have a dynamic executable find it's size
 	 * and then find a location for it in memory.
-	 * Note on arm64:
-	 * arm64's vmlinux has virtual address in physical address
-	 * field of PT_LOAD segments. So the following validity check
-	 * and relocation makes no sense on arm64.
 	 */
 	base = 0;
-	if ((ehdr->e_machine != EM_AARCH64) && (ehdr->e_type == ET_DYN)) {
-		unsigned long first, last, align;
-		first = ULONG_MAX;
-		last  = 0;
-		align = 0;
-		for(i = 0; i < ehdr->e_phnum; i++) {
-			unsigned long start, stop;
-			struct mem_phdr *phdr;
-			phdr = &ehdr->e_phdr[i];
-			if ((phdr->p_type != PT_LOAD) ||
-				(phdr->p_memsz == 0))
-			{
-				continue;
-			}
-			start = phdr->p_paddr;
-			stop  = start + phdr->p_memsz;
-			if (first > start) {
-				first = start;
-			}
-			if (last < stop) {
-				last = stop;
-			}
-			if (align < phdr->p_align) {
-				align = phdr->p_align;
-			}
-		}
-		/* If I can't use the default paddr find a new
-		 * hole for the dynamic executable.
-		 */
-		if (!valid_memory_range(info, first, last)) {
-			unsigned long hole;
-			hole = locate_hole(info,
-				last - first + 1, align, 
-				0, elf_max_addr(ehdr), 1);
-			if (hole == ULONG_MAX) {
-				result = -1;
-				goto out;
-			}
-			/* Base is the value that when added
-			 * to any virtual address in the file
-			 * yields it's load virtual address.
-			 */
-			base = hole - first;
-		}
-
+	if (ehdr->e_type == ET_DYN) {
+		result = get_elf_exec_load_base(ehdr, info, 0, elf_max_addr(ehdr), 0 /* align */, &base);
+		if (result < 0)
+			goto out;
 	}
 
-	/* Read in the PT_LOAD segments */
-	for(i = 0; i < ehdr->e_phnum; i++) {
-		struct mem_phdr *phdr;
-		size_t size;
-		phdr = &ehdr->e_phdr[i];
-		if (phdr->p_type != PT_LOAD) {
-			continue;
-		}
-		size = phdr->p_filesz;
-		if (size > phdr->p_memsz) {
-			size = phdr->p_memsz;
-		}
-		add_segment(info,
-			phdr->p_data, size,
-			phdr->p_paddr + base, phdr->p_memsz);
+	load_elf_segments(ehdr, info, base);
+
+	/* Update entry point to reflect new load address*/
+	ehdr->e_entry += base;
+
+	result = 0;
+ out:
+	return result;
+}
+
+int elf_exec_load_relocatable(struct mem_ehdr *ehdr, struct kexec_info *info,
+			      unsigned long reloc_min, unsigned long reloc_max,
+			      unsigned long align)
+{
+	unsigned long base;
+	int result;
+
+	if (reloc_min > reloc_max) {
+		fprintf(stderr, "Bad relocation range, start=%lux > end=%lux.\n", reloc_min, reloc_max);
+		result = -1;
+		goto out;
 	}
+	if (!ehdr->e_phdr) {
+		fprintf(stderr, "No program header?\n");
+		result = -1;
+		goto out;
+	}
+
+	base = 0;
+	result = get_elf_exec_load_base(ehdr, info, reloc_min, reloc_max, align, &base);
+	if (result < 0)
+		goto out;
+
+	load_elf_segments(ehdr, info, base);
 
 	/* Update entry point to reflect new load address*/
 	ehdr->e_entry += base;
@@ -157,3 +207,22 @@ void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
 		die("ELF exec load failed\n");
 	}
 }
+
+void elf_exec_build_load_relocatable(struct kexec_info *info, struct mem_ehdr *ehdr,
+				     const char *buf, off_t len, uint32_t flags,
+				     unsigned long reloc_min, unsigned long reloc_max,
+				     unsigned long align)
+{
+	int result;
+	/* Parse the Elf file */
+	result = build_elf_exec_info(buf, len, ehdr, flags);
+	if (result < 0) {
+		die("%s: ELF exec parse failed\n", __func__);
+	}
+
+	/* Load the Elf data */
+	result = elf_exec_load_relocatable(ehdr, info, reloc_min, reloc_max, align);
+	if (result < 0) {
+		die("%s: ELF exec load failed\n", __func__);
+	}
+}
\ No newline at end of file
diff --git a/kexec/kexec-elf.h b/kexec/kexec-elf.h
index 1164db4..1e512c8 100644
--- a/kexec/kexec-elf.h
+++ b/kexec/kexec-elf.h
@@ -100,11 +100,18 @@ extern int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
 extern int build_elf_core_info(const char *buf, off_t len,
 					struct mem_ehdr *ehdr, uint32_t flags);
 extern int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info);
+extern int elf_exec_load_relocatable(struct mem_ehdr *ehdr, struct kexec_info *info,
+				     unsigned long reloc_min, unsigned long reloc_max,
+				     unsigned long align);
 extern int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
 	unsigned long min, unsigned long max, int end);
 
 extern void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
 				const char *buf, off_t len, uint32_t flags);
+extern void elf_exec_build_load_relocatable(struct kexec_info *info, struct mem_ehdr *ehdr,
+					    const char *buf, off_t len, uint32_t flags,
+					    unsigned long reloc_min, unsigned long reloc_max,
+					    unsigned long align);
 extern void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
 	const char *buf, off_t len, unsigned long min, unsigned long max, 
 	int end, uint32_t flags);
-- 
2.7.4




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrer: Christian Schlaeger, Ralf Herbrich
Ust-ID: DE 289 237 879
Eingetragen am Amtsgericht Charlottenburg HRB 149173 B



_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

  reply	other threads:[~2019-05-21  7:33 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-21  7:32 [PATCH 1/3] xen: Avoid overlapping segments in low memory Varad Gautam
2019-05-21  7:32 ` Varad Gautam [this message]
2019-06-25  8:11   ` [PATCH 2/3 RESEND] elf: Support ELF loading with relocation Varad Gautam
2019-05-21  7:32 ` [PATCH 3/3] x86: Support multiboot2 images Varad Gautam
2019-05-31  9:22   ` Simon Horman
2019-06-24 18:59   ` [PATCH v2] " Varad Gautam
2019-05-31  9:07 ` [PATCH 1/3] xen: Avoid overlapping segments in low memory Simon Horman
2019-06-24 19:02   ` vrd

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1558423948-24583-2-git-send-email-vrd@amazon.de \
    --to=vrd@amazon.de \
    --cc=dwmw@amazon.co.uk \
    --cc=kexec@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.