Re: [PATCH] Support for booting ELF images.

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

 



I had not seen that patch series. It doesn't seem to have been checked in, are you still working on it? kexec seems like a really fancy method of loading the images, but it seems like quite a large patch set just to support another image format. I guess this means that kexec would need to be added for any other architectures that want to boot from an ELF image.

I'm afraid I am guilty as charged of following the U-boot practice, that's where I got the initial idea from, I'll look at reworking my changes to use bootm instead.

Thanks,
Owen

On 14-06-26 03:06 PM, Antony Pavlov wrote:
On Thu, 26 Jun 2014 14:11:32 -0700
Owen Kirby <osk@xxxxxxxxxx> wrote:

Have you seen the '[RFC 00/10] MIPS: use kexec to load ELF linux images' series?
    http://lists.infradead.org/pipermail/barebox/2014-April/018651.html

This series is kexec-based so it has relocator.
The relocator make it possible to load ELF files that overlap current barebox adresses.

Also there is no need to add new 'bootelf' command for new file format support.
Adding new command for every new file format or new hardware interface is vicious U-boot practice.
In barebox we already have the 'filetype' mechanism for supporting new file formats, so
we can load ELF files using conventional 'bootm' command.

 From 1edc77c7b960d5b42ac3c03000ac5063018195f9 Mon Sep 17 00:00:00 2001
From: Owen Kirby <osk@xxxxxxxxxx>
Date: Thu, 26 Jun 2014 13:40:06 -0700
Subject: [PATCH] Support for booting ELF images.

This patch adds a bootelf command to load and execute OS kernels from the ELF format.

Signed-off-by: Owen Kirby <osk@xxxxxxxxxx>
---
  commands/Kconfig   |    7 ++
  commands/Makefile  |    1 +
  commands/bootelf.c |  112 ++++++++++++++++++++++++++
  common/Kconfig     |    3 +
  common/Makefile    |    1 +
  common/elf.c       |  222 ++++++++++++++++++++++++++++++++++++++++++++++++++++
  common/filetype.c  |    3 +
  include/elf.h      |    4 +
  include/filetype.h |    1 +
  9 files changed, 354 insertions(+)
  create mode 100644 commands/bootelf.c
  create mode 100644 common/elf.c

diff --git a/commands/Kconfig b/commands/Kconfig
index cc014f3..c4e4649 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -507,6 +507,13 @@ config CMD_BOOTU
  	  compile in the 'bootu' command to start raw (uncompressed)
  	  Linux images
+config CMD_BOOTELF
+	select ELF
+	tristate
+	prompt "elf"
+	help
+	  compile the 'bootelf' command to start ELF images
+
  config FLEXIBLE_BOOTARGS
  	bool
  	prompt "flexible Linux bootargs generation"
diff --git a/commands/Makefile b/commands/Makefile
index e463031..fd57811 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -1,5 +1,6 @@
  obj-$(CONFIG_STDDEV)		+= stddev.o
  obj-$(CONFIG_CMD_BOOTM)		+= bootm.o
+obj-$(CONFIG_CMD_BOOTELF)	+= bootelf.o
  obj-$(CONFIG_CMD_UIMAGE)	+= uimage.o
  obj-$(CONFIG_CMD_LINUX16)	+= linux16.o
  obj-$(CONFIG_CMD_LOADB)		+= loadb.o
