[PATCH] Support for booting ELF images.

Antony Pavlov antonynpavlov at gmail.com
Thu Jun 26 15:06:41 PDT 2014


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


-- 
-- 
Best regards,
  Antony Pavlov



More information about the barebox mailing list