uboot/lib/elf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-2-Clause
   2/*
   3   Copyright (c) 2001 William L. Pitts
   4*/
   5
   6#include <common.h>
   7#include <command.h>
   8#include <cpu_func.h>
   9#include <elf.h>
  10#include <env.h>
  11#include <net.h>
  12#include <vxworks.h>
  13#ifdef CONFIG_X86
  14#include <vbe.h>
  15#include <asm/e820.h>
  16#include <linux/linkage.h>
  17#endif
  18
  19/*
  20 * A very simple ELF64 loader, assumes the image is valid, returns the
  21 * entry point address.
  22 *
  23 * Note if U-Boot is 32-bit, the loader assumes the to segment's
  24 * physical address and size is within the lower 32-bit address space.
  25 */
  26unsigned long load_elf64_image_phdr(unsigned long addr)
  27{
  28        Elf64_Ehdr *ehdr; /* Elf header structure pointer */
  29        Elf64_Phdr *phdr; /* Program header structure pointer */
  30        int i;
  31
  32        ehdr = (Elf64_Ehdr *)addr;
  33        phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
  34
  35        /* Load each program header */
  36        for (i = 0; i < ehdr->e_phnum; ++i) {
  37                void *dst = (void *)(ulong)phdr->p_paddr;
  38                void *src = (void *)addr + phdr->p_offset;
  39
  40                debug("Loading phdr %i to 0x%p (%lu bytes)\n",
  41                      i, dst, (ulong)phdr->p_filesz);
  42                if (phdr->p_filesz)
  43                        memcpy(dst, src, phdr->p_filesz);
  44                if (phdr->p_filesz != phdr->p_memsz)
  45                        memset(dst + phdr->p_filesz, 0x00,
  46                               phdr->p_memsz - phdr->p_filesz);
  47                flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
  48                            roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
  49                ++phdr;
  50        }
  51
  52        if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
  53                                            EF_PPC64_ELFV1_ABI)) {
  54                /*
  55                 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
  56                 * descriptor pointer with the first double word being the
  57                 * address of the entry point of the function.
  58                 */
  59                uintptr_t addr = ehdr->e_entry;
  60
  61                return *(Elf64_Addr *)addr;
  62        }
  63
  64        return ehdr->e_entry;
  65}
  66
  67unsigned long load_elf64_image_shdr(unsigned long addr)
  68{
  69        Elf64_Ehdr *ehdr; /* Elf header structure pointer */
  70        Elf64_Shdr *shdr; /* Section header structure pointer */
  71        unsigned char *strtab = 0; /* String table pointer */
  72        unsigned char *image; /* Binary image pointer */
  73        int i; /* Loop counter */
  74
  75        ehdr = (Elf64_Ehdr *)addr;
  76
  77        /* Find the section header string table for output info */
  78        shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
  79                             (ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
  80
  81        if (shdr->sh_type == SHT_STRTAB)
  82                strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
  83
  84        /* Load each appropriate section */
  85        for (i = 0; i < ehdr->e_shnum; ++i) {
  86                shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
  87                                     (i * sizeof(Elf64_Shdr)));
  88
  89                if (!(shdr->sh_flags & SHF_ALLOC) ||
  90                    shdr->sh_addr == 0 || shdr->sh_size == 0) {
  91                        continue;
  92                }
  93
  94                if (strtab) {
  95                        debug("%sing %s @ 0x%08lx (%ld bytes)\n",
  96                              (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
  97                               &strtab[shdr->sh_name],
  98                               (unsigned long)shdr->sh_addr,
  99                               (long)shdr->sh_size);
 100                }
 101
 102                if (shdr->sh_type == SHT_NOBITS) {
 103                        memset((void *)(uintptr_t)shdr->sh_addr, 0,
 104                               shdr->sh_size);
 105                } else {
 106                        image = (unsigned char *)addr + (ulong)shdr->sh_offset;
 107                        memcpy((void *)(uintptr_t)shdr->sh_addr,
 108                               (const void *)image, shdr->sh_size);
 109                }
 110                flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
 111                            roundup((shdr->sh_addr + shdr->sh_size),
 112                                     ARCH_DMA_MINALIGN) -
 113                                rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
 114        }
 115
 116        if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
 117                                            EF_PPC64_ELFV1_ABI)) {
 118                /*
 119                 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
 120                 * descriptor pointer with the first double word being the
 121                 * address of the entry point of the function.
 122                 */
 123                uintptr_t addr = ehdr->e_entry;
 124
 125                return *(Elf64_Addr *)addr;
 126        }
 127
 128        return ehdr->e_entry;
 129}
 130
 131/*
 132 * A very simple ELF loader, assumes the image is valid, returns the
 133 * entry point address.
 134 *
 135 * The loader firstly reads the EFI class to see if it's a 64-bit image.
 136 * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
 137 */
 138unsigned long load_elf_image_phdr(unsigned long addr)
 139{
 140        Elf32_Ehdr *ehdr; /* Elf header structure pointer */
 141        Elf32_Phdr *phdr; /* Program header structure pointer */
 142        int i;
 143
 144        ehdr = (Elf32_Ehdr *)addr;
 145        if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
 146                return load_elf64_image_phdr(addr);
 147
 148        phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
 149
 150        /* Load each program header */
 151        for (i = 0; i < ehdr->e_phnum; ++i) {
 152                void *dst = (void *)(uintptr_t)phdr->p_paddr;
 153                void *src = (void *)addr + phdr->p_offset;
 154
 155                debug("Loading phdr %i to 0x%p (%i bytes)\n",
 156                      i, dst, phdr->p_filesz);
 157                if (phdr->p_filesz)
 158                        memcpy(dst, src, phdr->p_filesz);
 159                if (phdr->p_filesz != phdr->p_memsz)
 160                        memset(dst + phdr->p_filesz, 0x00,
 161                               phdr->p_memsz - phdr->p_filesz);
 162                flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
 163                            roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
 164                ++phdr;
 165        }
 166
 167        return ehdr->e_entry;
 168}
 169
 170unsigned long load_elf_image_shdr(unsigned long addr)
 171{
 172        Elf32_Ehdr *ehdr; /* Elf header structure pointer */
 173        Elf32_Shdr *shdr; /* Section header structure pointer */
 174        unsigned char *strtab = 0; /* String table pointer */
 175        unsigned char *image; /* Binary image pointer */
 176        int i; /* Loop counter */
 177
 178        ehdr = (Elf32_Ehdr *)addr;
 179        if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
 180                return load_elf64_image_shdr(addr);
 181
 182        /* Find the section header string table for output info */
 183        shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
 184                             (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
 185
 186        if (shdr->sh_type == SHT_STRTAB)
 187                strtab = (unsigned char *)(addr + shdr->sh_offset);
 188
 189        /* Load each appropriate section */
 190        for (i = 0; i < ehdr->e_shnum; ++i) {
 191                shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
 192                                     (i * sizeof(Elf32_Shdr)));
 193
 194                if (!(shdr->sh_flags & SHF_ALLOC) ||
 195                    shdr->sh_addr == 0 || shdr->sh_size == 0) {
 196                        continue;
 197                }
 198
 199                if (strtab) {
 200                        debug("%sing %s @ 0x%08lx (%ld bytes)\n",
 201                              (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
 202                               &strtab[shdr->sh_name],
 203                               (unsigned long)shdr->sh_addr,
 204                               (long)shdr->sh_size);
 205                }
 206
 207                if (shdr->sh_type == SHT_NOBITS) {
 208                        memset((void *)(uintptr_t)shdr->sh_addr, 0,
 209                               shdr->sh_size);
 210                } else {
 211                        image = (unsigned char *)addr + shdr->sh_offset;
 212                        memcpy((void *)(uintptr_t)shdr->sh_addr,
 213                               (const void *)image, shdr->sh_size);
 214                }
 215                flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
 216                            roundup((shdr->sh_addr + shdr->sh_size),
 217                                    ARCH_DMA_MINALIGN) -
 218                            rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
 219        }
 220
 221        return ehdr->e_entry;
 222}
 223
 224/*
 225 * Determine if a valid ELF image exists at the given memory location.
 226 * First look at the ELF header magic field, then make sure that it is
 227 * executable.
 228 */
 229int valid_elf_image(unsigned long addr)
 230{
 231        Elf32_Ehdr *ehdr; /* Elf header structure pointer */
 232
 233        ehdr = (Elf32_Ehdr *)addr;
 234
 235        if (!IS_ELF(*ehdr)) {
 236                printf("## No elf image at address 0x%08lx\n", addr);
 237                return 0;
 238        }
 239
 240        if (ehdr->e_type != ET_EXEC) {
 241                printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
 242                return 0;
 243        }
 244
 245        return 1;
 246}
 247