diff --git a/commands/bootelf.c b/commands/bootelf.c
new file mode 100644
index 0000000..dc38b9e
--- /dev/null
+++ b/commands/bootelf.c
@@ -0,0 +1,112 @@
+/*
+ * bootelf.c - ELF booting code
+ *
+ * Copyright (c) 2014 Owen Kirby <osk@xxxxxxxxxx>, Exegin Technologies Limited
+ *
+ * partly based on U-Boot ELF code.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <fs.h>
+#include <elf.h>
+
+static int do_readelf(int argc, char *argv[])
+{
+	void *hdr;
+	int fd;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		printf("could not open: %s\n", errno_str());
+		return 1;
+	}
+	hdr = elf_load_header(fd);
+	if (!hdr) {
+		close(fd);
+		return 1;
+	}
+	elf_print_header(hdr);
+	free(hdr);
+	close(fd);
+	return 0;
+}
+
+BAREBOX_CMD_START(readelf)
+	.cmd		= do_readelf,
+	.usage		= "Read an ELF image header",
+BAREBOX_CMD_END
+
+static int do_bootelf(int argc, char *argv[])
+{
+	void 	*hdr;
+	void 	*addr;
+	int	(*func)(int argc, char *argv[]);
+	int	fd;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		printf("could not open: %s\n", errno_str());
+		return 1;
+	}
+
+	/* Print the ELF header for the user. */
+	hdr = elf_load_header(fd);
+	if (!hdr) {
+		close(fd);
+		return 1;
+	}
+	elf_print_header(hdr);
+	free(hdr);
+
+	/* Load the ELF sections. */
+	addr = elf_load_sections(fd);
+	if (!addr) {
+		close(fd);
+		return 1;
+	}
+
+	/* Launch the application */
+	printf("## Starting application at 0x%p ...\n", addr);
+	console_flush();
+	func = addr;
+	shutdown_barebox();
+
+	if (do_execute)
+		do_execute(func, argc - 1, &argv[1]);
+	else
+		func(argc - 1, &argv[1]);
+
+	/*
+	 * The application returned. Since we have shutdown barebox and
+	 * we know nothing about the state of the cpu/memory we can't
+	 * do anything here.
+	 */
+	while (1);
+	return 0;
+}
+
+BAREBOX_CMD_START(bootelf)
+	.cmd		= do_bootelf,
+	.usage		= "Boot an ELF image",
+BAREBOX_CMD_END
+
diff --git a/common/Kconfig b/common/Kconfig
index 0031cc8..0d22a58 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -53,6 +53,9 @@ config UIMAGE
  	select CRC32
  	bool
+config ELF
+	bool
+
  config GLOBALVAR
  	bool
diff --git a/common/Makefile b/common/Makefile
index 204241c..9decc96 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_CONSOLE_FULL)	+= console.o
  obj-$(CONFIG_CONSOLE_SIMPLE)	+= console_simple.o
  obj-$(CONFIG_DIGEST)		+= digest.o
  obj-$(CONFIG_DDR_SPD)		+= ddr_spd.o
+obj-$(CONFIG_ELF)		+= elf.o
  obj-$(CONFIG_ENV_HANDLING)	+= environment.o
  obj-$(CONFIG_ENVIRONMENT_VARIABLES) += env.o
  obj-$(CONFIG_FILETYPE)		+= filetype.o
