mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] Support for booting ELF images.
@ 2014-06-26 21:11 Owen Kirby
  2014-06-26 22:06 ` Antony Pavlov
  2014-06-27  5:40 ` Antony Pavlov
  0 siblings, 2 replies; 6+ messages in thread
From: Owen Kirby @ 2014-06-26 21:11 UTC (permalink / raw)
  To: barebox

From 1edc77c7b960d5b42ac3c03000ac5063018195f9 Mon Sep 17 00:00:00 2001
From: Owen Kirby <osk@exegin.com>
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@exegin.com>
---
 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@exegin.com>, 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@exegin.com>, 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@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Support for booting ELF images.
  2014-06-26 21:11 [PATCH] Support for booting ELF images Owen Kirby
@ 2014-06-26 22:06 ` Antony Pavlov
  2014-06-26 23:09   ` Owen Kirby
  2014-06-27  5:40 ` Antony Pavlov
  1 sibling, 1 reply; 6+ messages in thread
From: Antony Pavlov @ 2014-06-26 22:06 UTC (permalink / raw)
  To: Owen Kirby; +Cc: barebox

On Thu, 26 Jun 2014 14:11:32 -0700
Owen Kirby <osk@exegin.com> 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@exegin.com>
> 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@exegin.com>
> ---
>  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@exegin.com>, 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@exegin.com>, 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@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox


-- 
-- 
Best regards,
  Antony Pavlov

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Support for booting ELF images.
  2014-06-26 22:06 ` Antony Pavlov
@ 2014-06-26 23:09   ` Owen Kirby
  2014-06-27  5:10     ` Antony Pavlov
  0 siblings, 1 reply; 6+ messages in thread
From: Owen Kirby @ 2014-06-26 23:09 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

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@exegin.com> 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@exegin.com>
>> 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@exegin.com>
>> ---
>>   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@exegin.com>, 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@exegin.com>, 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@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/barebox
>


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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Support for booting ELF images.
  2014-06-26 23:09   ` Owen Kirby
@ 2014-06-27  5:10     ` Antony Pavlov
  2014-06-30 18:46       ` Owen Kirby
  0 siblings, 1 reply; 6+ messages in thread
From: Antony Pavlov @ 2014-06-27  5:10 UTC (permalink / raw)
  To: Owen Kirby; +Cc: barebox

On Thu, 26 Jun 2014 16:09:35 -0700
Owen Kirby <osk@exegin.com> wrote:

> 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 

Yes, my kexec series have not been checked in.
I can fix it this weekend.

The main problem of my series is that it's a MIPS series but barebox is essentially a ARM bootloader.
It seems that I have to add kexec ARM support :)

Which hardware platform do you use?

> of loading  the images, but it seems like quite a large patch set just 
> to support another image format.

My series consist of three parts:

  * MIPS cache memory stuff (patches 1-4);
  * common (not ELF) kexec code (patches 5-6);
  * common ELF support (patches 7-8);
  * MIPS ELF support (patch 9);
  * MIPS malta machine-specific stuff (patch 10).

So only patches 7-9 are actually used to support ELF 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.

It uses relocator so somebody has to port kexec relocator code from linux kernel
to use barebox kexec on another architecture.

I know how to run linux on qemu-versatile virtual hardware so I can port ARM kexec stuff.
 
> 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@exegin.com> 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@exegin.com>
> >> 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@exegin.com>
> >> ---
> >>   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@exegin.com>, 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@exegin.com>, 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@lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/barebox
> >
> 


-- 
-- 
Best regards,
  Antony Pavlov

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Support for booting ELF images.
  2014-06-26 21:11 [PATCH] Support for booting ELF images Owen Kirby
  2014-06-26 22:06 ` Antony Pavlov
@ 2014-06-27  5:40 ` Antony Pavlov
  1 sibling, 0 replies; 6+ messages in thread
From: Antony Pavlov @ 2014-06-27  5:40 UTC (permalink / raw)
  To: Owen Kirby; +Cc: barebox

On Thu, 26 Jun 2014 14:11:32 -0700
Owen Kirby <osk@exegin.com> wrote:

Here are some ELF-unrelated comments on your patch:

1. please use 'git send-email' for sending patches;

2. please use scripts/checkpatch.pl on your patches before sending them to maillist;

   My checkpatch.pl reports about errors:

       total: 28 errors, 28 warnings, 399 lines checked

> From 1edc77c7b960d5b42ac3c03000ac5063018195f9 Mon Sep 17 00:00:00 2001
> From: Owen Kirby <osk@exegin.com>
> 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@exegin.com>
> ---
>  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@exegin.com>, 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@exegin.com>, 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@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox


-- 
-- 
Best regards,
  Antony Pavlov

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Support for booting ELF images.
  2014-06-27  5:10     ` Antony Pavlov
@ 2014-06-30 18:46       ` Owen Kirby
  0 siblings, 0 replies; 6+ messages in thread
From: Owen Kirby @ 2014-06-30 18:46 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On 14-06-26 10:10 PM, Antony Pavlov wrote:
> Yes, my kexec series have not been checked in.
> I can fix it this weekend.
>
> The main problem of my series is that it's a MIPS series but barebox is essentially a ARM bootloader.
> It seems that I have to add kexec ARM support :)
>
> Which hardware platform do you use?
We are indeed using an ARM platform (based on an Atmel AT91 SoC, but I 
haven't submitted a patch for our specific board yet). We are primarily 
using Barebox as a bootloader for the Linux kernel, but some of our 
customers want to our boards as eval kits for other operating systems 
(ie: eCos and FreeRTOS).

It's only for those other operating systems that we need the ability to 
load and execute ELF images, we're still using zImage for the Linux 
kernel and I'd feel bad for dumping a lot of kexec work on you when we 
don't really need to be able to boot Linux with it.

Cheers,
Owen


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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-06-30 18:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-26 21:11 [PATCH] Support for booting ELF images Owen Kirby
2014-06-26 22:06 ` Antony Pavlov
2014-06-26 23:09   ` Owen Kirby
2014-06-27  5:10     ` Antony Pavlov
2014-06-30 18:46       ` Owen Kirby
2014-06-27  5:40 ` Antony Pavlov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox