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