From patchwork Wed Jan 22 03:59:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keerthy X-Patchwork-Id: 239904 List-Id: U-Boot discussion From: j-keerthy at ti.com (Keerthy) Date: Wed, 22 Jan 2020 09:29:57 +0530 Subject: [PATCH v4 02/10] lib: elf: Move the generic elf loading/validating functions to lib In-Reply-To: <20200122040005.7573-1-j-keerthy@ti.com> References: <20200122040005.7573-1-j-keerthy@ti.com> Message-ID: <20200122040005.7573-3-j-keerthy@ti.com> Move the generic elf loading/validating functions to lib/ so that they can be re-used and accessed by code existing outside cmd. Signed-off-by: Keerthy Suggested-by: Simon Goldschmidt Reviewed-by: Simon Goldschmidt --- Changes in v4: * /s/ELF/LIB_ELF config option name cmd/Kconfig | 1 + cmd/elf.c | 229 -------------------------------------------- include/elf.h | 4 + lib/Kconfig | 3 + lib/Makefile | 1 + lib/elf.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 265 insertions(+), 229 deletions(-) create mode 100644 lib/elf.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 298feae24d..ac0a985596 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -375,6 +375,7 @@ config CMD_ADTIMG config CMD_ELF bool "bootelf, bootvx" default y + select LIB_ELF help Boot an ELF/vxWorks image from the memory. diff --git a/cmd/elf.c b/cmd/elf.c index 32f12a72b9..23cc17aebc 100644 --- a/cmd/elf.c +++ b/cmd/elf.c @@ -26,211 +26,6 @@ #include #endif -/* - * A very simple ELF64 loader, assumes the image is valid, returns the - * entry point address. - * - * Note if U-Boot is 32-bit, the loader assumes the to segment's - * physical address and size is within the lower 32-bit address space. - */ -static unsigned long load_elf64_image_phdr(unsigned long addr) -{ - Elf64_Ehdr *ehdr; /* Elf header structure pointer */ - Elf64_Phdr *phdr; /* Program header structure pointer */ - int i; - - ehdr = (Elf64_Ehdr *)addr; - phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff); - - /* Load each program header */ - for (i = 0; i < ehdr->e_phnum; ++i) { - void *dst = (void *)(ulong)phdr->p_paddr; - void *src = (void *)addr + phdr->p_offset; - - debug("Loading phdr %i to 0x%p (%lu bytes)\n", - i, dst, (ulong)phdr->p_filesz); - if (phdr->p_filesz) - memcpy(dst, src, phdr->p_filesz); - if (phdr->p_filesz != phdr->p_memsz) - memset(dst + phdr->p_filesz, 0x00, - phdr->p_memsz - phdr->p_filesz); - flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), - roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); - ++phdr; - } - - if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & - EF_PPC64_ELFV1_ABI)) { - /* - * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function - * descriptor pointer with the first double word being the - * address of the entry point of the function. - */ - uintptr_t addr = ehdr->e_entry; - - return *(Elf64_Addr *)addr; - } - - return ehdr->e_entry; -} - -static unsigned long load_elf64_image_shdr(unsigned long addr) -{ - Elf64_Ehdr *ehdr; /* Elf header structure pointer */ - Elf64_Shdr *shdr; /* Section header structure pointer */ - unsigned char *strtab = 0; /* String table pointer */ - unsigned char *image; /* Binary image pointer */ - int i; /* Loop counter */ - - ehdr = (Elf64_Ehdr *)addr; - - /* Find the section header string table for output info */ - shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + - (ehdr->e_shstrndx * sizeof(Elf64_Shdr))); - - if (shdr->sh_type == SHT_STRTAB) - strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset); - - /* Load each appropriate section */ - for (i = 0; i < ehdr->e_shnum; ++i) { - shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + - (i * sizeof(Elf64_Shdr))); - - if (!(shdr->sh_flags & SHF_ALLOC) || - shdr->sh_addr == 0 || shdr->sh_size == 0) { - continue; - } - - if (strtab) { - debug("%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); - } - - if (shdr->sh_type == SHT_NOBITS) { - memset((void *)(uintptr_t)shdr->sh_addr, 0, - shdr->sh_size); - } else { - image = (unsigned char *)addr + (ulong)shdr->sh_offset; - memcpy((void *)(uintptr_t)shdr->sh_addr, - (const void *)image, shdr->sh_size); - } - flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), - roundup((shdr->sh_addr + shdr->sh_size), - ARCH_DMA_MINALIGN) - - rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); - } - - if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & - EF_PPC64_ELFV1_ABI)) { - /* - * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function - * descriptor pointer with the first double word being the - * address of the entry point of the function. - */ - uintptr_t addr = ehdr->e_entry; - - return *(Elf64_Addr *)addr; - } - - return ehdr->e_entry; -} - -/* - * A very simple ELF loader, assumes the image is valid, returns the - * entry point address. - * - * The loader firstly reads the EFI class to see if it's a 64-bit image. - * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader. - */ -static unsigned long load_elf_image_phdr(unsigned long addr) -{ - Elf32_Ehdr *ehdr; /* Elf header structure pointer */ - Elf32_Phdr *phdr; /* Program header structure pointer */ - int i; - - ehdr = (Elf32_Ehdr *)addr; - if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) - return load_elf64_image_phdr(addr); - - phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); - - /* Load each program header */ - for (i = 0; i < ehdr->e_phnum; ++i) { - void *dst = (void *)(uintptr_t)phdr->p_paddr; - void *src = (void *)addr + phdr->p_offset; - - debug("Loading phdr %i to 0x%p (%i bytes)\n", - i, dst, phdr->p_filesz); - if (phdr->p_filesz) - memcpy(dst, src, phdr->p_filesz); - if (phdr->p_filesz != phdr->p_memsz) - memset(dst + phdr->p_filesz, 0x00, - phdr->p_memsz - phdr->p_filesz); - flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), - roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); - ++phdr; - } - - return ehdr->e_entry; -} - -static unsigned long load_elf_image_shdr(unsigned long addr) -{ - Elf32_Ehdr *ehdr; /* Elf header structure pointer */ - Elf32_Shdr *shdr; /* Section header structure pointer */ - unsigned char *strtab = 0; /* String table pointer */ - unsigned char *image; /* Binary image pointer */ - int i; /* Loop counter */ - - ehdr = (Elf32_Ehdr *)addr; - if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) - return load_elf64_image_shdr(addr); - - /* Find the section header string table for output info */ - shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + - (ehdr->e_shstrndx * sizeof(Elf32_Shdr))); - - if (shdr->sh_type == SHT_STRTAB) - strtab = (unsigned char *)(addr + shdr->sh_offset); - - /* Load each appropriate section */ - for (i = 0; i < ehdr->e_shnum; ++i) { - shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + - (i * sizeof(Elf32_Shdr))); - - if (!(shdr->sh_flags & SHF_ALLOC) || - shdr->sh_addr == 0 || shdr->sh_size == 0) { - continue; - } - - if (strtab) { - debug("%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); - } - - if (shdr->sh_type == SHT_NOBITS) { - memset((void *)(uintptr_t)shdr->sh_addr, 0, - shdr->sh_size); - } else { - image = (unsigned char *)addr + shdr->sh_offset; - memcpy((void *)(uintptr_t)shdr->sh_addr, - (const void *)image, shdr->sh_size); - } - flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), - roundup((shdr->sh_addr + shdr->sh_size), - ARCH_DMA_MINALIGN) - - rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); - } - - return ehdr->e_entry; -} - /* Allow ports to override the default behavior */ static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]), int argc, char * const argv[]) @@ -246,30 +41,6 @@ static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]), return ret; } -/* - * Determine if a valid ELF image exists at the given memory location. - * First look at the ELF header magic field, then make sure that it is - * executable. - */ -int valid_elf_image(unsigned long addr) -{ - Elf32_Ehdr *ehdr; /* Elf header structure pointer */ - - ehdr = (Elf32_Ehdr *)addr; - - if (!IS_ELF(*ehdr)) { - printf("## No elf image at address 0x%08lx\n", addr); - return 0; - } - - if (ehdr->e_type != ET_EXEC) { - printf("## Not a 32-bit elf image at address 0x%08lx\n", addr); - return 0; - } - - return 1; -} - /* Interpreter command to boot an arbitrary ELF image from memory */ int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { diff --git a/include/elf.h b/include/elf.h index 81f40191d7..e7c51986df 100644 --- a/include/elf.h +++ b/include/elf.h @@ -692,6 +692,10 @@ unsigned long elf_hash(const unsigned char *name); #ifndef __ASSEMBLER__ int valid_elf_image(unsigned long addr); +unsigned long load_elf64_image_phdr(unsigned long addr); +unsigned long load_elf64_image_shdr(unsigned long addr); +unsigned long load_elf_image_phdr(unsigned long addr); +unsigned long load_elf_image_shdr(unsigned long addr); #endif #endif /* _ELF_H */ diff --git a/lib/Kconfig b/lib/Kconfig index d040a87d26..5ca86cd7fb 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -601,4 +601,7 @@ config TEST_FDTDEC config LIB_DATE bool +config LIB_ELF + bool "enable basic elf loading/validating functions" + endmenu diff --git a/lib/Makefile b/lib/Makefile index 51eba80b89..11bc77e7ad 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -122,6 +122,7 @@ obj-y += vsprintf.o strto.o endif obj-y += date.o +obj-$(CONFIG_LIB_ELF) += elf.o # # Build a fast OID lookup registry from include/linux/oid_registry.h diff --git a/lib/elf.c b/lib/elf.c new file mode 100644 index 0000000000..54ac4ee502 --- /dev/null +++ b/lib/elf.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001 William L. Pitts + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_X86 +#include +#include +#include +#endif + +/* + * A very simple ELF64 loader, assumes the image is valid, returns the + * entry point address. + * + * Note if U-Boot is 32-bit, the loader assumes the to segment's + * physical address and size is within the lower 32-bit address space. + */ +unsigned long load_elf64_image_phdr(unsigned long addr) +{ + Elf64_Ehdr *ehdr; /* Elf header structure pointer */ + Elf64_Phdr *phdr; /* Program header structure pointer */ + int i; + + ehdr = (Elf64_Ehdr *)addr; + phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff); + + /* Load each program header */ + for (i = 0; i < ehdr->e_phnum; ++i) { + void *dst = (void *)(ulong)phdr->p_paddr; + void *src = (void *)addr + phdr->p_offset; + + debug("Loading phdr %i to 0x%p (%lu bytes)\n", + i, dst, (ulong)phdr->p_filesz); + if (phdr->p_filesz) + memcpy(dst, src, phdr->p_filesz); + if (phdr->p_filesz != phdr->p_memsz) + memset(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); + ++phdr; + } + + if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & + EF_PPC64_ELFV1_ABI)) { + /* + * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function + * descriptor pointer with the first double word being the + * address of the entry point of the function. + */ + uintptr_t addr = ehdr->e_entry; + + return *(Elf64_Addr *)addr; + } + + return ehdr->e_entry; +} + +unsigned long load_elf64_image_shdr(unsigned long addr) +{ + Elf64_Ehdr *ehdr; /* Elf header structure pointer */ + Elf64_Shdr *shdr; /* Section header structure pointer */ + unsigned char *strtab = 0; /* String table pointer */ + unsigned char *image; /* Binary image pointer */ + int i; /* Loop counter */ + + ehdr = (Elf64_Ehdr *)addr; + + /* Find the section header string table for output info */ + shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + + (ehdr->e_shstrndx * sizeof(Elf64_Shdr))); + + if (shdr->sh_type == SHT_STRTAB) + strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset); + + /* Load each appropriate section */ + for (i = 0; i < ehdr->e_shnum; ++i) { + shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + + (i * sizeof(Elf64_Shdr))); + + if (!(shdr->sh_flags & SHF_ALLOC) || + shdr->sh_addr == 0 || shdr->sh_size == 0) { + continue; + } + + if (strtab) { + debug("%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); + } + + if (shdr->sh_type == SHT_NOBITS) { + memset((void *)(uintptr_t)shdr->sh_addr, 0, + shdr->sh_size); + } else { + image = (unsigned char *)addr + (ulong)shdr->sh_offset; + memcpy((void *)(uintptr_t)shdr->sh_addr, + (const void *)image, shdr->sh_size); + } + flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), + roundup((shdr->sh_addr + shdr->sh_size), + ARCH_DMA_MINALIGN) - + rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); + } + + if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & + EF_PPC64_ELFV1_ABI)) { + /* + * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function + * descriptor pointer with the first double word being the + * address of the entry point of the function. + */ + uintptr_t addr = ehdr->e_entry; + + return *(Elf64_Addr *)addr; + } + + return ehdr->e_entry; +} + +/* + * A very simple ELF loader, assumes the image is valid, returns the + * entry point address. + * + * The loader firstly reads the EFI class to see if it's a 64-bit image. + * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader. + */ +unsigned long load_elf_image_phdr(unsigned long addr) +{ + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + Elf32_Phdr *phdr; /* Program header structure pointer */ + int i; + + ehdr = (Elf32_Ehdr *)addr; + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) + return load_elf64_image_phdr(addr); + + phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); + + /* Load each program header */ + for (i = 0; i < ehdr->e_phnum; ++i) { + void *dst = (void *)(uintptr_t)phdr->p_paddr; + void *src = (void *)addr + phdr->p_offset; + + debug("Loading phdr %i to 0x%p (%i bytes)\n", + i, dst, phdr->p_filesz); + if (phdr->p_filesz) + memcpy(dst, src, phdr->p_filesz); + if (phdr->p_filesz != phdr->p_memsz) + memset(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); + ++phdr; + } + + return ehdr->e_entry; +} + +unsigned long load_elf_image_shdr(unsigned long addr) +{ + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + Elf32_Shdr *shdr; /* Section header structure pointer */ + unsigned char *strtab = 0; /* String table pointer */ + unsigned char *image; /* Binary image pointer */ + int i; /* Loop counter */ + + ehdr = (Elf32_Ehdr *)addr; + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) + return load_elf64_image_shdr(addr); + + /* Find the section header string table for output info */ + shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + + (ehdr->e_shstrndx * sizeof(Elf32_Shdr))); + + if (shdr->sh_type == SHT_STRTAB) + strtab = (unsigned char *)(addr + shdr->sh_offset); + + /* Load each appropriate section */ + for (i = 0; i < ehdr->e_shnum; ++i) { + shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + + (i * sizeof(Elf32_Shdr))); + + if (!(shdr->sh_flags & SHF_ALLOC) || + shdr->sh_addr == 0 || shdr->sh_size == 0) { + continue; + } + + if (strtab) { + debug("%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); + } + + if (shdr->sh_type == SHT_NOBITS) { + memset((void *)(uintptr_t)shdr->sh_addr, 0, + shdr->sh_size); + } else { + image = (unsigned char *)addr + shdr->sh_offset; + memcpy((void *)(uintptr_t)shdr->sh_addr, + (const void *)image, shdr->sh_size); + } + flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), + roundup((shdr->sh_addr + shdr->sh_size), + ARCH_DMA_MINALIGN) - + rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); + } + + return ehdr->e_entry; +} + +/* + * Determine if a valid ELF image exists at the given memory location. + * First look at the ELF header magic field, then make sure that it is + * executable. + */ +int valid_elf_image(unsigned long addr) +{ + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + + ehdr = (Elf32_Ehdr *)addr; + + if (!IS_ELF(*ehdr)) { + printf("## No elf image at address 0x%08lx\n", addr); + return 0; + } + + if (ehdr->e_type != ET_EXEC) { + printf("## Not a 32-bit elf image at address 0x%08lx\n", addr); + return 0; + } + + return 1; +}