blob: e767a42a3b3f16e38acb4beb40fceaf9bd29b41e [file] [log] [blame]
Keerthy76f361a2020-02-12 13:55:03 +05301// SPDX-License-Identifier: BSD-2-Clause
2/*
3 Copyright (c) 2001 William L. Pitts
4*/
5
Keerthy76f361a2020-02-12 13:55:03 +05306#include <command.h>
7#include <cpu_func.h>
8#include <elf.h>
9#include <env.h>
Maxim Moskaletse4170b82024-06-05 21:43:34 +030010#include <errno.h>
Keerthy76f361a2020-02-12 13:55:03 +053011#include <net.h>
12#include <vxworks.h>
13#ifdef CONFIG_X86
Simon Glassec86bc62022-07-30 15:52:04 -060014#include <vesa.h>
Keerthy76f361a2020-02-12 13:55:03 +053015#include <asm/e820.h>
16#include <linux/linkage.h>
17#endif
18
Maxim Moskaletse4170b82024-06-05 21:43:34 +030019/**
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 */
26unsigned 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 */
45unsigned 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
Keerthy76f361a2020-02-12 13:55:03 +053072/*
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 */
79unsigned 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 */
Maxim Moskaletsd1791422024-08-17 14:02:22 +030089 for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
Keerthy76f361a2020-02-12 13:55:03 +053090 void *dst = (void *)(ulong)phdr->p_paddr;
91 void *src = (void *)addr + phdr->p_offset;
92
JianfengA.Zhu@sony.com0e49fd12024-08-07 02:20:07 +000093 /* Only load PT_LOAD program header */
94 if (phdr->p_type != PT_LOAD)
95 continue;
96
Keerthy76f361a2020-02-12 13:55:03 +053097 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));
Keerthy76f361a2020-02-12 13:55:03 +0530106 }
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
123unsigned 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 */
194unsigned 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 */
Maxim Moskaletsd1791422024-08-17 14:02:22 +0300207 for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
Keerthy76f361a2020-02-12 13:55:03 +0530208 void *dst = (void *)(uintptr_t)phdr->p_paddr;
209 void *src = (void *)addr + phdr->p_offset;
210
JianfengA.Zhu@sony.com0e49fd12024-08-07 02:20:07 +0000211 /* Only load PT_LOAD program header */
212 if (phdr->p_type != PT_LOAD)
213 continue;
214
Keerthy76f361a2020-02-12 13:55:03 +0530215 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));
Keerthy76f361a2020-02-12 13:55:03 +0530224 }
225
226 return ehdr->e_entry;
227}
228
229unsigned 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 */
288int 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}