blob: 28ec87b8e4827537a0e8122fd55d0facdf7b9c02 [file] [log] [blame]
Keerthy805b3ca2020-02-12 13:55:03 +05301// SPDX-License-Identifier: BSD-2-Clause
2/*
3 Copyright (c) 2001 William L. Pitts
4*/
5
Keerthy805b3ca2020-02-12 13:55:03 +05306#include <command.h>
7#include <cpu_func.h>
8#include <elf.h>
9#include <env.h>
Maxim Moskalets46b6a3e2024-06-05 21:43:34 +030010#include <errno.h>
Keerthy805b3ca2020-02-12 13:55:03 +053011#include <net.h>
12#include <vxworks.h>
13#ifdef CONFIG_X86
Simon Glasscafe8712022-07-30 15:52:04 -060014#include <vesa.h>
Keerthy805b3ca2020-02-12 13:55:03 +053015#include <asm/e820.h>
16#include <linux/linkage.h>
17#endif
18
Maxim Moskalets46b6a3e2024-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
Keerthy805b3ca2020-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 */
89 for (i = 0; i < ehdr->e_phnum; ++i) {
90 void *dst = (void *)(ulong)phdr->p_paddr;
91 void *src = (void *)addr + phdr->p_offset;
92
JianfengA.Zhu@sony.com37dc8c22024-08-07 02:20:07 +000093 /* Only load PT_LOAD program header */
94 if (phdr->p_type != PT_LOAD)
95 continue;
96
Keerthy805b3ca2020-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));
106 ++phdr;
107 }
108
109 if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
110 EF_PPC64_ELFV1_ABI)) {
111 /*
112 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
113 * descriptor pointer with the first double word being the
114 * address of the entry point of the function.
115 */
116 uintptr_t addr = ehdr->e_entry;
117
118 return *(Elf64_Addr *)addr;
119 }
120
121 return ehdr->e_entry;
122}
123
124unsigned long load_elf64_image_shdr(unsigned long addr)
125{
126 Elf64_Ehdr *ehdr; /* Elf header structure pointer */
127 Elf64_Shdr *shdr; /* Section header structure pointer */
128 unsigned char *strtab = 0; /* String table pointer */
129 unsigned char *image; /* Binary image pointer */
130 int i; /* Loop counter */
131
132 ehdr = (Elf64_Ehdr *)addr;
133
134 /* Find the section header string table for output info */
135 shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
136 (ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
137
138 if (shdr->sh_type == SHT_STRTAB)
139 strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
140
141 /* Load each appropriate section */
142 for (i = 0; i < ehdr->e_shnum; ++i) {
143 shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
144 (i * sizeof(Elf64_Shdr)));
145
146 if (!(shdr->sh_flags & SHF_ALLOC) ||
147 shdr->sh_addr == 0 || shdr->sh_size == 0) {
148 continue;
149 }
150
151 if (strtab) {
152 debug("%sing %s @ 0x%08lx (%ld bytes)\n",
153 (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
154 &strtab[shdr->sh_name],
155 (unsigned long)shdr->sh_addr,
156 (long)shdr->sh_size);
157 }
158
159 if (shdr->sh_type == SHT_NOBITS) {
160 memset((void *)(uintptr_t)shdr->sh_addr, 0,
161 shdr->sh_size);
162 } else {
163 image = (unsigned char *)addr + (ulong)shdr->sh_offset;
164 memcpy((void *)(uintptr_t)shdr->sh_addr,
165 (const void *)image, shdr->sh_size);
166 }
167 flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
168 roundup((shdr->sh_addr + shdr->sh_size),
169 ARCH_DMA_MINALIGN) -
170 rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
171 }
172
173 if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
174 EF_PPC64_ELFV1_ABI)) {
175 /*
176 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
177 * descriptor pointer with the first double word being the
178 * address of the entry point of the function.
179 */
180 uintptr_t addr = ehdr->e_entry;
181
182 return *(Elf64_Addr *)addr;
183 }
184
185 return ehdr->e_entry;
186}
187
188/*
189 * A very simple ELF loader, assumes the image is valid, returns the
190 * entry point address.
191 *
192 * The loader firstly reads the EFI class to see if it's a 64-bit image.
193 * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
194 */
195unsigned long load_elf_image_phdr(unsigned long addr)
196{
197 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
198 Elf32_Phdr *phdr; /* Program header structure pointer */
199 int i;
200
201 ehdr = (Elf32_Ehdr *)addr;
202 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
203 return load_elf64_image_phdr(addr);
204
205 phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
206
207 /* Load each program header */
208 for (i = 0; i < ehdr->e_phnum; ++i) {
209 void *dst = (void *)(uintptr_t)phdr->p_paddr;
210 void *src = (void *)addr + phdr->p_offset;
211
JianfengA.Zhu@sony.com37dc8c22024-08-07 02:20:07 +0000212 /* Only load PT_LOAD program header */
213 if (phdr->p_type != PT_LOAD)
214 continue;
215
Keerthy805b3ca2020-02-12 13:55:03 +0530216 debug("Loading phdr %i to 0x%p (%i bytes)\n",
217 i, dst, phdr->p_filesz);
218 if (phdr->p_filesz)
219 memcpy(dst, src, phdr->p_filesz);
220 if (phdr->p_filesz != phdr->p_memsz)
221 memset(dst + phdr->p_filesz, 0x00,
222 phdr->p_memsz - phdr->p_filesz);
223 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
224 roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
225 ++phdr;
226 }
227
228 return ehdr->e_entry;
229}
230
231unsigned long load_elf_image_shdr(unsigned long addr)
232{
233 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
234 Elf32_Shdr *shdr; /* Section header structure pointer */
235 unsigned char *strtab = 0; /* String table pointer */
236 unsigned char *image; /* Binary image pointer */
237 int i; /* Loop counter */
238
239 ehdr = (Elf32_Ehdr *)addr;
240 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
241 return load_elf64_image_shdr(addr);
242
243 /* Find the section header string table for output info */
244 shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
245 (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
246
247 if (shdr->sh_type == SHT_STRTAB)
248 strtab = (unsigned char *)(addr + shdr->sh_offset);
249
250 /* Load each appropriate section */
251 for (i = 0; i < ehdr->e_shnum; ++i) {
252 shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
253 (i * sizeof(Elf32_Shdr)));
254
255 if (!(shdr->sh_flags & SHF_ALLOC) ||
256 shdr->sh_addr == 0 || shdr->sh_size == 0) {
257 continue;
258 }
259
260 if (strtab) {
261 debug("%sing %s @ 0x%08lx (%ld bytes)\n",
262 (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
263 &strtab[shdr->sh_name],
264 (unsigned long)shdr->sh_addr,
265 (long)shdr->sh_size);
266 }
267
268 if (shdr->sh_type == SHT_NOBITS) {
269 memset((void *)(uintptr_t)shdr->sh_addr, 0,
270 shdr->sh_size);
271 } else {
272 image = (unsigned char *)addr + shdr->sh_offset;
273 memcpy((void *)(uintptr_t)shdr->sh_addr,
274 (const void *)image, shdr->sh_size);
275 }
276 flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
277 roundup((shdr->sh_addr + shdr->sh_size),
278 ARCH_DMA_MINALIGN) -
279 rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
280 }
281
282 return ehdr->e_entry;
283}
284
285/*
286 * Determine if a valid ELF image exists at the given memory location.
287 * First look at the ELF header magic field, then make sure that it is
288 * executable.
289 */
290int valid_elf_image(unsigned long addr)
291{
292 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
293
294 ehdr = (Elf32_Ehdr *)addr;
295
296 if (!IS_ELF(*ehdr)) {
297 printf("## No elf image at address 0x%08lx\n", addr);
298 return 0;
299 }
300
301 if (ehdr->e_type != ET_EXEC) {
302 printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
303 return 0;
304 }
305
306 return 1;
307}