]> Git Repo - u-boot.git/blob - lib/elf.c
Support setting a maximum size for the VPL image
[u-boot.git] / lib / elf.c
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 {
29         return entry(argc, argv);
30 }
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 {
48         unsigned long entry_addr;
49         char *args[] = {"", NULL};
50
51         errno = 0;
52
53         if (!valid_elf_image(addr)) {
54                 errno = ENOEXEC;
55                 return 1;
56         }
57
58         entry_addr = flags.phdr ? load_elf_image_phdr(addr)
59                                             : load_elf_image_shdr(addr);
60
61         if (!flags.autostart)
62                 return 0;
63
64         if (!argc && !argv) {
65                 argc = 1;
66                 argv = args;
67         }
68
69         return bootelf_exec((void *)entry_addr, argc, argv);
70 }
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 {
81         Elf64_Ehdr *ehdr; /* Elf header structure pointer */
82         Elf64_Phdr *phdr; /* Program header structure pointer */
83         int i;
84
85         ehdr = (Elf64_Ehdr *)addr;
86         phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
87
88         /* Load each program header */
89         for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
90                 void *dst = (void *)(ulong)phdr->p_paddr;
91                 void *src = (void *)addr + phdr->p_offset;
92
93                 /* Only load PT_LOAD program header */
94                 if (phdr->p_type != PT_LOAD)
95                         continue;
96
97                 debug("Loading phdr %i to 0x%p (%lu bytes)\n",
98                       i, dst, (ulong)phdr->p_filesz);
99                 if (phdr->p_filesz)
100                         memcpy(dst, src, phdr->p_filesz);
101                 if (phdr->p_filesz != phdr->p_memsz)
102                         memset(dst + phdr->p_filesz, 0x00,
103                                phdr->p_memsz - phdr->p_filesz);
104                 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
105                             roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
106         }
107
108         if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
109                                             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                 uintptr_t addr = ehdr->e_entry;
116
117                 return *(Elf64_Addr *)addr;
118         }
119
120         return ehdr->e_entry;
121 }
122
123 unsigned long load_elf64_image_shdr(unsigned long addr)
124 {
125         Elf64_Ehdr *ehdr; /* Elf header structure pointer */
126         Elf64_Shdr *shdr; /* Section header structure pointer */
127         unsigned char *strtab = 0; /* String table pointer */
128         unsigned char *image; /* Binary image pointer */
129         int i; /* Loop counter */
130
131         ehdr = (Elf64_Ehdr *)addr;
132
133         /* Find the section header string table for output info */
134         shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
135                              (ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
136
137         if (shdr->sh_type == SHT_STRTAB)
138                 strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
139
140         /* Load each appropriate section */
141         for (i = 0; i < ehdr->e_shnum; ++i) {
142                 shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
143                                      (i * sizeof(Elf64_Shdr)));
144
145                 if (!(shdr->sh_flags & SHF_ALLOC) ||
146                     shdr->sh_addr == 0 || shdr->sh_size == 0) {
147                         continue;
148                 }
149
150                 if (strtab) {
151                         debug("%sing %s @ 0x%08lx (%ld bytes)\n",
152                               (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
153                                &strtab[shdr->sh_name],
154                                (unsigned long)shdr->sh_addr,
155                                (long)shdr->sh_size);
156                 }
157
158                 if (shdr->sh_type == SHT_NOBITS) {
159                         memset((void *)(uintptr_t)shdr->sh_addr, 0,
160                                shdr->sh_size);
161                 } else {
162                         image = (unsigned char *)addr + (ulong)shdr->sh_offset;
163                         memcpy((void *)(uintptr_t)shdr->sh_addr,
164                                (const void *)image, shdr->sh_size);
165                 }
166                 flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
167                             roundup((shdr->sh_addr + shdr->sh_size),
168                                      ARCH_DMA_MINALIGN) -
169                                 rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
170         }
171
172         if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
173                                             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                 uintptr_t addr = ehdr->e_entry;
180
181                 return *(Elf64_Addr *)addr;
182         }
183
184         return ehdr->e_entry;
185 }
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 {
196         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
197         Elf32_Phdr *phdr; /* Program header structure pointer */
198         int i;
199
200         ehdr = (Elf32_Ehdr *)addr;
201         if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
202                 return load_elf64_image_phdr(addr);
203
204         phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
205
206         /* Load each program header */
207         for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
208                 void *dst = (void *)(uintptr_t)phdr->p_paddr;
209                 void *src = (void *)addr + phdr->p_offset;
210
211                 /* Only load PT_LOAD program header */
212                 if (phdr->p_type != PT_LOAD)
213                         continue;
214
215                 debug("Loading phdr %i to 0x%p (%i bytes)\n",
216                       i, dst, phdr->p_filesz);
217                 if (phdr->p_filesz)
218                         memcpy(dst, src, phdr->p_filesz);
219                 if (phdr->p_filesz != phdr->p_memsz)
220                         memset(dst + phdr->p_filesz, 0x00,
221                                phdr->p_memsz - phdr->p_filesz);
222                 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
223                             roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
224         }
225
226         return ehdr->e_entry;
227 }
228
229 unsigned long load_elf_image_shdr(unsigned long addr)
230 {
231         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
232         Elf32_Shdr *shdr; /* Section header structure pointer */
233         unsigned char *strtab = 0; /* String table pointer */
234         unsigned char *image; /* Binary image pointer */
235         int i; /* Loop counter */
236
237         ehdr = (Elf32_Ehdr *)addr;
238         if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
239                 return load_elf64_image_shdr(addr);
240
241         /* Find the section header string table for output info */
242         shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
243                              (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
244
245         if (shdr->sh_type == SHT_STRTAB)
246                 strtab = (unsigned char *)(addr + shdr->sh_offset);
247
248         /* Load each appropriate section */
249         for (i = 0; i < ehdr->e_shnum; ++i) {
250                 shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
251                                      (i * sizeof(Elf32_Shdr)));
252
253                 if (!(shdr->sh_flags & SHF_ALLOC) ||
254                     shdr->sh_addr == 0 || shdr->sh_size == 0) {
255                         continue;
256                 }
257
258                 if (strtab) {
259                         debug("%sing %s @ 0x%08lx (%ld bytes)\n",
260                               (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
261                                &strtab[shdr->sh_name],
262                                (unsigned long)shdr->sh_addr,
263                                (long)shdr->sh_size);
264                 }
265
266                 if (shdr->sh_type == SHT_NOBITS) {
267                         memset((void *)(uintptr_t)shdr->sh_addr, 0,
268                                shdr->sh_size);
269                 } else {
270                         image = (unsigned char *)addr + shdr->sh_offset;
271                         memcpy((void *)(uintptr_t)shdr->sh_addr,
272                                (const void *)image, shdr->sh_size);
273                 }
274                 flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
275                             roundup((shdr->sh_addr + shdr->sh_size),
276                                     ARCH_DMA_MINALIGN) -
277                             rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
278         }
279
280         return ehdr->e_entry;
281 }
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 {
290         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
291
292         ehdr = (Elf32_Ehdr *)addr;
293
294         if (!IS_ELF(*ehdr)) {
295                 printf("## No elf image at address 0x%08lx\n", addr);
296                 return 0;
297         }
298
299         if (ehdr->e_type != ET_EXEC) {
300                 printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
301                 return 0;
302         }
303
304         return 1;
305 }
This page took 0.041248 seconds and 4 git commands to generate.