[PATCH 2/4] add basic ELF parser

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This parser is needed for kernel boot support on MIPS
and can potentially reused on other platforms.

Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
---
 common/Makefile |   1 +
 common/elf.c    | 146 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/elf.h   |  10 ++++
 3 files changed, 157 insertions(+)
 create mode 100644 common/elf.c

diff --git a/common/Makefile b/common/Makefile
index 1ff7d2370..4fe7eaaf6 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -8,6 +8,7 @@ obj-y				+= misc.o
 obj-pbl-y			+= memsize.o
 obj-y				+= resource.o
 obj-y				+= bootsource.o
+obj-y				+= elf.o
 obj-y				+= restart.o
 obj-y				+= poweroff.o
 obj-$(CONFIG_AUTO_COMPLETE)	+= complete.o
diff --git a/common/elf.c b/common/elf.c
new file mode 100644
index 000000000..d6a1f8b6a
--- /dev/null
+++ b/common/elf.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
+ */
+
+#include <common.h>
+#include <elf.h>
+#include <memory.h>
+
+struct elf_section {
+	struct list_head list;
+	struct resource *r;
+};
+
+static int elf_request_region(struct elf_image *elf, resource_size_t start,
+			      resource_size_t size)
+{
+	struct list_head *list = &elf->list;
+	struct resource *r_new;
+	struct elf_section *r;
+
+	r = xzalloc(sizeof(*r));
+	r_new = request_sdram_region("elf_section", start, size);
+	if (!r_new) {
+		pr_err("Failed to request region: %x %x\n", start, size);
+		return -EINVAL;
+	}
+
+	r->r = r_new;
+	list_add_tail(&r->list, list);
+
+	return 0;
+}
+
+static void elf_release_regions(struct elf_image *elf)
+{
+	struct list_head *list = &elf->list;
+	struct elf_section *r, *r_tmp;
+
+	list_for_each_entry_safe(r, r_tmp, list, list) {
+		release_sdram_region(r->r);
+		free(r);
+	}
+}
+
+
+static int load_elf_phdr_segment(struct elf_image *elf, void *src,
+				 Elf32_Phdr *phdr)
+{
+	void *dst = (void *)phdr->p_paddr;
+	int ret;
+
+	/* we care only about PT_LOAD segments */
+	if (phdr->p_type != PT_LOAD)
+		return 0;
+
+	if (!phdr->p_filesz)
+		return 0;
+
+	pr_debug("Loading phdr to 0x%p (%i bytes)\n", dst, phdr->p_filesz);
+
+	ret = elf_request_region(elf, (resource_size_t)dst, phdr->p_filesz);
+	if (ret)
+		return ret;
+
+	memcpy(dst, src, phdr->p_filesz);
+
+	if (phdr->p_filesz < phdr->p_memsz)
+		memset(dst + phdr->p_filesz, 0x00,
+		       phdr->p_memsz - phdr->p_filesz);
+
+	return 0;
+}
+
+static int load_elf_image_phdr(struct elf_image *elf)
+{
+	void *buf = elf->buf;
+	Elf32_Ehdr *ehdr = buf;
+	Elf32_Phdr *phdr = (Elf32_Phdr *)(buf + ehdr->e_phoff);
+	int i, ret;
+
+	elf->entry = ehdr->e_entry;
+
+	for (i = 0; i < ehdr->e_phnum; ++i) {
+		void *src = buf + phdr->p_offset;
+
+		ret = load_elf_phdr_segment(elf, src, phdr);
+		/* in case of error elf_load_image() caller should clean up and
+		 * call elf_release_image() */
+		if (ret)
+			return ret;
+
+		++phdr;
+	}
+
+	return 0;
+}
+
+static int elf_check_image(void *buf)
+{
+	Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buf;
+
+	if (strncmp(buf, ELFMAG, SELFMAG)) {
+		pr_err("ELF magic not found.\n");
+                return -EINVAL;
+        }
+
+	if (ehdr->e_type != ET_EXEC) {
+		pr_err("Non EXEC ELF image.\n");
+                return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+struct elf_image *elf_load_image(void *buf)
+{
+	struct elf_image *elf;
+	int ret;
+
+	elf = xzalloc(sizeof(*elf));
+
+	INIT_LIST_HEAD(&elf->list);
+
+	elf->buf = buf;
+
+	ret = elf_check_image(buf);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = load_elf_image_phdr(elf);
+	if (ret) {
+		elf_release_image(elf);
+		return ERR_PTR(ret);
+	}
+
+	return elf;
+}
+
+void elf_release_image(struct elf_image *elf)
+{
+	elf_release_regions(elf);
+
+	free(elf->buf);
+	free(elf);
+}
diff --git a/include/elf.h b/include/elf.h
index ebcec7db0..92c8d9c12 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -2,6 +2,7 @@
 #define _LINUX_ELF_H
 
 #include <linux/types.h>
+#include <linux/list.h>
 //#include <linux/auxvec.h>
 //#include <linux/elf-em.h>
 #include <asm/elf.h>
@@ -397,4 +398,13 @@ static inline void arch_write_notes(struct file *file) { }
 #define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file)
 #endif /* ARCH_HAVE_EXTRA_ELF_NOTES */
 
+struct elf_image {
+	struct list_head list;
+	unsigned long entry;
+	void *buf;
+};
+
+struct elf_image *elf_load_image(void *buf);
+void elf_release_image(struct elf_image *elf);
+
 #endif /* _LINUX_ELF_H */
-- 
2.17.1


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



[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux