Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/lib/elf.c
Line
Count
Source
1
// SPDX-License-Identifier: BSD-2-Clause
2
/*
3
   Copyright (c) 2001 William L. Pitts
4
*/
5
6
#include <command.h>
7
#include <cpu_func.h>
8
#include <elf.h>
9
#include <env.h>
10
#include <errno.h>
11
#include <net.h>
12
#include <vxworks.h>
13
#ifdef CONFIG_X86
14
#include <vesa.h>
15
#include <asm/e820.h>
16
#include <linux/linkage.h>
17
#endif
18
19
/**
20
 * bootelf_exec() - start the ELF image execution.
21
 *
22
 * @entry: address of entry point of ELF.
23
 *
24
 * May by used to allow ports to override the default behavior.
25
 */
26
unsigned long bootelf_exec(ulong (*entry)(int, char * const[]),
27
         int argc, char *const argv[])
28
0
{
29
0
  return entry(argc, argv);
30
0
}
31
32
/**
33
 * bootelf() - Boot ELF from memory.
34
 *
35
 * @addr:  Loading address of ELF in memory.
36
 * @flags: Bits like ELF_PHDR to control boot details.
37
 * @argc: May be used to pass command line arguments (maybe unused).
38
 *    Necessary for backward compatibility with the CLI command.
39
 *    If unused, must be 0.
40
 * @argv: see @argc. If unused, must be NULL.
41
 * Return: Number returned by ELF application.
42
 *
43
 * Sets errno = ENOEXEC if the ELF image is not valid.
44
 */
45
unsigned long bootelf(unsigned long addr, Bootelf_flags flags,
46
          int argc, char *const argv[])
47
0
{
48
0
  unsigned long entry_addr;
49
0
  char *args[] = {"", NULL};
50
51
0
  errno = 0;
52
53
0
  if (!valid_elf_image(addr)) {
54
0
    errno = ENOEXEC;
55
0
    return 1;
56
0
  }
57
58
0
  entry_addr = flags.phdr ? load_elf_image_phdr(addr)
59
0
              : load_elf_image_shdr(addr);
60
61
0
  if (!flags.autostart)
62
0
    return 0;
63
64
0
  if (!argc && !argv) {
65
0
    argc = 1;
66
0
    argv = args;
67
0
  }
68
69
0
  return bootelf_exec((void *)entry_addr, argc, argv);
70
0
}
71
72
/*
73
 * A very simple ELF64 loader, assumes the image is valid, returns the
74
 * entry point address.
75
 *
76
 * Note if U-Boot is 32-bit, the loader assumes the to segment's
77
 * physical address and size is within the lower 32-bit address space.
78
 */
79
unsigned long load_elf64_image_phdr(unsigned long addr)
80
0
{
81
0
  Elf64_Ehdr *ehdr; /* Elf header structure pointer */
82
0
  Elf64_Phdr *phdr; /* Program header structure pointer */
83
0
  int i;
84
85
0
  ehdr = (Elf64_Ehdr *)addr;
86
0
  phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
87
88
  /* Load each program header */
89
0
  for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
90
0
    void *dst = (void *)(ulong)phdr->p_paddr;
91
0
    void *src = (void *)addr + phdr->p_offset;
92
93
    /* Only load PT_LOAD program header */
94
0
    if (phdr->p_type != PT_LOAD)
95
0
      continue;
96
97
0
    debug("Loading phdr %i to 0x%p (%lu bytes)\n",
98
0
          i, dst, (ulong)phdr->p_filesz);
99
0
    if (phdr->p_filesz)
100
0
      memcpy(dst, src, phdr->p_filesz);
101
0
    if (phdr->p_filesz != phdr->p_memsz)
102
0
      memset(dst + phdr->p_filesz, 0x00,
103
0
             phdr->p_memsz - phdr->p_filesz);
104
0
    flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
105
0
          roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
106
0
  }
107
108
0
  if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
109
0
              EF_PPC64_ELFV1_ABI)) {
110
    /*
111
     * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
112
     * descriptor pointer with the first double word being the
113
     * address of the entry point of the function.
114
     */
115
0
    uintptr_t addr = ehdr->e_entry;
116
117
0
    return *(Elf64_Addr *)addr;
118
0
  }
119
120
0
  return ehdr->e_entry;
121
0
}
122
123
unsigned long load_elf64_image_shdr(unsigned long addr)
124
0
{
125
0
  Elf64_Ehdr *ehdr; /* Elf header structure pointer */
126
0
  Elf64_Shdr *shdr; /* Section header structure pointer */
127
0
  unsigned char *strtab = 0; /* String table pointer */
128
0
  unsigned char *image; /* Binary image pointer */
129
0
  int i; /* Loop counter */
130
131
0
  ehdr = (Elf64_Ehdr *)addr;
132
133
  /* Find the section header string table for output info */
134
0
  shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
135
0
           (ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
136
137
0
  if (shdr->sh_type == SHT_STRTAB)
138
0
    strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
139
140
  /* Load each appropriate section */
141
0
  for (i = 0; i < ehdr->e_shnum; ++i) {
142
0
    shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
143
0
             (i * sizeof(Elf64_Shdr)));
144
145
0
    if (!(shdr->sh_flags & SHF_ALLOC) ||
146
0
        shdr->sh_addr == 0 || shdr->sh_size == 0) {
147
0
      continue;
148
0
    }
149
150
0
    if (strtab) {
151
0
      debug("%sing %s @ 0x%08lx (%ld bytes)\n",
152
0
            (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
153
0
             &strtab[shdr->sh_name],
154
0
             (unsigned long)shdr->sh_addr,
155
0
             (long)shdr->sh_size);
156
0
    }
157
158
0
    if (shdr->sh_type == SHT_NOBITS) {
159
0
      memset((void *)(uintptr_t)shdr->sh_addr, 0,
160
0
             shdr->sh_size);
161
0
    } else {
162
0
      image = (unsigned char *)addr + (ulong)shdr->sh_offset;
163
0
      memcpy((void *)(uintptr_t)shdr->sh_addr,
164
0
             (const void *)image, shdr->sh_size);
165
0
    }
166
0
    flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
167
0
          roundup((shdr->sh_addr + shdr->sh_size),
168
0
             ARCH_DMA_MINALIGN) -
169
0
        rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
170
0
  }
171
172
0
  if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
173
0
              EF_PPC64_ELFV1_ABI)) {
174
    /*
175
     * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
176
     * descriptor pointer with the first double word being the
177
     * address of the entry point of the function.
178
     */
179
0
    uintptr_t addr = ehdr->e_entry;
180
181
0
    return *(Elf64_Addr *)addr;
182
0
  }
