1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2001 William L. Pitts
4  * All rights reserved.
5  */
6 
7 #include <common.h>
8 #include <command.h>
9 #include <cpu_func.h>
10 #include <elf.h>
11 #include <env.h>
12 #include <image.h>
13 #include <log.h>
14 #include <net.h>
15 #include <vxworks.h>
16 #ifdef CONFIG_X86
17 #include <vbe.h>
18 #include <asm/cache.h>
19 #include <asm/e820.h>
20 #include <linux/linkage.h>
21 #endif
22 
23 /* Allow ports to override the default behavior */
do_bootelf_exec(ulong (* entry)(int,char * const[]),int argc,char * const argv[])24 static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
25 				     int argc, char *const argv[])
26 {
27 	unsigned long ret;
28 
29 	/*
30 	 * pass address parameter as argv[0] (aka command name),
31 	 * and all remaining args
32 	 */
33 	ret = entry(argc, argv);
34 
35 	return ret;
36 }
37 
38 /* Interpreter command to boot an arbitrary ELF image from memory */
do_bootelf(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])39 int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
40 {
41 	unsigned long addr; /* Address of the ELF image */
42 	unsigned long rc; /* Return value from user code */
43 	char *sload = NULL;
44 	const char *ep = env_get("autostart");
45 	int rcode = 0;
46 
47 	/* Consume 'bootelf' */
48 	argc--; argv++;
49 
50 	/* Check for flag. */
51 	if (argc >= 1 && (argv[0][0] == '-' && \
52 				(argv[0][1] == 'p' || argv[0][1] == 's'))) {
53 		sload = argv[0];
54 		/* Consume flag. */
55 		argc--; argv++;
56 	}
57 	/* Check for address. */
58 	if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
59 		/* Consume address */
60 		argc--; argv++;
61 	} else
62 		addr = image_load_addr;
63 
64 	if (!valid_elf_image(addr))
65 		return 1;
66 
67 	if (sload && sload[1] == 'p')
68 		addr = load_elf_image_phdr(addr);
69 	else
70 		addr = load_elf_image_shdr(addr);
71 
72 	if (ep && !strcmp(ep, "no"))
73 		return rcode;
74 
75 	printf("## Starting application at 0x%08lx ...\n", addr);
76 
77 	/*
78 	 * pass address parameter as argv[0] (aka command name),
79 	 * and all remaining args
80 	 */
81 	rc = do_bootelf_exec((void *)addr, argc, argv);
82 	if (rc != 0)
83 		rcode = 1;
84 
85 	printf("## Application terminated, rc = 0x%lx\n", rc);
86 
87 	return rcode;
88 }
89 
90 /*
91  * Interpreter command to boot VxWorks from a memory image.  The image can
92  * be either an ELF image or a raw binary.  Will attempt to setup the
93  * bootline and other parameters correctly.
94  */
do_bootvx(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])95 int do_bootvx(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
96 {
97 	unsigned long addr; /* Address of image */
98 	unsigned long bootaddr = 0; /* Address to put the bootline */
99 	char *bootline; /* Text of the bootline */
100 	char *tmp; /* Temporary char pointer */
101 	char build_buf[128]; /* Buffer for building the bootline */
102 	int ptr = 0;
103 #ifdef CONFIG_X86
104 	ulong base;
105 	struct e820_info *info;
106 	struct e820_entry *data;
107 	struct efi_gop_info *gop;
108 	struct vesa_mode_info *vesa = &mode_info.vesa;
109 #endif
110 
111 	/*
112 	 * Check the loadaddr variable.
113 	 * If we don't know where the image is then we're done.
114 	 */
115 	if (argc < 2)
116 		addr = image_load_addr;
117 	else
118 		addr = simple_strtoul(argv[1], NULL, 16);
119 
120 #if defined(CONFIG_CMD_NET)
121 	/*
122 	 * Check to see if we need to tftp the image ourselves
123 	 * before starting
124 	 */
125 	if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
126 		if (net_loop(TFTPGET) <= 0)
127 			return 1;
128 		printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
129 			addr);
130 	}
131 #endif
132 
133 	/*
134 	 * This should equate to
135 	 * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
136 	 * from the VxWorks BSP header files.
137 	 * This will vary from board to board
138 	 */
139 #if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
140 	tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
141 	eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
142 	memcpy(tmp, build_buf, 6);
143 #else
144 	puts("## Ethernet MAC address not copied to NV RAM\n");
145 #endif
146 
147 #ifdef CONFIG_X86
148 	/*
149 	 * Get VxWorks's physical memory base address from environment,
150 	 * if we don't specify it in the environment, use a default one.
151 	 */
152 	base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
153 	data = (struct e820_entry *)(base + E820_DATA_OFFSET);
154 	info = (struct e820_info *)(base + E820_INFO_OFFSET);
155 
156 	memset(info, 0, sizeof(struct e820_info));
157 	info->sign = E820_SIGNATURE;
158 	info->entries = install_e820_map(E820MAX, data);
159 	info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
160 		     E820_DATA_OFFSET;
161 
162 	/*
163 	 * Explicitly clear the bootloader image size otherwise if memory
164 	 * at this offset happens to contain some garbage data, the final
165 	 * available memory size for the kernel is insane.
166 	 */
167 	*(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
168 
169 	/*
170 	 * Prepare compatible framebuffer information block.
171 	 * The VESA mode has to be 32-bit RGBA.
172 	 */
173 	if (vesa->x_resolution && vesa->y_resolution) {
174 		gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
175 		gop->magic = EFI_GOP_INFO_MAGIC;
176 		gop->info.version = 0;
177 		gop->info.width = vesa->x_resolution;
178 		gop->info.height = vesa->y_resolution;
179 		gop->info.pixel_format = EFI_GOT_RGBA8;
180 		gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
181 		gop->fb_base = vesa->phys_base_ptr;
182 		gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
183 	}
184 #endif
185 
186 	/*
187 	 * Use bootaddr to find the location in memory that VxWorks
188 	 * will look for the bootline string. The default value is
189 	 * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
190 	 * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
191 	 */
192 	tmp = env_get("bootaddr");
193 	if (!tmp) {
194 #ifdef CONFIG_X86
195 		bootaddr = base + X86_BOOT_LINE_OFFSET;
196 #else
197 		printf("## VxWorks bootline address not specified\n");
198 		return 1;
199 #endif
200 	}
201 
202 	if (!bootaddr)
203 		bootaddr = simple_strtoul(tmp, NULL, 16);
204 
205 	/*
206 	 * Check to see if the bootline is defined in the 'bootargs' parameter.
207 	 * If it is not defined, we may be able to construct the info.
208 	 */
209 	bootline = env_get("bootargs");
210 	if (!bootline) {
211 		tmp = env_get("bootdev");
212 		if (tmp) {
213 			strcpy(build_buf, tmp);
214 			ptr = strlen(tmp);
215 		} else {
216 			printf("## VxWorks boot device not specified\n");
217 		}
218 
219 		tmp = env_get("bootfile");
220 		if (tmp)
221 			ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
222 		else
223 			ptr += sprintf(build_buf + ptr, "host:vxWorks ");
224 
225 		/*
226 		 * The following parameters are only needed if 'bootdev'
227 		 * is an ethernet device, otherwise they are optional.
228 		 */
229 		tmp = env_get("ipaddr");
230 		if (tmp) {
231 			ptr += sprintf(build_buf + ptr, "e=%s", tmp);
232 			tmp = env_get("netmask");
233 			if (tmp) {
234 				u32 mask = env_get_ip("netmask").s_addr;
235 				ptr += sprintf(build_buf + ptr,
236 					       ":%08x ", ntohl(mask));
237 			} else {
238 				ptr += sprintf(build_buf + ptr, " ");
239 			}
240 		}
241 
242 		tmp = env_get("serverip");
243 		if (tmp)
244 			ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
245 
246 		tmp = env_get("gatewayip");
247 		if (tmp)
248 			ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
249 
250 		tmp = env_get("hostname");
251 		if (tmp)
252 			ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
253 
254 		tmp = env_get("othbootargs");
255 		if (tmp) {
256 			strcpy(build_buf + ptr, tmp);
257 			ptr += strlen(tmp);
258 		}
259 
260 		bootline = build_buf;
261 	}
262 
263 	memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
264 	flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
265 	printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
266 
267 	/*
268 	 * If the data at the load address is an elf image, then
269 	 * treat it like an elf image. Otherwise, assume that it is a
270 	 * binary image.
271 	 */
272 	if (valid_elf_image(addr))
273 		addr = load_elf_image_phdr(addr);
274 	else
275 		puts("## Not an ELF image, assuming binary\n");
276 
277 	printf("## Starting vxWorks at 0x%08lx ...\n", addr);
278 
279 	dcache_disable();
280 #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
281 	armv8_setup_psci();
282 	smp_kick_all_cpus();
283 #endif
284 
285 #ifdef CONFIG_X86
286 	/* VxWorks on x86 uses stack to pass parameters */
287 	((asmlinkage void (*)(int))addr)(0);
288 #else
289 	((void (*)(int))addr)(0);
290 #endif
291 
292 	puts("## vxWorks terminated\n");
293 
294 	return 1;
295 }
296 
297 U_BOOT_CMD(
298 	bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
299 	"Boot from an ELF image in memory",
300 	"[-p|-s] [address]\n"
301 	"\t- load ELF image at [address] via program headers (-p)\n"
302 	"\t  or via section headers (-s)"
303 );
304 
305 U_BOOT_CMD(
306 	bootvx, 2, 0, do_bootvx,
307 	"Boot vxWorks from an ELF image",
308 	" [address] - load address of vxWorks ELF image."
309 );
310