diff --git a/common/elf.c b/common/elf.c
new file mode 100644
index 0000000..1383ccc
--- /dev/null
+++ b/common/elf.c
@@ -0,0 +1,222 @@
+/*
+ * elf.c - ELF handling code
+ *
+ * Copyright (c) 2014 Owen Kirby <osk@xxxxxxxxxx>, Exegin Technologies Limited
+ *
+ * partly based on U-Boot ELF code.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <fs.h>
+#include <elf.h>
+
+const char *elf_types[] = {
+	[ET_NONE] = "None",
+	[ET_REL] = "Relocatable",
+	[ET_EXEC] = "Executable",
+	[ET_DYN] = "Dynamic",
+	[ET_CORE] = "Core Dump",
+};
+
+void *elf_load_header(int fd)
+{
+	unsigned char ident[EI_NIDENT];
+
+	if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, ident, sizeof(ident)) < 0)) {
+		printf("could not read ident header: %s\n", errno_str());
+		return NULL;
+	}
+	/* Ensure we find the ELF magic number. */
+	if (strncmp(ident, ELFMAG, SELFMAG)) {
+		printf("Bad Magic Number\n");
+		return NULL;
+	}
+
+	/* Read the ELF32 header. */
+	if (ident[EI_CLASS] == ELFCLASS32) {
+		Elf32_Ehdr *hdr = xzalloc(sizeof(Elf32_Ehdr));
+		memcpy(hdr->e_ident, ident, EI_NIDENT);
+		if (read(fd, &hdr->e_type, sizeof(*hdr) - EI_NIDENT) >= 0) return hdr;
+		printf("could not read ELF header: %s\n", errno_str());
+		free(hdr);
+		return NULL;
+	}
+	if (ident[EI_CLASS] == ELFCLASS64) {
+		Elf64_Ehdr *hdr = xzalloc(sizeof(Elf64_Ehdr));
+		memcpy(hdr->e_ident, ident, EI_NIDENT);
+		if (read(fd, &hdr->e_type, sizeof(*hdr) - EI_NIDENT) >= 0) return hdr;
+		printf("could not read ELF header: %s\n", errno_str());
+		free(hdr);
+		return NULL;
+	}
+	printf("Unknown ELF image class\n");
+	return NULL;
+} /* elf_load_header */
+EXPORT_SYMBOL(elf_load_header);
+
+#define ELF_FMT "  %-16s"
+
+/* A rough clone of readelf for debugging and stuff. */
+void elf_print_header(const void *hdr)
+{
+	const unsigned char *ident = hdr;
+	int i;
+
+	/* Ensure we find the ELF magic number. */
+	if (strncmp(ident, ELFMAG, SELFMAG)) {
+		printf("Bad Magic Number\n");
+		return;
+	}
+	printf("  Magic:");
+	for (i=0; i<EI_NIDENT; i++) printf(" %02x", ident[i]);
+	printf("\n");
+
+	/* Print the rest of the ident string. */
+	switch (ident[EI_CLASS]) {
+		case ELFCLASSNONE: printf(ELF_FMT "%s\n", "Class:", "None"); break;
+		case ELFCLASS32: printf(ELF_FMT "%s\n", "Class:", "ELF32"); break;
+		case ELFCLASS64: printf(ELF_FMT "%s\n", "Class:", "ELF64"); break;
+		default: printf(ELF_FMT "%s\n", "Class:", "Invalid"); break;
+	} /* switch */
+	switch (ident[EI_DATA]) {
+		case ELFDATANONE: printf(ELF_FMT "%s\n", "Data:", "None"); break;
+		case ELFDATA2LSB: printf(ELF_FMT "%s\n", "Data:", "2's compliment, litte endian"); break;
+		case ELFDATA2MSB: printf(ELF_FMT "%s\n", "Data:", "2's compliment, big endian"); break;
+		default: printf(ELF_FMT "%s\n", "Data:", "Invalid"); break;
+	} /* switch */
+	printf(ELF_FMT "0x%x\n", "Version:", ident[EI_VERSION]);
+	/* TODO: OS/ABI */
+
+	if (ident[EI_CLASS] == ELFCLASS32) {
+		const Elf32_Ehdr *elf32 = (const Elf32_Ehdr *)hdr;
+		if (elf32->e_type <= ARRAY_SIZE(elf_types))
+			printf(ELF_FMT "%s\n", "Type:", elf_types[elf32->e_type]);
+		else
+			printf(ELF_FMT "0x%x\n", "Type:", elf32->e_type);
+		printf(ELF_FMT "0x%x\n", "Machine:", elf32->e_machine);
+		printf(ELF_FMT "0x%x\n", "Version:", elf32->e_version);
+		printf(ELF_FMT "0x%lx\n", "Entry point:", (unsigned long)elf32->e_entry);
+		printf(ELF_FMT "0x%08x\n", "Flags:", elf32->e_flags);
+	}
+	else if (ident[EI_CLASS] == ELFCLASS64) {
+		const Elf64_Ehdr *elf64 = (const Elf64_Ehdr *)hdr;
+		if (elf64->e_type <= ARRAY_SIZE(elf_types))
+			printf(ELF_FMT "%s\n", "Type:", elf_types[elf64->e_type]);
+		else
+			printf(ELF_FMT "0x%x\n", "Type:", elf64->e_type);
+		printf(ELF_FMT "0x%x\n", "Machine:", elf64->e_machine);
+		printf(ELF_FMT "0x%x\n", "Version:", elf64->e_version);
+		printf(ELF_FMT "0x%llx\n", "Entry point:", (unsigned long long)elf64->e_entry);
+		printf(ELF_FMT "0x%08x\n", "Flags:", elf64->e_flags);
+	}
+	/* TODO: Print the section/program header offsets. */
+} /* elf_print_header */
+EXPORT_SYMBOL(elf_print_header);
+
+static void *elf32_load_sections(int fd, Elf32_Ehdr *hdr)
+{
+	unsigned long off;
+	unsigned char *strtab = NULL;
+	size_t strtabsz = 0;
+	Elf32_Shdr shdr;
+	int i;
+
+	/* We can only load executable images. */
+	if (hdr->e_type != ET_EXEC) {
+		printf("ELF image is not executable\n");
+		return NULL;
+	}
+
+	/* Find the string table from among the section headers. */
+	off = hdr->e_shoff + (hdr->e_shstrndx * sizeof(shdr));
+	if ((lseek(fd, off, SEEK_SET) < 0) || (read(fd, &shdr, sizeof(shdr)) < 0)) {
+		printf("could not read string section header: %s\n", errno_str());
+		return NULL;
+	}
+	if ((shdr.sh_type == SHT_STRTAB) && (shdr.sh_size)) {
+		strtabsz = shdr.sh_size;
+		strtab = xzalloc(shdr.sh_size);
+		if (!strtab) {
+			printf("could not allocate memory for string table\n");
+			return NULL;
+		}
+		if ((lseek(fd, shdr.sh_offset, SEEK_SET) < 0) || (read(fd, strtab, shdr.sh_size) < 0)) {
+			printf("could not read string table section: %s\n", errno_str());
+			free(strtab);
+			return NULL;
+		}
+	}
+
+	/* Load the program sections. */
+	for (i = 0; i < hdr->e_shnum; i++) {
+		/* Read the next section header */
+		off = hdr->e_shoff + (i * sizeof(shdr));
+		if ((lseek(fd, off, SEEK_SET) < 0) || (read(fd, &shdr, sizeof(shdr)) < 0)) {
+			printf("could not read section header: %s\n", errno_str());
+			free(strtab);
+			return NULL;
+		}
+		/* Ignore unallocated or empty sections. */
+		if (!(shdr.sh_flags & SHF_ALLOC)) continue;
+		if (!shdr.sh_addr || !shdr.sh_size) continue;
+
+		/* Inform the user. */
+		if (strtab) {
+			printf("%sing %s @ 0x%08lx (%ld bytes)\n",
+				(shdr.sh_type == SHT_NOBITS) ? "Clear" : "Load",
+				&strtab[shdr.sh_name],
+				(unsigned long) shdr.sh_addr,
+				(long) shdr.sh_size);
+		}
+
+		/* Program the section. */
+		if (shdr.sh_type == SHT_NOBITS) {
+			memset((void *)shdr.sh_addr, 0, shdr.sh_size);
+		} else {
+			if ((lseek(fd, shdr.sh_offset, SEEK_SET) < 0) ||
+				(read(fd, (void *)shdr.sh_addr, shdr.sh_size) < 0)) {
+				printf("could not read section data: %s\n", errno_str());
+				free(strtab);
+				return NULL;
+			}
+		}
+	} /* for */
+
+	/* Success. */
+	free(strtab);
+	return (void *)hdr->e_entry;
+} /* elf32_load_sections */
+
+void *elf_load_sections(int fd)
+{
+	unsigned char *hdr;
+	void *entry;
+
+	/* Load the ELF header. */
+	hdr = elf_load_header(fd);
+	if (!hdr) return NULL;
+	if (hdr[EI_CLASS] == ELFCLASS32) {
+		entry = elf32_load_sections(fd, (Elf32_Ehdr *)hdr);
+	}
+	else {
+		printf("Unsupported ELF image class\n");
+		entry = NULL;
+	}
+	free(hdr);
+	return entry;
+} /* elf_load_sections */
+EXPORT_SYMBOL(elf_load_sections);
+
diff --git a/common/filetype.c b/common/filetype.c
index 0b5da30..0f46fda 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -52,6 +52,7 @@ static const struct filetype_str filetype_str[] = {
  	[filetype_ext] = { "ext filesystem", "ext" },
  	[filetype_gpt] = { "GUID Partition Table", "gpt" },
  	[filetype_bpk] = { "Binary PacKage", "bpk" },
+	[filetype_elf] = { "executable and linkable file", "elf" },
  	[filetype_barebox_env] = { "barebox environment file", "bbenv" },
  };
@@ -227,6 +228,8 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
  		return filetype_mips_barebox;
  	if (buf[0] == be32_to_cpu(0x534F4659))
  		return filetype_bpk;
+	if (strncmp(buf8, "\177ELF", 4) == 0)
+		return filetype_elf;
if (bufsize < 64)
  		return filetype_unknown;
diff --git a/include/elf.h b/include/elf.h
index 6d4addf..357814f 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -397,4 +397,8 @@ 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 */
+void *elf_load_header(int fd);
+void elf_print_header(const void *hdr);
+void *elf_load_sections(int fd);
+
  #endif /* _LINUX_ELF_H */
diff --git a/include/filetype.h b/include/filetype.h
index c20a4f9..c4f776f 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -30,6 +30,7 @@ enum filetype {
  	filetype_ubifs,
  	filetype_bpk,
  	filetype_barebox_env,
+	filetype_elf,
  	filetype_max,
  };
--
1.7.9.5



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



_______________________________________________
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