183
184
0
  return ehdr->e_entry;
185
0
}
186
187
/*
188
 * A very simple ELF loader, assumes the image is valid, returns the
189
 * entry point address.
190
 *
191
 * The loader firstly reads the EFI class to see if it's a 64-bit image.
192
 * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
193
 */
194
unsigned long load_elf_image_phdr(unsigned long addr)
195
0
{
196
0
  Elf32_Ehdr *ehdr; /* Elf header structure pointer */
197
0
  Elf32_Phdr *phdr; /* Program header structure pointer */
198
0
  int i;
199
200
0
  ehdr = (Elf32_Ehdr *)addr;
201
0
  if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
202
0
    return load_elf64_image_phdr(addr);
203
204
0
  phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
205
206
  /* Load each program header */
207
0
  for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
208
0
    void *dst = (void *)(uintptr_t)phdr->p_paddr;
209
0
    void *src = (void *)addr + phdr->p_offset;
210
211
    /* Only load PT_LOAD program header */
212
0
    if (phdr->p_type != PT_LOAD)
213
0
      continue;
214
215
0
    debug("Loading phdr %i to 0x%p (%i bytes)\n",
216
0
          i, dst, phdr->p_filesz);
217
0
    if (phdr->p_filesz)
218
0
      memcpy(dst, src, phdr->p_filesz);
219
0
    if (phdr->p_filesz != phdr->p_memsz)
220
0
      memset(dst + phdr->p_filesz, 0x00,
221
0
             phdr->p_memsz - phdr->p_filesz);
222
0
    flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
223
0
          roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
224
0
  }
225
226
0
  return ehdr->e_entry;
227
0
}
228
229
unsigned long load_elf_image_shdr(unsigned long addr)
230
0
{
231
0
  Elf32_Ehdr *ehdr; /* Elf header structure pointer */
232
0
  Elf32_Shdr *shdr; /* Section header structure pointer */
233
0
  unsigned char *strtab = 0; /* String table pointer */
234
0
  unsigned char *image; /* Binary image pointer */
235
0
  int i; /* Loop counter */
236
237
0
  ehdr = (Elf32_Ehdr *)addr;
238
0
  if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
239
0
    return load_elf64_image_shdr(addr);
240
241
  /* Find the section header string table for output info */
242
0
  shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
243
0
           (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
244
245
0
  if (shdr->sh_type == SHT_STRTAB)
246
0
    strtab = (unsigned char *)(addr + shdr->sh_offset);
247
248
  /* Load each appropriate section */
249
0
  for (i = 0; i < ehdr->e_shnum; ++i) {
250
0
    shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
251
0
             (i * sizeof(Elf32_Shdr)));
252
253
0
    if (!(shdr->sh_flags & SHF_ALLOC) ||
254
0
        shdr->sh_addr == 0 || shdr->sh_size == 0) {
255
0
      continue;
256
0
    }
257
258
0
    if (strtab) {
259
0
      debug("%sing %s @ 0x%08lx (%ld bytes)\n",
260
0
            (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
261
0
             &strtab[shdr->sh_name],
262
0
             (unsigned long)shdr->sh_addr,
263
0
             (long)shdr->sh_size);
264
0
    }
265
266
0
    if (shdr->sh_type == SHT_NOBITS) {
267
0
      memset((void *)(uintptr_t)shdr->sh_addr, 0,
268
0
             shdr->sh_size);
269
0
    } else {
270
0
      image = (unsigned char *)addr + shdr->sh_offset;
271
0
      memcpy((void *)(uintptr_t)shdr->sh_addr,
272
0
             (const void *)image, shdr->sh_size);
273
0
    }
274
0
    flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
275
0
          roundup((shdr->sh_addr + shdr->sh_size),
276
0
            ARCH_DMA_MINALIGN) -
277
0
          rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
278
0
  }
279
280
0
  return ehdr->e_entry;
281
0
}
282
283
/*
284
 * Determine if a valid ELF image exists at the given memory location.
285
 * First look at the ELF header magic field, then make sure that it is
286
 * executable.
287
 */
288
int valid_elf_image(unsigned long addr)
289
0
{
290
0
  Elf32_Ehdr *ehdr; /* Elf header structure pointer */
291
292
0
  ehdr = (Elf32_Ehdr *)addr;
293
294
0
  if (!IS_ELF(*ehdr)) {
295
0
    printf("## No elf image at address 0x%08lx\n", addr);
296
0
    return 0;
297
0
  }
298
299
0
  if (ehdr->e_type != ET_EXEC) {
300
0
    printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
301
0
    return 0;
302
0
  }
303
304
0
  return 1;
305
0
}