xref: /openbmc/u-boot/cmd/elf.c (revision 2846ea81a0295b47dda75111cfef099d5eed85e2)
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>
199925f1dbSAlex Kiernan #include <environment.h>
202e192b24SSimon Glass #include <net.h>
212e192b24SSimon Glass #include <vxworks.h>
222e192b24SSimon Glass #ifdef CONFIG_X86
23447ae4f7SBin Meng #include <vbe.h>
242e192b24SSimon Glass #include <asm/e820.h>
252e192b24SSimon Glass #include <linux/linkage.h>
262e192b24SSimon Glass #endif
272e192b24SSimon Glass 
282e192b24SSimon Glass /*
29839c4e9cSBin Meng  * A very simple ELF64 loader, assumes the image is valid, returns the
302e192b24SSimon Glass  * entry point address.
31839c4e9cSBin Meng  *
32839c4e9cSBin Meng  * Note if U-Boot is 32-bit, the loader assumes the to segment's
33839c4e9cSBin Meng  * physical address and size is within the lower 32-bit address space.
34839c4e9cSBin Meng  */
35839c4e9cSBin Meng static unsigned long load_elf64_image_phdr(unsigned long addr)
36839c4e9cSBin Meng {
37839c4e9cSBin Meng 	Elf64_Ehdr *ehdr; /* Elf header structure pointer */
38839c4e9cSBin Meng 	Elf64_Phdr *phdr; /* Program header structure pointer */
39839c4e9cSBin Meng 	int i;
40839c4e9cSBin Meng 
41839c4e9cSBin Meng 	ehdr = (Elf64_Ehdr *)addr;
42839c4e9cSBin Meng 	phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
43839c4e9cSBin Meng 
44839c4e9cSBin Meng 	/* Load each program header */
45839c4e9cSBin Meng 	for (i = 0; i < ehdr->e_phnum; ++i) {
46839c4e9cSBin Meng 		void *dst = (void *)(ulong)phdr->p_paddr;
47839c4e9cSBin Meng 		void *src = (void *)addr + phdr->p_offset;
48839c4e9cSBin Meng 
49839c4e9cSBin Meng 		debug("Loading phdr %i to 0x%p (%lu bytes)\n",
50839c4e9cSBin Meng 		      i, dst, (ulong)phdr->p_filesz);
51839c4e9cSBin Meng 		if (phdr->p_filesz)
52839c4e9cSBin Meng 			memcpy(dst, src, phdr->p_filesz);
53839c4e9cSBin Meng 		if (phdr->p_filesz != phdr->p_memsz)
54839c4e9cSBin Meng 			memset(dst + phdr->p_filesz, 0x00,
55839c4e9cSBin Meng 			       phdr->p_memsz - phdr->p_filesz);
56839c4e9cSBin Meng 		flush_cache((unsigned long)dst, phdr->p_filesz);
57839c4e9cSBin Meng 		++phdr;
58839c4e9cSBin Meng 	}
59839c4e9cSBin Meng 
60*2846ea81SRob Bracero 	if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
61*2846ea81SRob Bracero 					    EF_PPC64_ELFV1_ABI)) {
62*2846ea81SRob Bracero 		/*
63*2846ea81SRob Bracero 		 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
64*2846ea81SRob Bracero 		 * descriptor pointer with the first double word being the
65*2846ea81SRob Bracero 		 * address of the entry point of the function.
66*2846ea81SRob Bracero 		 */
67*2846ea81SRob Bracero 		uintptr_t addr = ehdr->e_entry;
68*2846ea81SRob Bracero 
69*2846ea81SRob Bracero 		return *(Elf64_Addr *)addr;
70*2846ea81SRob Bracero 	}
71*2846ea81SRob Bracero 
72*2846ea81SRob Bracero 	return ehdr->e_entry;
73*2846ea81SRob Bracero }
74*2846ea81SRob Bracero 
75*2846ea81SRob Bracero static unsigned long load_elf64_image_shdr(unsigned long addr)
76*2846ea81SRob Bracero {
77*2846ea81SRob Bracero 	Elf64_Ehdr *ehdr; /* Elf header structure pointer */
78*2846ea81SRob Bracero 	Elf64_Shdr *shdr; /* Section header structure pointer */
79*2846ea81SRob Bracero 	unsigned char *strtab = 0; /* String table pointer */
80*2846ea81SRob Bracero 	unsigned char *image; /* Binary image pointer */
81*2846ea81SRob Bracero 	int i; /* Loop counter */
82*2846ea81SRob Bracero 
83*2846ea81SRob Bracero 	ehdr = (Elf64_Ehdr *)addr;
84*2846ea81SRob Bracero 
85*2846ea81SRob Bracero 	/* Find the section header string table for output info */
86*2846ea81SRob Bracero 	shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
87*2846ea81SRob Bracero 			     (ehdr->e_shstrndx * sizeof(Elf64_Shdr)));
88*2846ea81SRob Bracero 
89*2846ea81SRob Bracero 	if (shdr->sh_type == SHT_STRTAB)
90*2846ea81SRob Bracero 		strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset);
91*2846ea81SRob Bracero 
92*2846ea81SRob Bracero 	/* Load each appropriate section */
93*2846ea81SRob Bracero 	for (i = 0; i < ehdr->e_shnum; ++i) {
94*2846ea81SRob Bracero 		shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff +
95*2846ea81SRob Bracero 				     (i * sizeof(Elf64_Shdr)));
96*2846ea81SRob Bracero 
97*2846ea81SRob Bracero 		if (!(shdr->sh_flags & SHF_ALLOC) ||
98*2846ea81SRob Bracero 		    shdr->sh_addr == 0 || shdr->sh_size == 0) {
99*2846ea81SRob Bracero 			continue;
100*2846ea81SRob Bracero 		}
101*2846ea81SRob Bracero 
102*2846ea81SRob Bracero 		if (strtab) {
103*2846ea81SRob Bracero 			debug("%sing %s @ 0x%08lx (%ld bytes)\n",
104*2846ea81SRob Bracero 			      (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
105*2846ea81SRob Bracero 			       &strtab[shdr->sh_name],
106*2846ea81SRob Bracero 			       (unsigned long)shdr->sh_addr,
107*2846ea81SRob Bracero 			       (long)shdr->sh_size);
108*2846ea81SRob Bracero 		}
109*2846ea81SRob Bracero 
110*2846ea81SRob Bracero 		if (shdr->sh_type == SHT_NOBITS) {
111*2846ea81SRob Bracero 			memset((void *)(uintptr_t)shdr->sh_addr, 0,
112*2846ea81SRob Bracero 			       shdr->sh_size);
113*2846ea81SRob Bracero 		} else {
114*2846ea81SRob Bracero 			image = (unsigned char *)addr + (ulong)shdr->sh_offset;
115*2846ea81SRob Bracero 			memcpy((void *)(uintptr_t)shdr->sh_addr,
116*2846ea81SRob Bracero 			       (const void *)image, shdr->sh_size);
117*2846ea81SRob Bracero 		}
118*2846ea81SRob Bracero 		flush_cache((ulong)shdr->sh_addr, shdr->sh_size);
119*2846ea81SRob Bracero 	}
120*2846ea81SRob Bracero 
121*2846ea81SRob Bracero 	if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
122*2846ea81SRob Bracero 					    EF_PPC64_ELFV1_ABI)) {
123*2846ea81SRob Bracero 		/*
124*2846ea81SRob Bracero 		 * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function
125*2846ea81SRob Bracero 		 * descriptor pointer with the first double word being the
126*2846ea81SRob Bracero 		 * address of the entry point of the function.
127*2846ea81SRob Bracero 		 */
128*2846ea81SRob Bracero 		uintptr_t addr = ehdr->e_entry;
129*2846ea81SRob Bracero 
130*2846ea81SRob Bracero 		return *(Elf64_Addr *)addr;
131*2846ea81SRob Bracero 	}
132*2846ea81SRob Bracero 
133839c4e9cSBin Meng 	return ehdr->e_entry;
134839c4e9cSBin Meng }
135839c4e9cSBin Meng 
136839c4e9cSBin Meng /*
137839c4e9cSBin Meng  * A very simple ELF loader, assumes the image is valid, returns the
138839c4e9cSBin Meng  * entry point address.
139839c4e9cSBin Meng  *
140839c4e9cSBin Meng  * The loader firstly reads the EFI class to see if it's a 64-bit image.
141839c4e9cSBin Meng  * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
1422e192b24SSimon Glass  */
1432e192b24SSimon Glass static unsigned long load_elf_image_phdr(unsigned long addr)
1442e192b24SSimon Glass {
1452e192b24SSimon Glass 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
1462e192b24SSimon Glass 	Elf32_Phdr *phdr; /* Program header structure pointer */
1472e192b24SSimon Glass 	int i;
1482e192b24SSimon Glass 
1492e192b24SSimon Glass 	ehdr = (Elf32_Ehdr *)addr;
150839c4e9cSBin Meng 	if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
151839c4e9cSBin Meng 		return load_elf64_image_phdr(addr);
152839c4e9cSBin Meng 
1532e192b24SSimon Glass 	phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
1542e192b24SSimon Glass 
1552e192b24SSimon Glass 	/* Load each program header */
1562e192b24SSimon Glass 	for (i = 0; i < ehdr->e_phnum; ++i) {
1572e192b24SSimon Glass 		void *dst = (void *)(uintptr_t)phdr->p_paddr;
1582e192b24SSimon Glass 		void *src = (void *)addr + phdr->p_offset;
159839c4e9cSBin Meng 
1602e192b24SSimon Glass 		debug("Loading phdr %i to 0x%p (%i bytes)\n",
1612e192b24SSimon Glass 		      i, dst, phdr->p_filesz);
1622e192b24SSimon Glass 		if (phdr->p_filesz)
1632e192b24SSimon Glass 			memcpy(dst, src, phdr->p_filesz);
1642e192b24SSimon Glass 		if (phdr->p_filesz != phdr->p_memsz)
1652e192b24SSimon Glass 			memset(dst + phdr->p_filesz, 0x00,
1662e192b24SSimon Glass 			       phdr->p_memsz - phdr->p_filesz);
1672e192b24SSimon Glass 		flush_cache((unsigned long)dst, phdr->p_filesz);
1682e192b24SSimon Glass 		++phdr;
1692e192b24SSimon Glass 	}
1702e192b24SSimon Glass 
1712e192b24SSimon Glass 	return ehdr->e_entry;
1722e192b24SSimon Glass }
1732e192b24SSimon Glass 
1742e192b24SSimon Glass static unsigned long load_elf_image_shdr(unsigned long addr)
1752e192b24SSimon Glass {
1762e192b24SSimon Glass 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
1772e192b24SSimon Glass 	Elf32_Shdr *shdr; /* Section header structure pointer */
1782e192b24SSimon Glass 	unsigned char *strtab = 0; /* String table pointer */
1792e192b24SSimon Glass 	unsigned char *image; /* Binary image pointer */
1802e192b24SSimon Glass 	int i; /* Loop counter */
1812e192b24SSimon Glass 
1822e192b24SSimon Glass 	ehdr = (Elf32_Ehdr *)addr;
183*2846ea81SRob Bracero 	if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
184*2846ea81SRob Bracero 		return load_elf64_image_shdr(addr);
1852e192b24SSimon Glass 
1862e192b24SSimon Glass 	/* Find the section header string table for output info */
1872e192b24SSimon Glass 	shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
1882e192b24SSimon Glass 			     (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
1892e192b24SSimon Glass 
1902e192b24SSimon Glass 	if (shdr->sh_type == SHT_STRTAB)
1912e192b24SSimon Glass 		strtab = (unsigned char *)(addr + shdr->sh_offset);
1922e192b24SSimon Glass 
1932e192b24SSimon Glass 	/* Load each appropriate section */
1942e192b24SSimon Glass 	for (i = 0; i < ehdr->e_shnum; ++i) {
1952e192b24SSimon Glass 		shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
1962e192b24SSimon Glass 				     (i * sizeof(Elf32_Shdr)));
1972e192b24SSimon Glass 
1982e192b24SSimon Glass 		if (!(shdr->sh_flags & SHF_ALLOC) ||
1992e192b24SSimon Glass 		    shdr->sh_addr == 0 || shdr->sh_size == 0) {
2002e192b24SSimon Glass 			continue;
2012e192b24SSimon Glass 		}
2022e192b24SSimon Glass 
2032e192b24SSimon Glass 		if (strtab) {
2042e192b24SSimon Glass 			debug("%sing %s @ 0x%08lx (%ld bytes)\n",
2052e192b24SSimon Glass 			      (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
2062e192b24SSimon Glass 			       &strtab[shdr->sh_name],
2072e192b24SSimon Glass 			       (unsigned long)shdr->sh_addr,
2082e192b24SSimon Glass 			       (long)shdr->sh_size);
2092e192b24SSimon Glass 		}
2102e192b24SSimon Glass 
2112e192b24SSimon Glass 		if (shdr->sh_type == SHT_NOBITS) {
2122e192b24SSimon Glass 			memset((void *)(uintptr_t)shdr->sh_addr, 0,
2132e192b24SSimon Glass 			       shdr->sh_size);
2142e192b24SSimon Glass 		} else {
2152e192b24SSimon Glass 			image = (unsigned char *)addr + shdr->sh_offset;
2162e192b24SSimon Glass 			memcpy((void *)(uintptr_t)shdr->sh_addr,
2172e192b24SSimon Glass 			       (const void *)image, shdr->sh_size);
2182e192b24SSimon Glass 		}
2192e192b24SSimon Glass 		flush_cache(shdr->sh_addr, shdr->sh_size);
2202e192b24SSimon Glass 	}
2212e192b24SSimon Glass 
2222e192b24SSimon Glass 	return ehdr->e_entry;
2232e192b24SSimon Glass }
2242e192b24SSimon Glass 
2252e192b24SSimon Glass /* Allow ports to override the default behavior */
2262e192b24SSimon Glass static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
2272e192b24SSimon Glass 				     int argc, char * const argv[])
2282e192b24SSimon Glass {
2292e192b24SSimon Glass 	unsigned long ret;
2302e192b24SSimon Glass 
2312e192b24SSimon Glass 	/*
2322e192b24SSimon Glass 	 * pass address parameter as argv[0] (aka command name),
2332e192b24SSimon Glass 	 * and all remaining args
2342e192b24SSimon Glass 	 */
2352e192b24SSimon Glass 	ret = entry(argc, argv);
2362e192b24SSimon Glass 
2372e192b24SSimon Glass 	return ret;
2382e192b24SSimon Glass }
2392e192b24SSimon Glass 
2402e192b24SSimon Glass /*
2412e192b24SSimon Glass  * Determine if a valid ELF image exists at the given memory location.
2422e192b24SSimon Glass  * First look at the ELF header magic field, then make sure that it is
2432e192b24SSimon Glass  * executable.
2442e192b24SSimon Glass  */
2452e192b24SSimon Glass int valid_elf_image(unsigned long addr)
2462e192b24SSimon Glass {
2472e192b24SSimon Glass 	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
2482e192b24SSimon Glass 
2492e192b24SSimon Glass 	ehdr = (Elf32_Ehdr *)addr;
2502e192b24SSimon Glass 
2512e192b24SSimon Glass 	if (!IS_ELF(*ehdr)) {
2522e192b24SSimon Glass 		printf("## No elf image at address 0x%08lx\n", addr);
2532e192b24SSimon Glass 		return 0;
2542e192b24SSimon Glass 	}
2552e192b24SSimon Glass 
2562e192b24SSimon Glass 	if (ehdr->e_type != ET_EXEC) {
2572e192b24SSimon Glass 		printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
2582e192b24SSimon Glass 		return 0;
2592e192b24SSimon Glass 	}
2602e192b24SSimon Glass 
2612e192b24SSimon Glass 	return 1;
2622e192b24SSimon Glass }
2632e192b24SSimon Glass 
2642e192b24SSimon Glass /* Interpreter command to boot an arbitrary ELF image from memory */
2652e192b24SSimon Glass int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2662e192b24SSimon Glass {
2672e192b24SSimon Glass 	unsigned long addr; /* Address of the ELF image */
2682e192b24SSimon Glass 	unsigned long rc; /* Return value from user code */
269be1b8679STom Rini 	char *sload = NULL;
27000caae6dSSimon Glass 	const char *ep = env_get("autostart");
2712e192b24SSimon Glass 	int rcode = 0;
2722e192b24SSimon Glass 
273be1b8679STom Rini 	/* Consume 'bootelf' */
274be1b8679STom Rini 	argc--; argv++;
2752e192b24SSimon Glass 
276be1b8679STom Rini 	/* Check for flag. */
277be1b8679STom Rini 	if (argc >= 1 && (argv[0][0] == '-' && \
278be1b8679STom Rini 				(argv[0][1] == 'p' || argv[0][1] == 's'))) {
279be1b8679STom Rini 		sload = argv[0];
280be1b8679STom Rini 		/* Consume flag. */
281be1b8679STom Rini 		argc--; argv++;
282be1b8679STom Rini 	}
283be1b8679STom Rini 	/* Check for address. */
284be1b8679STom Rini 	if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
285be1b8679STom Rini 		/* Consume address */
286be1b8679STom Rini 		argc--; argv++;
287be1b8679STom Rini 	} else
2882e192b24SSimon Glass 		addr = load_addr;
2892e192b24SSimon Glass 
2902e192b24SSimon Glass 	if (!valid_elf_image(addr))
2912e192b24SSimon Glass 		return 1;
2922e192b24SSimon Glass 
2932e192b24SSimon Glass 	if (sload && sload[1] == 'p')
2942e192b24SSimon Glass 		addr = load_elf_image_phdr(addr);
2952e192b24SSimon Glass 	else
2962e192b24SSimon Glass 		addr = load_elf_image_shdr(addr);
2972e192b24SSimon Glass 
2982e192b24SSimon Glass 	if (ep && !strcmp(ep, "no"))
2992e192b24SSimon Glass 		return rcode;
3002e192b24SSimon Glass 
3012e192b24SSimon Glass 	printf("## Starting application at 0x%08lx ...\n", addr);
3022e192b24SSimon Glass 
3032e192b24SSimon Glass 	/*
3042e192b24SSimon Glass 	 * pass address parameter as argv[0] (aka command name),
3052e192b24SSimon Glass 	 * and all remaining args
3062e192b24SSimon Glass 	 */
307be1b8679STom Rini 	rc = do_bootelf_exec((void *)addr, argc, argv);
3082e192b24SSimon Glass 	if (rc != 0)
3092e192b24SSimon Glass 		rcode = 1;
3102e192b24SSimon Glass 
3112e192b24SSimon Glass 	printf("## Application terminated, rc = 0x%lx\n", rc);
3122e192b24SSimon Glass 
3132e192b24SSimon Glass 	return rcode;
3142e192b24SSimon Glass }
3152e192b24SSimon Glass 
3162e192b24SSimon Glass /*
3172e192b24SSimon Glass  * Interpreter command to boot VxWorks from a memory image.  The image can
3182e192b24SSimon Glass  * be either an ELF image or a raw binary.  Will attempt to setup the
3192e192b24SSimon Glass  * bootline and other parameters correctly.
3202e192b24SSimon Glass  */
3212e192b24SSimon Glass int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
3222e192b24SSimon Glass {
3232e192b24SSimon Glass 	unsigned long addr; /* Address of image */
32479c584e5SBin Meng 	unsigned long bootaddr = 0; /* Address to put the bootline */
3252e192b24SSimon Glass 	char *bootline; /* Text of the bootline */
3262e192b24SSimon Glass 	char *tmp; /* Temporary char pointer */
3272e192b24SSimon Glass 	char build_buf[128]; /* Buffer for building the bootline */
3282e192b24SSimon Glass 	int ptr = 0;
3292e192b24SSimon Glass #ifdef CONFIG_X86
3302902be86SBin Meng 	ulong base;
331fa5e91f7SBin Meng 	struct e820_info *info;
33245519924SBin Meng 	struct e820_entry *data;
333447ae4f7SBin Meng 	struct efi_gop_info *gop;
334447ae4f7SBin Meng 	struct vesa_mode_info *vesa = &mode_info.vesa;
3352e192b24SSimon Glass #endif
3362e192b24SSimon Glass 
3372e192b24SSimon Glass 	/*
3382e192b24SSimon Glass 	 * Check the loadaddr variable.
3392e192b24SSimon Glass 	 * If we don't know where the image is then we're done.
3402e192b24SSimon Glass 	 */
3412e192b24SSimon Glass 	if (argc < 2)
3422e192b24SSimon Glass 		addr = load_addr;
3432e192b24SSimon Glass 	else
3442e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
3452e192b24SSimon Glass 
3462e192b24SSimon Glass #if defined(CONFIG_CMD_NET)
3472e192b24SSimon Glass 	/*
3482e192b24SSimon Glass 	 * Check to see if we need to tftp the image ourselves
3492e192b24SSimon Glass 	 * before starting
3502e192b24SSimon Glass 	 */
3512e192b24SSimon Glass 	if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
3522e192b24SSimon Glass 		if (net_loop(TFTPGET) <= 0)
3532e192b24SSimon Glass 			return 1;
3542e192b24SSimon Glass 		printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
3552e192b24SSimon Glass 			addr);
3562e192b24SSimon Glass 	}
3572e192b24SSimon Glass #endif
3582e192b24SSimon Glass 
3592e192b24SSimon Glass 	/*
3602e192b24SSimon Glass 	 * This should equate to
3612e192b24SSimon Glass 	 * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
3622e192b24SSimon Glass 	 * from the VxWorks BSP header files.
3632e192b24SSimon Glass 	 * This will vary from board to board
3642e192b24SSimon Glass 	 */
3658996975fSTuomas Tynkkynen #if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
3662e192b24SSimon Glass 	tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
36735affd7aSSimon Glass 	eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
3682e192b24SSimon Glass 	memcpy(tmp, build_buf, 6);
3692e192b24SSimon Glass #else
3702e192b24SSimon Glass 	puts("## Ethernet MAC address not copied to NV RAM\n");
3712e192b24SSimon Glass #endif
3722e192b24SSimon Glass 
37379c584e5SBin Meng #ifdef CONFIG_X86
37479c584e5SBin Meng 	/*
37579c584e5SBin Meng 	 * Get VxWorks's physical memory base address from environment,
37679c584e5SBin Meng 	 * if we don't specify it in the environment, use a default one.
37779c584e5SBin Meng 	 */
37879c584e5SBin Meng 	base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
37979c584e5SBin Meng 	data = (struct e820_entry *)(base + E820_DATA_OFFSET);
38079c584e5SBin Meng 	info = (struct e820_info *)(base + E820_INFO_OFFSET);
38179c584e5SBin Meng 
38279c584e5SBin Meng 	memset(info, 0, sizeof(struct e820_info));
38379c584e5SBin Meng 	info->sign = E820_SIGNATURE;
38479c584e5SBin Meng 	info->entries = install_e820_map(E820MAX, data);
38579c584e5SBin Meng 	info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
38679c584e5SBin Meng 		     E820_DATA_OFFSET;
38779c584e5SBin Meng 
38879c584e5SBin Meng 	/*
38979c584e5SBin Meng 	 * Explicitly clear the bootloader image size otherwise if memory
39079c584e5SBin Meng 	 * at this offset happens to contain some garbage data, the final
39179c584e5SBin Meng 	 * available memory size for the kernel is insane.
39279c584e5SBin Meng 	 */
39379c584e5SBin Meng 	*(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
39479c584e5SBin Meng 
39579c584e5SBin Meng 	/*
39679c584e5SBin Meng 	 * Prepare compatible framebuffer information block.
39779c584e5SBin Meng 	 * The VESA mode has to be 32-bit RGBA.
39879c584e5SBin Meng 	 */
39979c584e5SBin Meng 	if (vesa->x_resolution && vesa->y_resolution) {
40079c584e5SBin Meng 		gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
40179c584e5SBin Meng 		gop->magic = EFI_GOP_INFO_MAGIC;
40279c584e5SBin Meng 		gop->info.version = 0;
40379c584e5SBin Meng 		gop->info.width = vesa->x_resolution;
40479c584e5SBin Meng 		gop->info.height = vesa->y_resolution;
40579c584e5SBin Meng 		gop->info.pixel_format = EFI_GOT_RGBA8;
40679c584e5SBin Meng 		gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
40779c584e5SBin Meng 		gop->fb_base = vesa->phys_base_ptr;
40879c584e5SBin Meng 		gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
40979c584e5SBin Meng 	}
41079c584e5SBin Meng #endif
41179c584e5SBin Meng 
4122e192b24SSimon Glass 	/*
4132e192b24SSimon Glass 	 * Use bootaddr to find the location in memory that VxWorks
4142e192b24SSimon Glass 	 * will look for the bootline string. The default value is
4152e192b24SSimon Glass 	 * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
4162e192b24SSimon Glass 	 * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
4172e192b24SSimon Glass 	 */
41800caae6dSSimon Glass 	tmp = env_get("bootaddr");
4192e192b24SSimon Glass 	if (!tmp) {
42079c584e5SBin Meng #ifdef CONFIG_X86
42179c584e5SBin Meng 		bootaddr = base + X86_BOOT_LINE_OFFSET;
42279c584e5SBin Meng #else
4232e192b24SSimon Glass 		printf("## VxWorks bootline address not specified\n");
424ced71a2fSBin Meng 		return 1;
42579c584e5SBin Meng #endif
426ced71a2fSBin Meng 	}
427ced71a2fSBin Meng 
42879c584e5SBin Meng 	if (!bootaddr)
4292e192b24SSimon Glass 		bootaddr = simple_strtoul(tmp, NULL, 16);
4302e192b24SSimon Glass 
4312e192b24SSimon Glass 	/*
432ced71a2fSBin Meng 	 * Check to see if the bootline is defined in the 'bootargs' parameter.
433ced71a2fSBin Meng 	 * If it is not defined, we may be able to construct the info.
4342e192b24SSimon Glass 	 */
43500caae6dSSimon Glass 	bootline = env_get("bootargs");
4367824ad6aSBin Meng 	if (!bootline) {
43700caae6dSSimon Glass 		tmp = env_get("bootdev");
4382e192b24SSimon Glass 		if (tmp) {
4392e192b24SSimon Glass 			strcpy(build_buf, tmp);
4402e192b24SSimon Glass 			ptr = strlen(tmp);
441ced71a2fSBin Meng 		} else {
4422e192b24SSimon Glass 			printf("## VxWorks boot device not specified\n");
443ced71a2fSBin Meng 		}
4442e192b24SSimon Glass 
44500caae6dSSimon Glass 		tmp = env_get("bootfile");
4462e192b24SSimon Glass 		if (tmp)
447ced71a2fSBin Meng 			ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
4482e192b24SSimon Glass 		else
449ced71a2fSBin Meng 			ptr += sprintf(build_buf + ptr, "host:vxWorks ");
4502e192b24SSimon Glass 
4512e192b24SSimon Glass 		/*
4522e192b24SSimon Glass 		 * The following parameters are only needed if 'bootdev'
4532e192b24SSimon Glass 		 * is an ethernet device, otherwise they are optional.
4542e192b24SSimon Glass 		 */
45500caae6dSSimon Glass 		tmp = env_get("ipaddr");
4562e192b24SSimon Glass 		if (tmp) {
4572e192b24SSimon Glass 			ptr += sprintf(build_buf + ptr, "e=%s", tmp);
45800caae6dSSimon Glass 			tmp = env_get("netmask");
4592e192b24SSimon Glass 			if (tmp) {
460723806ccSSimon Glass 				u32 mask = env_get_ip("netmask").s_addr;
4612e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr,
4622e192b24SSimon Glass 					       ":%08x ", ntohl(mask));
4632e192b24SSimon Glass 			} else {
4642e192b24SSimon Glass 				ptr += sprintf(build_buf + ptr, " ");
4652e192b24SSimon Glass 			}
4662e192b24SSimon Glass 		}
4672e192b24SSimon Glass 
46800caae6dSSimon Glass 		tmp = env_get("serverip");
4692e192b24SSimon Glass 		if (tmp)
4702e192b24SSimon Glass 			ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
4712e192b24SSimon Glass 
47200caae6dSSimon Glass 		tmp = env_get("gatewayip");
4732e192b24SSimon Glass 		if (tmp)
4742e192b24SSimon Glass 			ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
4752e192b24SSimon Glass 
47600caae6dSSimon Glass 		tmp = env_get("hostname");
4772e192b24SSimon Glass 		if (tmp)
4782e192b24SSimon Glass 			ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
4792e192b24SSimon Glass 
48000caae6dSSimon Glass 		tmp = env_get("othbootargs");
4812e192b24SSimon Glass 		if (tmp) {
4822e192b24SSimon Glass 			strcpy(build_buf + ptr, tmp);
4832e192b24SSimon Glass 			ptr += strlen(tmp);
4842e192b24SSimon Glass 		}
4852e192b24SSimon Glass 
4867824ad6aSBin Meng 		bootline = build_buf;
4872e192b24SSimon Glass 	}
4882e192b24SSimon Glass 
489ced71a2fSBin Meng 	memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
4907824ad6aSBin Meng 	flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
491ced71a2fSBin Meng 	printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
4922e192b24SSimon Glass 
4932e192b24SSimon Glass 	/*
4942e192b24SSimon Glass 	 * If the data at the load address is an elf image, then
4952e192b24SSimon Glass 	 * treat it like an elf image. Otherwise, assume that it is a
4962e192b24SSimon Glass 	 * binary image.
4972e192b24SSimon Glass 	 */
4982e192b24SSimon Glass 	if (valid_elf_image(addr))
499476c2fcdSChristian Gmeiner 		addr = load_elf_image_phdr(addr);
5002e192b24SSimon Glass 	else
5012e192b24SSimon Glass 		puts("## Not an ELF image, assuming binary\n");
5022e192b24SSimon Glass 
5032e192b24SSimon Glass 	printf("## Starting vxWorks at 0x%08lx ...\n", addr);
5042e192b24SSimon Glass 
5052e192b24SSimon Glass 	dcache_disable();
5063194daa1SVasyl Vavrychuk #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
5073194daa1SVasyl Vavrychuk 	armv8_setup_psci();
5083194daa1SVasyl Vavrychuk 	smp_kick_all_cpus();
5093194daa1SVasyl Vavrychuk #endif
5103194daa1SVasyl Vavrychuk 
5112e192b24SSimon Glass #ifdef CONFIG_X86
5122e192b24SSimon Glass 	/* VxWorks on x86 uses stack to pass parameters */
5132e192b24SSimon Glass 	((asmlinkage void (*)(int))addr)(0);
5142e192b24SSimon Glass #else
5152e192b24SSimon Glass 	((void (*)(int))addr)(0);
5162e192b24SSimon Glass #endif
5172e192b24SSimon Glass 
5182e192b24SSimon Glass 	puts("## vxWorks terminated\n");
5192e192b24SSimon Glass 
5202e192b24SSimon Glass 	return 1;
5212e192b24SSimon Glass }
5222e192b24SSimon Glass 
5232e192b24SSimon Glass U_BOOT_CMD(
524be1b8679STom Rini 	bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
5252e192b24SSimon Glass 	"Boot from an ELF image in memory",
5262e192b24SSimon Glass 	"[-p|-s] [address]\n"
5272e192b24SSimon Glass 	"\t- load ELF image at [address] via program headers (-p)\n"
5282e192b24SSimon Glass 	"\t  or via section headers (-s)"
5292e192b24SSimon Glass );
5302e192b24SSimon Glass 
5312e192b24SSimon Glass U_BOOT_CMD(
5322e192b24SSimon Glass 	bootvx, 2, 0, do_bootvx,
5332e192b24SSimon Glass 	"Boot vxWorks from an ELF image",
5342e192b24SSimon Glass 	" [address] - load address of vxWorks ELF image."
5352e192b24SSimon Glass );
536