xref: /openbmc/u-boot/cmd/elf.c (revision 8996975f)
12e192b24SSimon Glass /*
22e192b24SSimon Glass  * Copyright (c) 2001 William L. Pitts
32e192b24SSimon Glass  * All rights reserved.
42e192b24SSimon Glass  *
52e192b24SSimon Glass  * Redistribution and use in source and binary forms are freely
62e192b24SSimon Glass  * permitted provided that the above copyright notice and this
72e192b24SSimon Glass  * paragraph and the following disclaimer are duplicated in all
82e192b24SSimon Glass  * such forms.
92e192b24SSimon Glass  *
102e192b24SSimon Glass  * This software is provided "AS IS" and without any express or
112e192b24SSimon Glass  * implied warranties, including, without limitation, the implied
122e192b24SSimon Glass  * warranties of merchantability and fitness for a particular
132e192b24SSimon Glass  * purpose.
142e192b24SSimon Glass  */
152e192b24SSimon Glass 
162e192b24SSimon Glass #include <common.h>
172e192b24SSimon Glass #include <command.h>
182e192b24SSimon Glass #include <elf.h>
192e192b24SSimon Glass #include <net.h>
202e192b24SSimon Glass #include <vxworks.h>
212e192b24SSimon Glass #ifdef CONFIG_X86
222e192b24SSimon Glass #include <asm/e820.h>
232e192b24SSimon Glass #include <linux/linkage.h>
242e192b24SSimon Glass #endif
252e192b24SSimon Glass 
262e192b24SSimon Glass /*
272e192b24SSimon Glass  * A very simple elf loader, assumes the image is valid, returns the
282e192b24SSimon Glass  * entry point address.
292e192b24SSimon Glass  */
302e192b24SSimon Glass static unsigned long load_elf_image_phdr(unsigned long addr)
312e192b24SSimon Glass {
322e192b24SSimon Glass 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
332e192b24SSimon Glass 	Elf32_Phdr *phdr; /* Program header structure pointer */
342e192b24SSimon Glass 	int i;
352e192b24SSimon Glass 
362e192b24SSimon Glass 	ehdr = (Elf32_Ehdr *)addr;
372e192b24SSimon Glass 	phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
382e192b24SSimon Glass 
392e192b24SSimon Glass 	/* Load each program header */
402e192b24SSimon Glass 	for (i = 0; i < ehdr->e_phnum; ++i) {
412e192b24SSimon Glass 		void *dst = (void *)(uintptr_t)phdr->p_paddr;
422e192b24SSimon Glass 		void *src = (void *)addr + phdr->p_offset;
432e192b24SSimon Glass 		debug("Loading phdr %i to 0x%p (%i bytes)\n",
442e192b24SSimon Glass 		      i, dst, phdr->p_filesz);
452e192b24SSimon Glass 		if (phdr->p_filesz)
462e192b24SSimon Glass 			memcpy(dst, src, phdr->p_filesz);
472e192b24SSimon Glass 		if (phdr->p_filesz != phdr->p_memsz)
482e192b24SSimon Glass 			memset(dst + phdr->p_filesz, 0x00,
492e192b24SSimon Glass 			       phdr->p_memsz - phdr->p_filesz);
502e192b24SSimon Glass 		flush_cache((unsigned long)dst, phdr->p_filesz);
512e192b24SSimon Glass 		++phdr;
522e192b24SSimon Glass 	}
532e192b24SSimon Glass 
542e192b24SSimon Glass 	return ehdr->e_entry;
552e192b24SSimon Glass }
562e192b24SSimon Glass 
572e192b24SSimon Glass static unsigned long load_elf_image_shdr(unsigned long addr)
582e192b24SSimon Glass {
592e192b24SSimon Glass 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
602e192b24SSimon Glass 	Elf32_Shdr *shdr; /* Section header structure pointer */
612e192b24SSimon Glass 	unsigned char *strtab = 0; /* String table pointer */
622e192b24SSimon Glass 	unsigned char *image; /* Binary image pointer */
632e192b24SSimon Glass 	int i; /* Loop counter */
642e192b24SSimon Glass 
652e192b24SSimon Glass 	ehdr = (Elf32_Ehdr *)addr;
662e192b24SSimon Glass 
672e192b24SSimon Glass 	/* Find the section header string table for output info */
682e192b24SSimon Glass 	shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
692e192b24SSimon Glass 			     (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
702e192b24SSimon Glass 
712e192b24SSimon Glass 	if (shdr->sh_type == SHT_STRTAB)
722e192b24SSimon Glass 		strtab = (unsigned char *)(addr + shdr->sh_offset);
732e192b24SSimon Glass 
742e192b24SSimon Glass 	/* Load each appropriate section */
752e192b24SSimon Glass 	for (i = 0; i < ehdr->e_shnum; ++i) {
762e192b24SSimon Glass 		shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
772e192b24SSimon Glass 				     (i * sizeof(Elf32_Shdr)));
782e192b24SSimon Glass 
792e192b24SSimon Glass 		if (!(shdr->sh_flags & SHF_ALLOC) ||
802e192b24SSimon Glass 		    shdr->sh_addr == 0 || shdr->sh_size == 0) {
812e192b24SSimon Glass 			continue;
822e192b24SSimon Glass 		}
832e192b24SSimon Glass 
842e192b24SSimon Glass 		if (strtab) {
852e192b24SSimon Glass 			debug("%sing %s @ 0x%08lx (%ld bytes)\n",
862e192b24SSimon Glass 			      (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
872e192b24SSimon Glass 			       &strtab[shdr->sh_name],
882e192b24SSimon Glass 			       (unsigned long)shdr->sh_addr,
892e192b24SSimon Glass 			       (long)shdr->sh_size);
902e192b24SSimon Glass 		}
912e192b24SSimon Glass 
922e192b24SSimon Glass 		if (shdr->sh_type == SHT_NOBITS) {
932e192b24SSimon Glass 			memset((void *)(uintptr_t)shdr->sh_addr, 0,
942e192b24SSimon Glass 			       shdr->sh_size);
952e192b24SSimon Glass 		} else {
962e192b24SSimon Glass 			image = (unsigned char *)addr + shdr->sh_offset;
972e192b24SSimon Glass 			memcpy((void *)(uintptr_t)shdr->sh_addr,
982e192b24SSimon Glass 			       (const void *)image, shdr->sh_size);
992e192b24SSimon Glass 		}
1002e192b24SSimon Glass 		flush_cache(shdr->sh_addr, shdr->sh_size);
1012e192b24SSimon Glass 	}
1022e192b24SSimon Glass 
1032e192b24SSimon Glass 	return ehdr->e_entry;
1042e192b24SSimon Glass }
1052e192b24SSimon Glass 
1062e192b24SSimon Glass /* Allow ports to override the default behavior */
1072e192b24SSimon Glass static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
1082e192b24SSimon Glass 				     int argc, char * const argv[])
1092e192b24SSimon Glass {
1102e192b24SSimon Glass 	unsigned long ret;
1112e192b24SSimon Glass 
1122e192b24SSimon Glass 	/*
1132e192b24SSimon Glass 	 * pass address parameter as argv[0] (aka command name),
1142e192b24SSimon Glass 	 * and all remaining args
1152e192b24SSimon Glass 	 */
1162e192b24SSimon Glass 	ret = entry(argc, argv);
1172e192b24SSimon Glass 
1182e192b24SSimon Glass 	return ret;
1192e192b24SSimon Glass }
1202e192b24SSimon Glass 
1212e192b24SSimon Glass /*
1222e192b24SSimon Glass  * Determine if a valid ELF image exists at the given memory location.
1232e192b24SSimon Glass  * First look at the ELF header magic field, then make sure that it is
1242e192b24SSimon Glass  * executable.
1252e192b24SSimon Glass  */
1262e192b24SSimon Glass int valid_elf_image(unsigned long addr)
1272e192b24SSimon Glass {
1282e192b24SSimon Glass 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
1292e192b24SSimon Glass 
1302e192b24SSimon Glass 	ehdr = (Elf32_Ehdr *)addr;
1312e192b24SSimon Glass 
1322e192b24SSimon Glass 	if (!IS_ELF(*ehdr)) {
1332e192b24SSimon Glass 		printf("## No elf image at address 0x%08lx\n", addr);
1342e192b24SSimon Glass 		return 0;
1352e192b24SSimon Glass 	}
1362e192b24SSimon Glass 
1372e192b24SSimon Glass 	if (ehdr->e_type != ET_EXEC) {
1382e192b24SSimon Glass 		printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
1392e192b24SSimon Glass 		return 0;
1402e192b24SSimon Glass 	}
1412e192b24SSimon Glass 
1422e192b24SSimon Glass 	return 1;
1432e192b24SSimon Glass }
1442e192b24SSimon Glass 
1452e192b24SSimon Glass /* Interpreter command to boot an arbitrary ELF image from memory */
1462e192b24SSimon Glass int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1472e192b24SSimon Glass {
1482e192b24SSimon Glass 	unsigned long addr; /* Address of the ELF image */
1492e192b24SSimon Glass 	unsigned long rc; /* Return value from user code */
150be1b8679STom Rini 	char *sload = NULL;
15100caae6dSSimon Glass 	const char *ep = env_get("autostart");
1522e192b24SSimon Glass 	int rcode = 0;
1532e192b24SSimon Glass 
154be1b8679STom Rini 	/* Consume 'bootelf' */
155be1b8679STom Rini 	argc--; argv++;
1562e192b24SSimon Glass 
157be1b8679STom Rini 	/* Check for flag. */
158be1b8679STom Rini 	if (argc >= 1 && (argv[0][0] == '-' && \
159be1b8679STom Rini 				(argv[0][1] == 'p' || argv[0][1] == 's'))) {
160be1b8679STom Rini 		sload = argv[0];
161be1b8679STom Rini 		/* Consume flag. */
162be1b8679STom Rini 		argc--; argv++;
163be1b8679STom Rini 	}
164be1b8679STom Rini 	/* Check for address. */
165be1b8679STom Rini 	if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
166be1b8679STom Rini 		/* Consume address */
167be1b8679STom Rini 		argc--; argv++;
168be1b8679STom Rini 	} else
1692e192b24SSimon Glass 		addr = load_addr;
1702e192b24SSimon Glass 
1712e192b24SSimon Glass 	if (!valid_elf_image(addr))
1722e192b24SSimon Glass 		return 1;
1732e192b24SSimon Glass 
1742e192b24SSimon Glass 	if (sload && sload[1] == 'p')
1752e192b24SSimon Glass 		addr = load_elf_image_phdr(addr);
1762e192b24SSimon Glass 	else
1772e192b24SSimon Glass 		addr = load_elf_image_shdr(addr);
1782e192b24SSimon Glass 
1792e192b24SSimon Glass 	if (ep && !strcmp(ep, "no"))
1802e192b24SSimon Glass 		return rcode;
1812e192b24SSimon Glass 
1822e192b24SSimon Glass 	printf("## Starting application at 0x%08lx ...\n", addr);
1832e192b24SSimon Glass 
1842e192b24SSimon Glass 	/*
1852e192b24SSimon Glass 	 * pass address parameter as argv[0] (aka command name),
1862e192b24SSimon Glass 	 * and all remaining args
1872e192b24SSimon Glass 	 */
188be1b8679STom Rini 	rc = do_bootelf_exec((void *)addr, argc, argv);
1892e192b24SSimon Glass 	if (rc != 0)
1902e192b24SSimon Glass 		rcode = 1;
1912e192b24SSimon Glass 
1922e192b24SSimon Glass 	printf("## Application terminated, rc = 0x%lx\n", rc);
1932e192b24SSimon Glass 
1942e192b24SSimon Glass 	return rcode;
1952e192b24SSimon Glass }
1962e192b24SSimon Glass 
1972e192b24SSimon Glass /*
1982e192b24SSimon Glass  * Interpreter command to boot VxWorks from a memory image.  The image can
1992e192b24SSimon Glass  * be either an ELF image or a raw binary.  Will attempt to setup the
2002e192b24SSimon Glass  * bootline and other parameters correctly.
2012e192b24SSimon Glass  */
2022e192b24SSimon Glass int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2032e192b24SSimon Glass {
2042e192b24SSimon Glass 	unsigned long addr; /* Address of image */
2052e192b24SSimon Glass 	unsigned long bootaddr; /* Address to put the bootline */
2062e192b24SSimon Glass 	char *bootline; /* Text of the bootline */
2072e192b24SSimon Glass 	char *tmp; /* Temporary char pointer */
2082e192b24SSimon Glass 	char build_buf[128]; /* Buffer for building the bootline */
2092e192b24SSimon Glass 	int ptr = 0;
2102e192b24SSimon Glass #ifdef CONFIG_X86
2112e192b24SSimon Glass 	struct e820info *info;
2122e192b24SSimon Glass 	struct e820entry *data;
2132e192b24SSimon Glass #endif
2142e192b24SSimon Glass 
2152e192b24SSimon Glass 	/*
2162e192b24SSimon Glass 	 * Check the loadaddr variable.
2172e192b24SSimon Glass 	 * If we don't know where the image is then we're done.
2182e192b24SSimon Glass 	 */
2192e192b24SSimon Glass 	if (argc < 2)
2202e192b24SSimon Glass 		addr = load_addr;
2212e192b24SSimon Glass 	else
2222e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
2232e192b24SSimon Glass 
2242e192b24SSimon Glass #if defined(CONFIG_CMD_NET)
2252e192b24SSimon Glass 	/*
2262e192b24SSimon Glass 	 * Check to see if we need to tftp the image ourselves
2272e192b24SSimon Glass 	 * before starting
2282e192b24SSimon Glass 	 */
2292e192b24SSimon Glass 	if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
2302e192b24SSimon Glass 		if (net_loop(TFTPGET) <= 0)
2312e192b24SSimon Glass 			return 1;
2322e192b24SSimon Glass 		printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
2332e192b24SSimon Glass 			addr);
2342e192b24SSimon Glass 	}
2352e192b24SSimon Glass #endif
2362e192b24SSimon Glass 
2372e192b24SSimon Glass 	/*
2382e192b24SSimon Glass 	 * This should equate to
2392e192b24SSimon Glass 	 * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
2402e192b24SSimon Glass 	 * from the VxWorks BSP header files.
2412e192b24SSimon Glass 	 * This will vary from board to board
2422e192b24SSimon Glass 	 */
243*8996975fSTuomas Tynkkynen #if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
2442e192b24SSimon Glass 	tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
24535affd7aSSimon Glass 	eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
2462e192b24SSimon Glass 	memcpy(tmp, build_buf, 6);
2472e192b24SSimon Glass #else
2482e192b24SSimon Glass 	puts("## Ethernet MAC address not copied to NV RAM\n");
2492e192b24SSimon Glass #endif
2502e192b24SSimon Glass 
2512e192b24SSimon Glass 	/*
2522e192b24SSimon Glass 	 * Use bootaddr to find the location in memory that VxWorks
2532e192b24SSimon Glass 	 * will look for the bootline string. The default value is
2542e192b24SSimon Glass 	 * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
2552e192b24SSimon Glass 	 * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
2562e192b24SSimon Glass 	 */
25700caae6dSSimon Glass 	tmp = env_get("bootaddr");
2582e192b24SSimon Glass 	if (!tmp) {
2592e192b24SSimon Glass 		printf("## VxWorks bootline address not specified\n");
2602e192b24SSimon Glass 	} else {
2612e192b24SSimon Glass 		bootaddr = simple_strtoul(tmp, NULL, 16);
2622e192b24SSimon Glass 
2632e192b24SSimon Glass 		/*
2642e192b24SSimon Glass 		 * Check to see if the bootline is defined in the 'bootargs'
2652e192b24SSimon Glass 		 * parameter. If it is not defined, we may be able to
2662e192b24SSimon Glass 		 * construct the info.
2672e192b24SSimon Glass 		 */
26800caae6dSSimon Glass 		bootline = env_get("bootargs");
2692e192b24SSimon Glass 		if (bootline) {
2702e192b24SSimon Glass 			memcpy((void *)bootaddr, bootline,
2712e192b24SSimon Glass 			       max(strlen(bootline), (size_t)255));
2722e192b24SSimon Glass 			flush_cache(bootaddr, max(strlen(bootline),
2732e192b24SSimon Glass 						  (size_t)255));
2742e192b24SSimon Glass 		} else {
27500caae6dSSimon Glass 			tmp = env_get("bootdev");
2762e192b24SSimon Glass 			if (tmp) {
2772e192b24SSimon Glass 				strcpy(build_buf, tmp);
2782e192b24SSimon Glass 				ptr = strlen(tmp);
2792e192b24SSimon Glass 			} else
2802e192b24SSimon Glass 				printf("## VxWorks boot device not specified\n");
2812e192b24SSimon Glass 
28200caae6dSSimon Glass 			tmp = env_get("bootfile");
2832e192b24SSimon Glass 			if (tmp)
2842e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr,
2852e192b24SSimon Glass 					       "host:%s ", tmp);
2862e192b24SSimon Glass 			else
2872e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr,
2882e192b24SSimon Glass 					       "host:vxWorks ");
2892e192b24SSimon Glass 
2902e192b24SSimon Glass 			/*
2912e192b24SSimon Glass 			 * The following parameters are only needed if 'bootdev'
2922e192b24SSimon Glass 			 * is an ethernet device, otherwise they are optional.
2932e192b24SSimon Glass 			 */
29400caae6dSSimon Glass 			tmp = env_get("ipaddr");
2952e192b24SSimon Glass 			if (tmp) {
2962e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr, "e=%s", tmp);
29700caae6dSSimon Glass 				tmp = env_get("netmask");
2982e192b24SSimon Glass 				if (tmp) {
299723806ccSSimon Glass 					u32 mask = env_get_ip("netmask").s_addr;
3002e192b24SSimon Glass 					ptr += sprintf(build_buf + ptr,
3012e192b24SSimon Glass 						       ":%08x ", ntohl(mask));
3022e192b24SSimon Glass 				} else {
3032e192b24SSimon Glass 					ptr += sprintf(build_buf + ptr, " ");
3042e192b24SSimon Glass 				}
3052e192b24SSimon Glass 			}
3062e192b24SSimon Glass 
30700caae6dSSimon Glass 			tmp = env_get("serverip");
3082e192b24SSimon Glass 			if (tmp)
3092e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
3102e192b24SSimon Glass 
31100caae6dSSimon Glass 			tmp = env_get("gatewayip");
3122e192b24SSimon Glass 			if (tmp)
3132e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
3142e192b24SSimon Glass 
31500caae6dSSimon Glass 			tmp = env_get("hostname");
3162e192b24SSimon Glass 			if (tmp)
3172e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
3182e192b24SSimon Glass 
31900caae6dSSimon Glass 			tmp = env_get("othbootargs");
3202e192b24SSimon Glass 			if (tmp) {
3212e192b24SSimon Glass 				strcpy(build_buf + ptr, tmp);
3222e192b24SSimon Glass 				ptr += strlen(tmp);
3232e192b24SSimon Glass 			}
3242e192b24SSimon Glass 
3252e192b24SSimon Glass 			memcpy((void *)bootaddr, build_buf,
3262e192b24SSimon Glass 			       max(strlen(build_buf), (size_t)255));
3272e192b24SSimon Glass 			flush_cache(bootaddr, max(strlen(build_buf),
3282e192b24SSimon Glass 						  (size_t)255));
3292e192b24SSimon Glass 		}
3302e192b24SSimon Glass 
3312e192b24SSimon Glass 		printf("## Using bootline (@ 0x%lx): %s\n", bootaddr,
3322e192b24SSimon Glass 		       (char *)bootaddr);
3332e192b24SSimon Glass 	}
3342e192b24SSimon Glass 
3352e192b24SSimon Glass #ifdef CONFIG_X86
3362e192b24SSimon Glass 	/*
3372e192b24SSimon Glass 	 * Since E820 information is critical to the kernel, if we don't
3382e192b24SSimon Glass 	 * specify these in the environments, use a default one.
3392e192b24SSimon Glass 	 */
34000caae6dSSimon Glass 	tmp = env_get("e820data");
3412e192b24SSimon Glass 	if (tmp)
3422e192b24SSimon Glass 		data = (struct e820entry *)simple_strtoul(tmp, NULL, 16);
3432e192b24SSimon Glass 	else
3442e192b24SSimon Glass 		data = (struct e820entry *)VXWORKS_E820_DATA_ADDR;
34500caae6dSSimon Glass 	tmp = env_get("e820info");
3462e192b24SSimon Glass 	if (tmp)
3472e192b24SSimon Glass 		info = (struct e820info *)simple_strtoul(tmp, NULL, 16);
3482e192b24SSimon Glass 	else
3492e192b24SSimon Glass 		info = (struct e820info *)VXWORKS_E820_INFO_ADDR;
3502e192b24SSimon Glass 
3512e192b24SSimon Glass 	memset(info, 0, sizeof(struct e820info));
3522e192b24SSimon Glass 	info->sign = E820_SIGNATURE;
3532e192b24SSimon Glass 	info->entries = install_e820_map(E820MAX, data);
3542e192b24SSimon Glass 	info->addr = (info->entries - 1) * sizeof(struct e820entry) +
3552e192b24SSimon Glass 		     VXWORKS_E820_DATA_ADDR;
3562e192b24SSimon Glass #endif
3572e192b24SSimon Glass 
3582e192b24SSimon Glass 	/*
3592e192b24SSimon Glass 	 * If the data at the load address is an elf image, then
3602e192b24SSimon Glass 	 * treat it like an elf image. Otherwise, assume that it is a
3612e192b24SSimon Glass 	 * binary image.
3622e192b24SSimon Glass 	 */
3632e192b24SSimon Glass 	if (valid_elf_image(addr))
3642e192b24SSimon Glass 		addr = load_elf_image_shdr(addr);
3652e192b24SSimon Glass 	else
3662e192b24SSimon Glass 		puts("## Not an ELF image, assuming binary\n");
3672e192b24SSimon Glass 
3682e192b24SSimon Glass 	printf("## Starting vxWorks at 0x%08lx ...\n", addr);
3692e192b24SSimon Glass 
3702e192b24SSimon Glass 	dcache_disable();
3712e192b24SSimon Glass #ifdef CONFIG_X86
3722e192b24SSimon Glass 	/* VxWorks on x86 uses stack to pass parameters */
3732e192b24SSimon Glass 	((asmlinkage void (*)(int))addr)(0);
3742e192b24SSimon Glass #else
3752e192b24SSimon Glass 	((void (*)(int))addr)(0);
3762e192b24SSimon Glass #endif
3772e192b24SSimon Glass 
3782e192b24SSimon Glass 	puts("## vxWorks terminated\n");
3792e192b24SSimon Glass 
3802e192b24SSimon Glass 	return 1;
3812e192b24SSimon Glass }
3822e192b24SSimon Glass 
3832e192b24SSimon Glass U_BOOT_CMD(
384be1b8679STom Rini 	bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
3852e192b24SSimon Glass 	"Boot from an ELF image in memory",
3862e192b24SSimon Glass 	"[-p|-s] [address]\n"
3872e192b24SSimon Glass 	"\t- load ELF image at [address] via program headers (-p)\n"
3882e192b24SSimon Glass 	"\t  or via section headers (-s)"
3892e192b24SSimon Glass );
3902e192b24SSimon Glass 
3912e192b24SSimon Glass U_BOOT_CMD(
3922e192b24SSimon Glass 	bootvx, 2, 0, do_bootvx,
3932e192b24SSimon Glass 	"Boot vxWorks from an ELF image",
3942e192b24SSimon Glass 	" [address] - load address of vxWorks ELF image."
3952e192b24SSimon Glass );
396