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