• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2001 William L. Pitts
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  */
15 
16 #include <common.h>
17 #include <command.h>
18 #include <cpu_func.h>
19 #include <elf.h>
20 #include <env.h>
21 #include <net.h>
22 #include <vxworks.h>
23 #ifdef CONFIG_X86
24 #include <vbe.h>
25 #include <asm/e820.h>
26 #include <linux/linkage.h>
27 #endif
28 
29 /*
30  * A very simple ELF64 loader, assumes the image is valid, returns the
31  * entry point address.
32  *
33  * Note if U-Boot is 32-bit, the loader assumes the to segment's
34  * physical address and size is within the lower 32-bit address space.
35  */
load_elf64_image_phdr(unsigned long addr)36 static unsigned long load_elf64_image_phdr(unsigned long addr)
37 {
38 	Elf64_Ehdr *ehdr; /* Elf header structure pointer */
39 	Elf64_Phdr *phdr; /* Program header structure pointer */
40 	int i;
41 
42 	ehdr = (Elf64_Ehdr *)addr;
43 	phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
44 
45 	/* Load each program header */
46 	for (i = 0; i < ehdr->e_phnum; ++i) {
47 		void *dst = (void *)(ulong)phdr->p_paddr;
48 		void *src = (void *)addr + phdr->p_offset;
49 
50 		debug("Loading phdr %i to 0x%p (%lu bytes)\n",
51 		      i, dst, (ulong)phdr->p_filesz);
52 		if (phdr->p_filesz)
53 			memcpy(dst, src, phdr->p_filesz);
54 		if (phdr->p_filesz != phdr->p_memsz)
55 			memset(dst + phdr->p_filesz, 0x00,
56 			       phdr->p_memsz - phdr->p_filesz);
57 		flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
58 			    roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
59 		++phdr;
60 	}
61 
62 	if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
63 					    EF_PPC64_ELFV1_ABI)) {
64 		/*
65 		 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
66 		 * descriptor pointer with the first double word being the
67 		 * address of the entry point of the function.
68 		 */
69 		uintptr_t addr = ehdr->e_entry;
70 
71 		return *(Elf64_Addr *)addr;
72 	}
73 
74 	return ehdr->e_entry;
75 }
76 
load_elf64_image_shdr(unsigned long addr)77 static unsigned long load_elf64_image_shdr(unsigned long addr)
78 {
79 	Elf64_Ehdr *ehdr; /* Elf header structure pointer */
80 	Elf64_Shdr *shdr; /* Section header structure pointer */
81 	unsigned char *strtab = 0; /* String table pointer */
82 	unsigned char *image; /* Binary image pointer */
83 	int i; /* Loop counter */
84 
85 	ehdr = (Elf64_Ehdr *)addr;
86 
87 	/* Find the section header string table for output info */
88 	shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
89 			     (ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
90 
91 	if (shdr->sh_type == SHT_STRTAB)
92 		strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
93 
94 	/* Load each appropriate section */
95 	for (i = 0; i < ehdr->e_shnum; ++i) {
96 		shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
97 				     (i * sizeof(Elf64_Shdr)));
98 
99 		if (!(shdr->sh_flags & SHF_ALLOC) ||
100 		    shdr->sh_addr == 0 || shdr->sh_size == 0) {
101 			continue;
102 		}
103 
104 		if (strtab) {
105 			debug("%sing %s @ 0x%08lx (%ld bytes)\n",
106 			      (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
107 			       &strtab[shdr->sh_name],
108 			       (unsigned long)shdr->sh_addr,
109 			       (long)shdr->sh_size);
110 		}
111 
112 		if (shdr->sh_type == SHT_NOBITS) {
113 			memset((void *)(uintptr_t)shdr->sh_addr, 0,
114 			       shdr->sh_size);
115 		} else {
116 			image = (unsigned char *)addr + (ulong)shdr->sh_offset;
117 			memcpy((void *)(uintptr_t)shdr->sh_addr,
118 			       (const void *)image, shdr->sh_size);
119 		}
120 		flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
121 			    roundup((shdr->sh_addr + shdr->sh_size),
122 				     ARCH_DMA_MINALIGN) -
123 			            rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
124 	}
125 
126 	if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
127 					    EF_PPC64_ELFV1_ABI)) {
128 		/*
129 		 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
130 		 * descriptor pointer with the first double word being the
131 		 * address of the entry point of the function.
132 		 */
133 		uintptr_t addr = ehdr->e_entry;
134 
135 		return *(Elf64_Addr *)addr;
136 	}
137 
138 	return ehdr->e_entry;
139 }
140 
141 /*
142  * A very simple ELF loader, assumes the image is valid, returns the
143  * entry point address.
144  *
145  * The loader firstly reads the EFI class to see if it's a 64-bit image.
146  * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
147  */
load_elf_image_phdr(unsigned long addr)148 static unsigned long load_elf_image_phdr(unsigned long addr)
149 {
150 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
151 	Elf32_Phdr *phdr; /* Program header structure pointer */
152 	int i;
153 
154 	ehdr = (Elf32_Ehdr *)addr;
155 	if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
156 		return load_elf64_image_phdr(addr);
157 
158 	phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
159 
160 	/* Load each program header */
161 	for (i = 0; i < ehdr->e_phnum; ++i) {
162 		void *dst = (void *)(uintptr_t)phdr->p_paddr;
163 		void *src = (void *)addr + phdr->p_offset;
164 
165 		debug("Loading phdr %i to 0x%p (%i bytes)\n",
166 		      i, dst, phdr->p_filesz);
167 		if (phdr->p_filesz)
168 			memcpy(dst, src, phdr->p_filesz);
169 		if (phdr->p_filesz != phdr->p_memsz)
170 			memset(dst + phdr->p_filesz, 0x00,
171 			       phdr->p_memsz - phdr->p_filesz);
172 		flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
173 			    roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
174 		++phdr;
175 	}
176 
177 	return ehdr->e_entry;
178 }
179 
load_elf_image_shdr(unsigned long addr)180 static unsigned long load_elf_image_shdr(unsigned long addr)
181 {
182 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
183 	Elf32_Shdr *shdr; /* Section header structure pointer */
184 	unsigned char *strtab = 0; /* String table pointer */
185 	unsigned char *image; /* Binary image pointer */
186 	int i; /* Loop counter */
187 
188 	ehdr = (Elf32_Ehdr *)addr;
189 	if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
190 		return load_elf64_image_shdr(addr);
191 
192 	/* Find the section header string table for output info */
193 	shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
194 			     (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
195 
196 	if (shdr->sh_type == SHT_STRTAB)
197 		strtab = (unsigned char *)(addr + shdr->sh_offset);
198 
199 	/* Load each appropriate section */
200 	for (i = 0; i < ehdr->e_shnum; ++i) {
201 		shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
202 				     (i * sizeof(Elf32_Shdr)));
203 
204 		if (!(shdr->sh_flags & SHF_ALLOC) ||
205 		    shdr->sh_addr == 0 || shdr->sh_size == 0) {
206 			continue;
207 		}
208 
209 		if (strtab) {
210 			debug("%sing %s @ 0x%08lx (%ld bytes)\n",
211 			      (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
212 			       &strtab[shdr->sh_name],
213 			       (unsigned long)shdr->sh_addr,
214 			       (long)shdr->sh_size);
215 		}
216 
217 		if (shdr->sh_type == SHT_NOBITS) {
218 			memset((void *)(uintptr_t)shdr->sh_addr, 0,
219 			       shdr->sh_size);
220 		} else {
221 			image = (unsigned char *)addr + shdr->sh_offset;
222 			memcpy((void *)(uintptr_t)shdr->sh_addr,
223 			       (const void *)image, shdr->sh_size);
224 		}
225 		flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN),
226 			    roundup((shdr->sh_addr + shdr->sh_size),
227 				    ARCH_DMA_MINALIGN) -
228 			    rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN));
229 	}
230 
231 	return ehdr->e_entry;
232 }
233 
234 /* Allow ports to override the default behavior */
do_bootelf_exec(ulong (* entry)(int,char * const[]),int argc,char * const argv[])235 static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
236 				     int argc, char * const argv[])
237 {
238 	unsigned long ret;
239 
240 	/*
241 	 * pass address parameter as argv[0] (aka command name),
242 	 * and all remaining args
243 	 */
244 	ret = entry(argc, argv);
245 
246 	return ret;
247 }
248 
249 /*
250  * Determine if a valid ELF image exists at the given memory location.
251  * First look at the ELF header magic field, then make sure that it is
252  * executable.
253  */
valid_elf_image(unsigned long addr)254 int valid_elf_image(unsigned long addr)
255 {
256 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
257 
258 	ehdr = (Elf32_Ehdr *)addr;
259 
260 	if (!IS_ELF(*ehdr)) {
261 		printf("## No elf image at address 0x%08lx\n", addr);
262 		return 0;
263 	}
264 
265 	if (ehdr->e_type != ET_EXEC) {
266 		printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
267 		return 0;
268 	}
269 
270 	return 1;
271 }
272 
273 /* Interpreter command to boot an arbitrary ELF image from memory */
do_bootelf(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])274 int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
275 {
276 	unsigned long addr; /* Address of the ELF image */
277 	unsigned long rc; /* Return value from user code */
278 	char *sload = NULL;
279 	const char *ep = env_get("autostart");
280 	int rcode = 0;
281 
282 	/* Consume 'bootelf' */
283 	argc--; argv++;
284 
285 	/* Check for flag. */
286 	if (argc >= 1 && (argv[0][0] == '-' && \
287 				(argv[0][1] == 'p' || argv[0][1] == 's'))) {
288 		sload = argv[0];
289 		/* Consume flag. */
290 		argc--; argv++;
291 	}
292 	/* Check for address. */
293 	if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
294 		/* Consume address */
295 		argc--; argv++;
296 	} else
297 		addr = load_addr;
298 
299 	if (!valid_elf_image(addr))
300 		return 1;
301 
302 	if (sload && sload[1] == 'p')
303 		addr = load_elf_image_phdr(addr);
304 	else
305 		addr = load_elf_image_shdr(addr);
306 
307 	if (ep && !strcmp(ep, "no"))
308 		return rcode;
309 
310 	printf("## Starting application at 0x%08lx ...\n", addr);
311 
312 	/*
313 	 * pass address parameter as argv[0] (aka command name),
314 	 * and all remaining args
315 	 */
316 	rc = do_bootelf_exec((void *)addr, argc, argv);
317 	if (rc != 0)
318 		rcode = 1;
319 
320 	printf("## Application terminated, rc = 0x%lx\n", rc);
321 
322 	return rcode;
323 }
324 
325 /*
326  * Interpreter command to boot VxWorks from a memory image.  The image can
327  * be either an ELF image or a raw binary.  Will attempt to setup the
328  * bootline and other parameters correctly.
329  */
do_bootvx(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])330 int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
331 {
332 	unsigned long addr; /* Address of image */
333 	unsigned long bootaddr = 0; /* Address to put the bootline */
334 	char *bootline; /* Text of the bootline */
335 	char *tmp; /* Temporary char pointer */
336 	char build_buf[128]; /* Buffer for building the bootline */
337 	int ptr = 0;
338 #ifdef CONFIG_X86
339 	ulong base;
340 	struct e820_info *info;
341 	struct e820_entry *data;
342 	struct efi_gop_info *gop;
343 	struct vesa_mode_info *vesa = &mode_info.vesa;
344 #endif
345 
346 	/*
347 	 * Check the loadaddr variable.
348 	 * If we don't know where the image is then we're done.
349 	 */
350 	if (argc < 2)
351 		addr = load_addr;
352 	else
353 		addr = simple_strtoul(argv[1], NULL, 16);
354 
355 #if defined(CONFIG_CMD_NET)
356 	/*
357 	 * Check to see if we need to tftp the image ourselves
358 	 * before starting
359 	 */
360 	if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
361 		if (net_loop(TFTPGET) <= 0)
362 			return 1;
363 		printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
364 			addr);
365 	}
366 #endif
367 
368 	/*
369 	 * This should equate to
370 	 * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
371 	 * from the VxWorks BSP header files.
372 	 * This will vary from board to board
373 	 */
374 #if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
375 	tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
376 	eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
377 	memcpy(tmp, build_buf, 6);
378 #else
379 	puts("## Ethernet MAC address not copied to NV RAM\n");
380 #endif
381 
382 #ifdef CONFIG_X86
383 	/*
384 	 * Get VxWorks's physical memory base address from environment,
385 	 * if we don't specify it in the environment, use a default one.
386 	 */
387 	base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
388 	data = (struct e820_entry *)(base + E820_DATA_OFFSET);
389 	info = (struct e820_info *)(base + E820_INFO_OFFSET);
390 
391 	memset(info, 0, sizeof(struct e820_info));
392 	info->sign = E820_SIGNATURE;
393 	info->entries = install_e820_map(E820MAX, data);
394 	info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
395 		     E820_DATA_OFFSET;
396 
397 	/*
398 	 * Explicitly clear the bootloader image size otherwise if memory
399 	 * at this offset happens to contain some garbage data, the final
400 	 * available memory size for the kernel is insane.
401 	 */
402 	*(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
403 
404 	/*
405 	 * Prepare compatible framebuffer information block.
406 	 * The VESA mode has to be 32-bit RGBA.
407 	 */
408 	if (vesa->x_resolution && vesa->y_resolution) {
409 		gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
410 		gop->magic = EFI_GOP_INFO_MAGIC;
411 		gop->info.version = 0;
412 		gop->info.width = vesa->x_resolution;
413 		gop->info.height = vesa->y_resolution;
414 		gop->info.pixel_format = EFI_GOT_RGBA8;
415 		gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
416 		gop->fb_base = vesa->phys_base_ptr;
417 		gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
418 	}
419 #endif
420 
421 	/*
422 	 * Use bootaddr to find the location in memory that VxWorks
423 	 * will look for the bootline string. The default value is
424 	 * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
425 	 * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
426 	 */
427 	tmp = env_get("bootaddr");
428 	if (!tmp) {
429 #ifdef CONFIG_X86
430 		bootaddr = base + X86_BOOT_LINE_OFFSET;
431 #else
432 		printf("## VxWorks bootline address not specified\n");
433 		return 1;
434 #endif
435 	}
436 
437 	if (!bootaddr)
438 		bootaddr = simple_strtoul(tmp, NULL, 16);
439 
440 	/*
441 	 * Check to see if the bootline is defined in the 'bootargs' parameter.
442 	 * If it is not defined, we may be able to construct the info.
443 	 */
444 	bootline = env_get("bootargs");
445 	if (!bootline) {
446 		tmp = env_get("bootdev");
447 		if (tmp) {
448 			strcpy(build_buf, tmp);
449 			ptr = strlen(tmp);
450 		} else {
451 			printf("## VxWorks boot device not specified\n");
452 		}
453 
454 		tmp = env_get("bootfile");
455 		if (tmp)
456 			ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
457 		else
458 			ptr += sprintf(build_buf + ptr, "host:vxWorks ");
459 
460 		/*
461 		 * The following parameters are only needed if 'bootdev'
462 		 * is an ethernet device, otherwise they are optional.
463 		 */
464 		tmp = env_get("ipaddr");
465 		if (tmp) {
466 			ptr += sprintf(build_buf + ptr, "e=%s", tmp);
467 			tmp = env_get("netmask");
468 			if (tmp) {
469 				u32 mask = env_get_ip("netmask").s_addr;
470 				ptr += sprintf(build_buf + ptr,
471 					       ":%08x ", ntohl(mask));
472 			} else {
473 				ptr += sprintf(build_buf + ptr, " ");
474 			}
475 		}
476 
477 		tmp = env_get("serverip");
478 		if (tmp)
479 			ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
480 
481 		tmp = env_get("gatewayip");
482 		if (tmp)
483 			ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
484 
485 		tmp = env_get("hostname");
486 		if (tmp)
487 			ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
488 
489 		tmp = env_get("othbootargs");
490 		if (tmp) {
491 			strcpy(build_buf + ptr, tmp);
492 			ptr += strlen(tmp);
493 		}
494 
495 		bootline = build_buf;
496 	}
497 
498 	memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
499 	flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
500 	printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
501 
502 	/*
503 	 * If the data at the load address is an elf image, then
504 	 * treat it like an elf image. Otherwise, assume that it is a
505 	 * binary image.
506 	 */
507 	if (valid_elf_image(addr))
508 		addr = load_elf_image_phdr(addr);
509 	else
510 		puts("## Not an ELF image, assuming binary\n");
511 
512 	printf("## Starting vxWorks at 0x%08lx ...\n", addr);
513 
514 	dcache_disable();
515 #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
516 	armv8_setup_psci();
517 	smp_kick_all_cpus();
518 #endif
519 
520 #ifdef CONFIG_X86
521 	/* VxWorks on x86 uses stack to pass parameters */
522 	((asmlinkage void (*)(int))addr)(0);
523 #else
524 	((void (*)(int))addr)(0);
525 #endif
526 
527 	puts("## vxWorks terminated\n");
528 
529 	return 1;
530 }
531 
532 U_BOOT_CMD(
533 	bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
534 	"Boot from an ELF image in memory",
535 	"[-p|-s] [address]\n"
536 	"\t- load ELF image at [address] via program headers (-p)\n"
537 	"\t  or via section headers (-s)"
538 );
539 
540 U_BOOT_CMD(
541 	bootvx, 2, 0, do_bootvx,
542 	"Boot vxWorks from an ELF image",
543 	" [address] - load address of vxWorks ELF image."
544 );
545