xref: /openbmc/u-boot/common/bootm_os.c (revision c225e7cf)
1 /*
2  * (C) Copyright 2000-2009
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <bootm.h>
10 #include <fdt_support.h>
11 #include <linux/libfdt.h>
12 #include <malloc.h>
13 #include <vxworks.h>
14 #include <tee/optee.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 static int do_bootm_standalone(int flag, int argc, char * const argv[],
19 			       bootm_headers_t *images)
20 {
21 	char *s;
22 	int (*appl)(int, char *const[]);
23 
24 	/* Don't start if "autostart" is set to "no" */
25 	s = env_get("autostart");
26 	if ((s != NULL) && !strcmp(s, "no")) {
27 		env_set_hex("filesize", images->os.image_len);
28 		return 0;
29 	}
30 	appl = (int (*)(int, char * const []))images->ep;
31 	appl(argc, argv);
32 	return 0;
33 }
34 
35 /*******************************************************************/
36 /* OS booting routines */
37 /*******************************************************************/
38 
39 #if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
40 static void copy_args(char *dest, int argc, char * const argv[], char delim)
41 {
42 	int i;
43 
44 	for (i = 0; i < argc; i++) {
45 		if (i > 0)
46 			*dest++ = delim;
47 		strcpy(dest, argv[i]);
48 		dest += strlen(argv[i]);
49 	}
50 }
51 #endif
52 
53 #ifdef CONFIG_BOOTM_NETBSD
54 static int do_bootm_netbsd(int flag, int argc, char * const argv[],
55 			    bootm_headers_t *images)
56 {
57 	void (*loader)(bd_t *, image_header_t *, char *, char *);
58 	image_header_t *os_hdr, *hdr;
59 	ulong kernel_data, kernel_len;
60 	char *cmdline;
61 
62 	if (flag != BOOTM_STATE_OS_GO)
63 		return 0;
64 
65 #if defined(CONFIG_FIT)
66 	if (!images->legacy_hdr_valid) {
67 		fit_unsupported_reset("NetBSD");
68 		return 1;
69 	}
70 #endif
71 	hdr = images->legacy_hdr_os;
72 
73 	/*
74 	 * Booting a (NetBSD) kernel image
75 	 *
76 	 * This process is pretty similar to a standalone application:
77 	 * The (first part of an multi-) image must be a stage-2 loader,
78 	 * which in turn is responsible for loading & invoking the actual
79 	 * kernel.  The only differences are the parameters being passed:
80 	 * besides the board info strucure, the loader expects a command
81 	 * line, the name of the console device, and (optionally) the
82 	 * address of the original image header.
83 	 */
84 	os_hdr = NULL;
85 	if (image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
86 		image_multi_getimg(hdr, 1, &kernel_data, &kernel_len);
87 		if (kernel_len)
88 			os_hdr = hdr;
89 	}
90 
91 	if (argc > 0) {
92 		ulong len;
93 		int   i;
94 
95 		for (i = 0, len = 0; i < argc; i += 1)
96 			len += strlen(argv[i]) + 1;
97 		cmdline = malloc(len);
98 		copy_args(cmdline, argc, argv, ' ');
99 	} else {
100 		cmdline = env_get("bootargs");
101 		if (cmdline == NULL)
102 			cmdline = "";
103 	}
104 
105 	loader = (void (*)(bd_t *, image_header_t *, char *, char *))images->ep;
106 
107 	printf("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
108 	       (ulong)loader);
109 
110 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
111 
112 	/*
113 	 * NetBSD Stage-2 Loader Parameters:
114 	 *   arg[0]: pointer to board info data
115 	 *   arg[1]: image load address
116 	 *   arg[2]: char pointer to the console device to use
117 	 *   arg[3]: char pointer to the boot arguments
118 	 */
119 	(*loader)(gd->bd, os_hdr, "", cmdline);
120 
121 	return 1;
122 }
123 #endif /* CONFIG_BOOTM_NETBSD*/
124 
125 #ifdef CONFIG_LYNXKDI
126 static int do_bootm_lynxkdi(int flag, int argc, char * const argv[],
127 			     bootm_headers_t *images)
128 {
129 	image_header_t *hdr = &images->legacy_hdr_os_copy;
130 
131 	if (flag != BOOTM_STATE_OS_GO)
132 		return 0;
133 
134 #if defined(CONFIG_FIT)
135 	if (!images->legacy_hdr_valid) {
136 		fit_unsupported_reset("Lynx");
137 		return 1;
138 	}
139 #endif
140 
141 	lynxkdi_boot((image_header_t *)hdr);
142 
143 	return 1;
144 }
145 #endif /* CONFIG_LYNXKDI */
146 
147 #ifdef CONFIG_BOOTM_RTEMS
148 static int do_bootm_rtems(int flag, int argc, char * const argv[],
149 			   bootm_headers_t *images)
150 {
151 	void (*entry_point)(bd_t *);
152 
153 	if (flag != BOOTM_STATE_OS_GO)
154 		return 0;
155 
156 #if defined(CONFIG_FIT)
157 	if (!images->legacy_hdr_valid) {
158 		fit_unsupported_reset("RTEMS");
159 		return 1;
160 	}
161 #endif
162 
163 	entry_point = (void (*)(bd_t *))images->ep;
164 
165 	printf("## Transferring control to RTEMS (at address %08lx) ...\n",
166 	       (ulong)entry_point);
167 
168 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
169 
170 	/*
171 	 * RTEMS Parameters:
172 	 *   r3: ptr to board info data
173 	 */
174 	(*entry_point)(gd->bd);
175 
176 	return 1;
177 }
178 #endif /* CONFIG_BOOTM_RTEMS */
179 
180 #if defined(CONFIG_BOOTM_OSE)
181 static int do_bootm_ose(int flag, int argc, char * const argv[],
182 			   bootm_headers_t *images)
183 {
184 	void (*entry_point)(void);
185 
186 	if (flag != BOOTM_STATE_OS_GO)
187 		return 0;
188 
189 #if defined(CONFIG_FIT)
190 	if (!images->legacy_hdr_valid) {
191 		fit_unsupported_reset("OSE");
192 		return 1;
193 	}
194 #endif
195 
196 	entry_point = (void (*)(void))images->ep;
197 
198 	printf("## Transferring control to OSE (at address %08lx) ...\n",
199 	       (ulong)entry_point);
200 
201 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
202 
203 	/*
204 	 * OSE Parameters:
205 	 *   None
206 	 */
207 	(*entry_point)();
208 
209 	return 1;
210 }
211 #endif /* CONFIG_BOOTM_OSE */
212 
213 #if defined(CONFIG_BOOTM_PLAN9)
214 static int do_bootm_plan9(int flag, int argc, char * const argv[],
215 			   bootm_headers_t *images)
216 {
217 	void (*entry_point)(void);
218 	char *s;
219 
220 	if (flag != BOOTM_STATE_OS_GO)
221 		return 0;
222 
223 #if defined(CONFIG_FIT)
224 	if (!images->legacy_hdr_valid) {
225 		fit_unsupported_reset("Plan 9");
226 		return 1;
227 	}
228 #endif
229 
230 	/* See README.plan9 */
231 	s = env_get("confaddr");
232 	if (s != NULL) {
233 		char *confaddr = (char *)simple_strtoul(s, NULL, 16);
234 
235 		if (argc > 0) {
236 			copy_args(confaddr, argc, argv, '\n');
237 		} else {
238 			s = env_get("bootargs");
239 			if (s != NULL)
240 				strcpy(confaddr, s);
241 		}
242 	}
243 
244 	entry_point = (void (*)(void))images->ep;
245 
246 	printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
247 	       (ulong)entry_point);
248 
249 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
250 
251 	/*
252 	 * Plan 9 Parameters:
253 	 *   None
254 	 */
255 	(*entry_point)();
256 
257 	return 1;
258 }
259 #endif /* CONFIG_BOOTM_PLAN9 */
260 
261 #if defined(CONFIG_BOOTM_VXWORKS) && \
262 	(defined(CONFIG_PPC) || defined(CONFIG_ARM))
263 
264 void do_bootvx_fdt(bootm_headers_t *images)
265 {
266 #if defined(CONFIG_OF_LIBFDT)
267 	int ret;
268 	char *bootline;
269 	ulong of_size = images->ft_len;
270 	char **of_flat_tree = &images->ft_addr;
271 	struct lmb *lmb = &images->lmb;
272 
273 	if (*of_flat_tree) {
274 		boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
275 
276 		ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
277 		if (ret)
278 			return;
279 
280 		/* Update ethernet nodes */
281 		fdt_fixup_ethernet(*of_flat_tree);
282 
283 		ret = fdt_add_subnode(*of_flat_tree, 0, "chosen");
284 		if ((ret >= 0 || ret == -FDT_ERR_EXISTS)) {
285 			bootline = env_get("bootargs");
286 			if (bootline) {
287 				ret = fdt_find_and_setprop(*of_flat_tree,
288 						"/chosen", "bootargs",
289 						bootline,
290 						strlen(bootline) + 1, 1);
291 				if (ret < 0) {
292 					printf("## ERROR: %s : %s\n", __func__,
293 					       fdt_strerror(ret));
294 					return;
295 				}
296 			}
297 		} else {
298 			printf("## ERROR: %s : %s\n", __func__,
299 			       fdt_strerror(ret));
300 			return;
301 		}
302 	}
303 #endif
304 
305 	boot_prep_vxworks(images);
306 
307 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
308 
309 #if defined(CONFIG_OF_LIBFDT)
310 	printf("## Starting vxWorks at 0x%08lx, device tree at 0x%08lx ...\n",
311 	       (ulong)images->ep, (ulong)*of_flat_tree);
312 #else
313 	printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
314 #endif
315 
316 	boot_jump_vxworks(images);
317 
318 	puts("## vxWorks terminated\n");
319 }
320 
321 static int do_bootm_vxworks(int flag, int argc, char * const argv[],
322 			     bootm_headers_t *images)
323 {
324 	if (flag != BOOTM_STATE_OS_GO)
325 		return 0;
326 
327 #if defined(CONFIG_FIT)
328 	if (!images->legacy_hdr_valid) {
329 		fit_unsupported_reset("VxWorks");
330 		return 1;
331 	}
332 #endif
333 
334 	do_bootvx_fdt(images);
335 
336 	return 1;
337 }
338 #endif
339 
340 #if defined(CONFIG_CMD_ELF)
341 static int do_bootm_qnxelf(int flag, int argc, char * const argv[],
342 			    bootm_headers_t *images)
343 {
344 	char *local_args[2];
345 	char str[16];
346 	int dcache;
347 
348 	if (flag != BOOTM_STATE_OS_GO)
349 		return 0;
350 
351 #if defined(CONFIG_FIT)
352 	if (!images->legacy_hdr_valid) {
353 		fit_unsupported_reset("QNX");
354 		return 1;
355 	}
356 #endif
357 
358 	sprintf(str, "%lx", images->ep); /* write entry-point into string */
359 	local_args[0] = argv[0];
360 	local_args[1] = str;	/* and provide it via the arguments */
361 
362 	/*
363 	 * QNX images require the data cache is disabled.
364 	 */
365 	dcache = dcache_status();
366 	if (dcache)
367 		dcache_disable();
368 
369 	do_bootelf(NULL, 0, 2, local_args);
370 
371 	if (dcache)
372 		dcache_enable();
373 
374 	return 1;
375 }
376 #endif
377 
378 #ifdef CONFIG_INTEGRITY
379 static int do_bootm_integrity(int flag, int argc, char * const argv[],
380 			   bootm_headers_t *images)
381 {
382 	void (*entry_point)(void);
383 
384 	if (flag != BOOTM_STATE_OS_GO)
385 		return 0;
386 
387 #if defined(CONFIG_FIT)
388 	if (!images->legacy_hdr_valid) {
389 		fit_unsupported_reset("INTEGRITY");
390 		return 1;
391 	}
392 #endif
393 
394 	entry_point = (void (*)(void))images->ep;
395 
396 	printf("## Transferring control to INTEGRITY (at address %08lx) ...\n",
397 	       (ulong)entry_point);
398 
399 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
400 
401 	/*
402 	 * INTEGRITY Parameters:
403 	 *   None
404 	 */
405 	(*entry_point)();
406 
407 	return 1;
408 }
409 #endif
410 
411 #ifdef CONFIG_BOOTM_OPENRTOS
412 static int do_bootm_openrtos(int flag, int argc, char * const argv[],
413 			   bootm_headers_t *images)
414 {
415 	void (*entry_point)(void);
416 
417 	if (flag != BOOTM_STATE_OS_GO)
418 		return 0;
419 
420 	entry_point = (void (*)(void))images->ep;
421 
422 	printf("## Transferring control to OpenRTOS (at address %08lx) ...\n",
423 		(ulong)entry_point);
424 
425 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
426 
427 	/*
428 	 * OpenRTOS Parameters:
429 	 *   None
430 	 */
431 	(*entry_point)();
432 
433 	return 1;
434 }
435 #endif
436 
437 #ifdef CONFIG_BOOTM_OPTEE
438 static int do_bootm_tee(int flag, int argc, char * const argv[],
439 			bootm_headers_t *images)
440 {
441 	int ret;
442 
443 	/* Verify OS type */
444 	if (images->os.os != IH_OS_TEE) {
445 		return 1;
446 	};
447 
448 	/* Validate OPTEE header */
449 	ret = optee_verify_bootm_image(images->os.image_start,
450 				       images->os.load,
451 				       images->os.image_len);
452 	if (ret)
453 		return ret;
454 
455 	/* Locate FDT etc */
456 	ret = bootm_find_images(flag, argc, argv);
457 	if (ret)
458 		return ret;
459 
460 	/* From here we can run the regular linux boot path */
461 	return do_bootm_linux(flag, argc, argv, images);
462 }
463 #endif
464 
465 static boot_os_fn *boot_os[] = {
466 	[IH_OS_U_BOOT] = do_bootm_standalone,
467 #ifdef CONFIG_BOOTM_LINUX
468 	[IH_OS_LINUX] = do_bootm_linux,
469 #endif
470 #ifdef CONFIG_BOOTM_NETBSD
471 	[IH_OS_NETBSD] = do_bootm_netbsd,
472 #endif
473 #ifdef CONFIG_LYNXKDI
474 	[IH_OS_LYNXOS] = do_bootm_lynxkdi,
475 #endif
476 #ifdef CONFIG_BOOTM_RTEMS
477 	[IH_OS_RTEMS] = do_bootm_rtems,
478 #endif
479 #if defined(CONFIG_BOOTM_OSE)
480 	[IH_OS_OSE] = do_bootm_ose,
481 #endif
482 #if defined(CONFIG_BOOTM_PLAN9)
483 	[IH_OS_PLAN9] = do_bootm_plan9,
484 #endif
485 #if defined(CONFIG_BOOTM_VXWORKS) && \
486 	(defined(CONFIG_PPC) || defined(CONFIG_ARM))
487 	[IH_OS_VXWORKS] = do_bootm_vxworks,
488 #endif
489 #if defined(CONFIG_CMD_ELF)
490 	[IH_OS_QNX] = do_bootm_qnxelf,
491 #endif
492 #ifdef CONFIG_INTEGRITY
493 	[IH_OS_INTEGRITY] = do_bootm_integrity,
494 #endif
495 #ifdef CONFIG_BOOTM_OPENRTOS
496 	[IH_OS_OPENRTOS] = do_bootm_openrtos,
497 #endif
498 #ifdef CONFIG_BOOTM_OPTEE
499 	[IH_OS_TEE] = do_bootm_tee,
500 #endif
501 };
502 
503 /* Allow for arch specific config before we boot */
504 __weak void arch_preboot_os(void)
505 {
506 	/* please define platform specific arch_preboot_os() */
507 }
508 
509 int boot_selected_os(int argc, char * const argv[], int state,
510 		     bootm_headers_t *images, boot_os_fn *boot_fn)
511 {
512 	arch_preboot_os();
513 	boot_fn(state, argc, argv, images);
514 
515 	/* Stand-alone may return when 'autostart' is 'no' */
516 	if (images->os.type == IH_TYPE_STANDALONE ||
517 	    IS_ENABLED(CONFIG_SANDBOX) ||
518 	    state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
519 		return 0;
520 	bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
521 	debug("\n## Control returned to monitor - resetting...\n");
522 
523 	return BOOTM_ERR_RESET;
524 }
525 
526 boot_os_fn *bootm_os_get_boot_func(int os)
527 {
528 #ifdef CONFIG_NEEDS_MANUAL_RELOC
529 	static bool relocated;
530 
531 	if (!relocated) {
532 		int i;
533 
534 		/* relocate boot function table */
535 		for (i = 0; i < ARRAY_SIZE(boot_os); i++)
536 			if (boot_os[i] != NULL)
537 				boot_os[i] += gd->reloc_off;
538 
539 		relocated = true;
540 	}
541 #endif
542 	return boot_os[os];
543 }
544