On Fri, Jan 17, 2020 at 5:27 AM Lokesh Vutla <[email protected]> wrote: > > Simon, > > On 13/01/20 11:24 AM, Keerthy wrote: > > 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 <[email protected]> > > Suggested-by: Simon Goldschmidt <[email protected]> > > Are you okay with this patch? If yes, Ill apply to u-boot-ti along with other > patches in this series.
Yes. Reviewed-by: Simon Goldschmidt <[email protected]> Regards, Simon > > Thanks and regards, > Lokesh > > > --- > > Changes in v2: > > > > * Factored out all the generic elf handling functions under lib/elf.c > > > > 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..6f4f08d02a 100644 > > --- a/cmd/Kconfig > > +++ b/cmd/Kconfig > > @@ -375,6 +375,7 @@ config CMD_ADTIMG > > config CMD_ELF > > bool "bootelf, bootvx" > > default y > > + select 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 <linux/linkage.h> > > #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..b155ced4b2 100644 > > --- a/lib/Kconfig > > +++ b/lib/Kconfig > > @@ -601,4 +601,7 @@ config TEST_FDTDEC > > config LIB_DATE > > bool > > > > +config ELF > > + bool "enable basic elf loading/validating functions" > > + > > endmenu > > diff --git a/lib/Makefile b/lib/Makefile > > index 6b7b9ce85c..93f22d210e 100644 > > --- a/lib/Makefile > > +++ b/lib/Makefile > > @@ -121,6 +121,7 @@ obj-y += vsprintf.o strto.o > > endif > > > > obj-y += date.o > > +obj-$(CONFIG_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 <common.h> > > +#include <command.h> > > +#include <cpu_func.h> > > +#include <elf.h> > > +#include <env.h> > > +#include <net.h> > > +#include <vxworks.h> > > +#ifdef CONFIG_X86 > > +#include <vbe.h> > > +#include <asm/e820.h> > > +#include <linux/linkage.h> > > +#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; > > +} > >

