blob: 44023532e134ab3811ea74804bde5459dafd5ad1 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass3b5866d2014-06-12 07:24:46 -06002/*
3 * (C) Copyright 2000-2009
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Simon Glass3b5866d2014-06-12 07:24:46 -06005 */
6
7#include <common.h>
8#include <bootm.h>
Simon Glass1ea97892020-05-10 11:40:00 -06009#include <bootstage.h>
Simon Glass1d91ba72019-11-14 12:57:37 -070010#include <cpu_func.h>
Cristian Ciocaltea6aca5982019-12-24 18:05:39 +020011#include <efi_loader.h>
Simon Glass313112a2019-08-01 09:46:46 -060012#include <env.h>
Simon Glass3b5866d2014-06-12 07:24:46 -060013#include <fdt_support.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090014#include <linux/libfdt.h>
Simon Glass3b5866d2014-06-12 07:24:46 -060015#include <malloc.h>
Cristian Ciocaltea6aca5982019-12-24 18:05:39 +020016#include <mapmem.h>
Simon Glass3b5866d2014-06-12 07:24:46 -060017#include <vxworks.h>
Bryan O'Donoghue04ca8152018-03-13 16:50:36 +000018#include <tee/optee.h>
Simon Glass3b5866d2014-06-12 07:24:46 -060019
20DECLARE_GLOBAL_DATA_PTR;
21
22static int do_bootm_standalone(int flag, int argc, char * const argv[],
23 bootm_headers_t *images)
24{
25 char *s;
26 int (*appl)(int, char *const[]);
27
28 /* Don't start if "autostart" is set to "no" */
Simon Glass64b723f2017-08-03 12:22:12 -060029 s = env_get("autostart");
Simon Glass3b5866d2014-06-12 07:24:46 -060030 if ((s != NULL) && !strcmp(s, "no")) {
Simon Glass4d949a22017-08-03 12:22:10 -060031 env_set_hex("filesize", images->os.image_len);
Simon Glass3b5866d2014-06-12 07:24:46 -060032 return 0;
33 }
34 appl = (int (*)(int, char * const []))images->ep;
35 appl(argc, argv);
36 return 0;
37}
38
39/*******************************************************************/
40/* OS booting routines */
41/*******************************************************************/
42
43#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
44static void copy_args(char *dest, int argc, char * const argv[], char delim)
45{
46 int i;
47
48 for (i = 0; i < argc; i++) {
49 if (i > 0)
50 *dest++ = delim;
51 strcpy(dest, argv[i]);
52 dest += strlen(argv[i]);
53 }
54}
55#endif
56
57#ifdef CONFIG_BOOTM_NETBSD
58static int do_bootm_netbsd(int flag, int argc, char * const argv[],
59 bootm_headers_t *images)
60{
61 void (*loader)(bd_t *, image_header_t *, char *, char *);
62 image_header_t *os_hdr, *hdr;
63 ulong kernel_data, kernel_len;
Simon Glass3b5866d2014-06-12 07:24:46 -060064 char *cmdline;
65
66 if (flag != BOOTM_STATE_OS_GO)
67 return 0;
68
69#if defined(CONFIG_FIT)
70 if (!images->legacy_hdr_valid) {
71 fit_unsupported_reset("NetBSD");
72 return 1;
73 }
74#endif
75 hdr = images->legacy_hdr_os;
76
77 /*
78 * Booting a (NetBSD) kernel image
79 *
80 * This process is pretty similar to a standalone application:
81 * The (first part of an multi-) image must be a stage-2 loader,
82 * which in turn is responsible for loading & invoking the actual
83 * kernel. The only differences are the parameters being passed:
84 * besides the board info strucure, the loader expects a command
85 * line, the name of the console device, and (optionally) the
86 * address of the original image header.
87 */
88 os_hdr = NULL;
89 if (image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
90 image_multi_getimg(hdr, 1, &kernel_data, &kernel_len);
91 if (kernel_len)
92 os_hdr = hdr;
93 }
94
Simon Glass3b5866d2014-06-12 07:24:46 -060095 if (argc > 0) {
96 ulong len;
97 int i;
98
99 for (i = 0, len = 0; i < argc; i += 1)
100 len += strlen(argv[i]) + 1;
101 cmdline = malloc(len);
102 copy_args(cmdline, argc, argv, ' ');
103 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600104 cmdline = env_get("bootargs");
Simon Glass3b5866d2014-06-12 07:24:46 -0600105 if (cmdline == NULL)
106 cmdline = "";
107 }
108
109 loader = (void (*)(bd_t *, image_header_t *, char *, char *))images->ep;
110
111 printf("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
112 (ulong)loader);
113
114 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
115
116 /*
117 * NetBSD Stage-2 Loader Parameters:
118 * arg[0]: pointer to board info data
119 * arg[1]: image load address
120 * arg[2]: char pointer to the console device to use
121 * arg[3]: char pointer to the boot arguments
122 */
Heiko Schocher65d94db2017-06-07 17:33:09 +0200123 (*loader)(gd->bd, os_hdr, "", cmdline);
Simon Glass3b5866d2014-06-12 07:24:46 -0600124
125 return 1;
126}
127#endif /* CONFIG_BOOTM_NETBSD*/
128
129#ifdef CONFIG_LYNXKDI
130static int do_bootm_lynxkdi(int flag, int argc, char * const argv[],
131 bootm_headers_t *images)
132{
133 image_header_t *hdr = &images->legacy_hdr_os_copy;
134
135 if (flag != BOOTM_STATE_OS_GO)
136 return 0;
137
138#if defined(CONFIG_FIT)
139 if (!images->legacy_hdr_valid) {
140 fit_unsupported_reset("Lynx");
141 return 1;
142 }
143#endif
144
145 lynxkdi_boot((image_header_t *)hdr);
146
147 return 1;
148}
149#endif /* CONFIG_LYNXKDI */
150
151#ifdef CONFIG_BOOTM_RTEMS
152static int do_bootm_rtems(int flag, int argc, char * const argv[],
153 bootm_headers_t *images)
154{
155 void (*entry_point)(bd_t *);
156
157 if (flag != BOOTM_STATE_OS_GO)
158 return 0;
159
160#if defined(CONFIG_FIT)
161 if (!images->legacy_hdr_valid) {
162 fit_unsupported_reset("RTEMS");
163 return 1;
164 }
165#endif
166
167 entry_point = (void (*)(bd_t *))images->ep;
168
169 printf("## Transferring control to RTEMS (at address %08lx) ...\n",
170 (ulong)entry_point);
171
172 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
173
174 /*
175 * RTEMS Parameters:
176 * r3: ptr to board info data
177 */
178 (*entry_point)(gd->bd);
179
180 return 1;
181}
182#endif /* CONFIG_BOOTM_RTEMS */
183
184#if defined(CONFIG_BOOTM_OSE)
185static int do_bootm_ose(int flag, int argc, char * const argv[],
186 bootm_headers_t *images)
187{
188 void (*entry_point)(void);
189
190 if (flag != BOOTM_STATE_OS_GO)
191 return 0;
192
193#if defined(CONFIG_FIT)
194 if (!images->legacy_hdr_valid) {
195 fit_unsupported_reset("OSE");
196 return 1;
197 }
198#endif
199
200 entry_point = (void (*)(void))images->ep;
201
202 printf("## Transferring control to OSE (at address %08lx) ...\n",
203 (ulong)entry_point);
204
205 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
206
207 /*
208 * OSE Parameters:
209 * None
210 */
211 (*entry_point)();
212
213 return 1;
214}
215#endif /* CONFIG_BOOTM_OSE */
216
217#if defined(CONFIG_BOOTM_PLAN9)
218static int do_bootm_plan9(int flag, int argc, char * const argv[],
219 bootm_headers_t *images)
220{
221 void (*entry_point)(void);
222 char *s;
223
224 if (flag != BOOTM_STATE_OS_GO)
225 return 0;
226
227#if defined(CONFIG_FIT)
228 if (!images->legacy_hdr_valid) {
229 fit_unsupported_reset("Plan 9");
230 return 1;
231 }
232#endif
233
234 /* See README.plan9 */
Simon Glass64b723f2017-08-03 12:22:12 -0600235 s = env_get("confaddr");
Simon Glass3b5866d2014-06-12 07:24:46 -0600236 if (s != NULL) {
237 char *confaddr = (char *)simple_strtoul(s, NULL, 16);
238
239 if (argc > 0) {
240 copy_args(confaddr, argc, argv, '\n');
241 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600242 s = env_get("bootargs");
Simon Glass3b5866d2014-06-12 07:24:46 -0600243 if (s != NULL)
244 strcpy(confaddr, s);
245 }
246 }
247
248 entry_point = (void (*)(void))images->ep;
249
250 printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
251 (ulong)entry_point);
252
253 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
254
255 /*
256 * Plan 9 Parameters:
257 * None
258 */
259 (*entry_point)();
260
261 return 1;
262}
263#endif /* CONFIG_BOOTM_PLAN9 */
264
265#if defined(CONFIG_BOOTM_VXWORKS) && \
266 (defined(CONFIG_PPC) || defined(CONFIG_ARM))
267
Bin Mengb43c3222018-12-21 07:13:39 -0800268static void do_bootvx_fdt(bootm_headers_t *images)
Simon Glass3b5866d2014-06-12 07:24:46 -0600269{
270#if defined(CONFIG_OF_LIBFDT)
271 int ret;
272 char *bootline;
273 ulong of_size = images->ft_len;
274 char **of_flat_tree = &images->ft_addr;
275 struct lmb *lmb = &images->lmb;
276
277 if (*of_flat_tree) {
278 boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
279
280 ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
281 if (ret)
282 return;
283
Hannes Schmelzer51962ee2017-08-25 14:27:37 +0200284 /* Update ethernet nodes */
285 fdt_fixup_ethernet(*of_flat_tree);
286
Simon Glass3b5866d2014-06-12 07:24:46 -0600287 ret = fdt_add_subnode(*of_flat_tree, 0, "chosen");
288 if ((ret >= 0 || ret == -FDT_ERR_EXISTS)) {
Simon Glass64b723f2017-08-03 12:22:12 -0600289 bootline = env_get("bootargs");
Simon Glass3b5866d2014-06-12 07:24:46 -0600290 if (bootline) {
291 ret = fdt_find_and_setprop(*of_flat_tree,
292 "/chosen", "bootargs",
293 bootline,
294 strlen(bootline) + 1, 1);
295 if (ret < 0) {
296 printf("## ERROR: %s : %s\n", __func__,
297 fdt_strerror(ret));
298 return;
299 }
300 }
301 } else {
302 printf("## ERROR: %s : %s\n", __func__,
303 fdt_strerror(ret));
304 return;
305 }
306 }
307#endif
308
309 boot_prep_vxworks(images);
310
311 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
312
313#if defined(CONFIG_OF_LIBFDT)
314 printf("## Starting vxWorks at 0x%08lx, device tree at 0x%08lx ...\n",
315 (ulong)images->ep, (ulong)*of_flat_tree);
316#else
317 printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
318#endif
319
320 boot_jump_vxworks(images);
321
322 puts("## vxWorks terminated\n");
323}
324
Lihua Zhaodcda76e2019-11-15 00:21:17 -0800325static int do_bootm_vxworks_legacy(int flag, int argc, char * const argv[],
326 bootm_headers_t *images)
Simon Glass3b5866d2014-06-12 07:24:46 -0600327{
328 if (flag != BOOTM_STATE_OS_GO)
329 return 0;
330
331#if defined(CONFIG_FIT)
332 if (!images->legacy_hdr_valid) {
333 fit_unsupported_reset("VxWorks");
334 return 1;
335 }
336#endif
337
338 do_bootvx_fdt(images);
339
340 return 1;
341}
Lihua Zhaodcda76e2019-11-15 00:21:17 -0800342
343int do_bootm_vxworks(int flag, int argc, char * const argv[],
344 bootm_headers_t *images)
345{
346 char *bootargs;
347 int pos;
348 unsigned long vxflags;
349 bool std_dtb = false;
350
351 /* get bootargs env */
352 bootargs = env_get("bootargs");
353
354 if (bootargs != NULL) {
355 for (pos = 0; pos < strlen(bootargs); pos++) {
356 /* find f=0xnumber flag */
357 if ((bootargs[pos] == '=') && (pos >= 1) &&
358 (bootargs[pos - 1] == 'f')) {
359 vxflags = simple_strtoul(&bootargs[pos + 1],
360 NULL, 16);
361 if (vxflags & VXWORKS_SYSFLG_STD_DTB)
362 std_dtb = true;
363 }
364 }
365 }
366
367 if (std_dtb) {
368 if (flag & BOOTM_STATE_OS_PREP)
369 printf(" Using standard DTB\n");
370 return do_bootm_linux(flag, argc, argv, images);
371 } else {
372 if (flag & BOOTM_STATE_OS_PREP)
373 printf(" !!! WARNING !!! Using legacy DTB\n");
374 return do_bootm_vxworks_legacy(flag, argc, argv, images);
375 }
376}
Simon Glass3b5866d2014-06-12 07:24:46 -0600377#endif
378
379#if defined(CONFIG_CMD_ELF)
380static int do_bootm_qnxelf(int flag, int argc, char * const argv[],
381 bootm_headers_t *images)
382{
383 char *local_args[2];
384 char str[16];
Emmanuel Vadot9a922b42017-01-19 10:23:56 +0100385 int dcache;
Simon Glass3b5866d2014-06-12 07:24:46 -0600386
387 if (flag != BOOTM_STATE_OS_GO)
388 return 0;
389
390#if defined(CONFIG_FIT)
391 if (!images->legacy_hdr_valid) {
392 fit_unsupported_reset("QNX");
393 return 1;
394 }
395#endif
396
397 sprintf(str, "%lx", images->ep); /* write entry-point into string */
398 local_args[0] = argv[0];
399 local_args[1] = str; /* and provide it via the arguments */
Emmanuel Vadot9a922b42017-01-19 10:23:56 +0100400
401 /*
402 * QNX images require the data cache is disabled.
403 */
404 dcache = dcache_status();
405 if (dcache)
406 dcache_disable();
407
Simon Glass3b5866d2014-06-12 07:24:46 -0600408 do_bootelf(NULL, 0, 2, local_args);
409
Emmanuel Vadot9a922b42017-01-19 10:23:56 +0100410 if (dcache)
411 dcache_enable();
412
Simon Glass3b5866d2014-06-12 07:24:46 -0600413 return 1;
414}
415#endif
416
417#ifdef CONFIG_INTEGRITY
418static int do_bootm_integrity(int flag, int argc, char * const argv[],
419 bootm_headers_t *images)
420{
421 void (*entry_point)(void);
422
423 if (flag != BOOTM_STATE_OS_GO)
424 return 0;
425
426#if defined(CONFIG_FIT)
427 if (!images->legacy_hdr_valid) {
428 fit_unsupported_reset("INTEGRITY");
429 return 1;
430 }
431#endif
432
433 entry_point = (void (*)(void))images->ep;
434
435 printf("## Transferring control to INTEGRITY (at address %08lx) ...\n",
436 (ulong)entry_point);
437
438 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
439
440 /*
441 * INTEGRITY Parameters:
442 * None
443 */
444 (*entry_point)();
445
446 return 1;
447}
448#endif
449
Marek Vasut0e3b5122014-12-16 14:07:21 +0100450#ifdef CONFIG_BOOTM_OPENRTOS
451static int do_bootm_openrtos(int flag, int argc, char * const argv[],
452 bootm_headers_t *images)
453{
454 void (*entry_point)(void);
455
456 if (flag != BOOTM_STATE_OS_GO)
457 return 0;
458
459 entry_point = (void (*)(void))images->ep;
460
461 printf("## Transferring control to OpenRTOS (at address %08lx) ...\n",
462 (ulong)entry_point);
463
464 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
465
466 /*
467 * OpenRTOS Parameters:
468 * None
469 */
470 (*entry_point)();
471
472 return 1;
473}
474#endif
475
Bryan O'Donoghue04ca8152018-03-13 16:50:36 +0000476#ifdef CONFIG_BOOTM_OPTEE
477static int do_bootm_tee(int flag, int argc, char * const argv[],
478 bootm_headers_t *images)
479{
480 int ret;
481
482 /* Verify OS type */
483 if (images->os.os != IH_OS_TEE) {
484 return 1;
485 };
486
487 /* Validate OPTEE header */
488 ret = optee_verify_bootm_image(images->os.image_start,
489 images->os.load,
490 images->os.image_len);
491 if (ret)
492 return ret;
493
494 /* Locate FDT etc */
495 ret = bootm_find_images(flag, argc, argv);
496 if (ret)
497 return ret;
498
499 /* From here we can run the regular linux boot path */
500 return do_bootm_linux(flag, argc, argv, images);
501}
502#endif
503
Cristian Ciocaltea6aca5982019-12-24 18:05:39 +0200504#ifdef CONFIG_BOOTM_EFI
505static int do_bootm_efi(int flag, int argc, char * const argv[],
506 bootm_headers_t *images)
507{
508 int ret;
509 efi_status_t efi_ret;
510 void *image_buf;
511
512 if (flag != BOOTM_STATE_OS_GO)
513 return 0;
514
515 /* Locate FDT, if provided */
516 ret = bootm_find_images(flag, argc, argv);
517 if (ret)
518 return ret;
519
520 /* Initialize EFI drivers */
521 efi_ret = efi_init_obj_list();
522 if (efi_ret != EFI_SUCCESS) {
523 printf("## Failed to initialize UEFI sub-system: r = %lu\n",
524 efi_ret & ~EFI_ERROR_MASK);
525 return 1;
526 }
527
528 /* Install device tree */
529 efi_ret = efi_install_fdt(images->ft_len
530 ? images->ft_addr : EFI_FDT_USE_INTERNAL);
531 if (efi_ret != EFI_SUCCESS) {
532 printf("## Failed to install device tree: r = %lu\n",
533 efi_ret & ~EFI_ERROR_MASK);
534 return 1;
535 }
536
537 /* Run EFI image */
538 printf("## Transferring control to EFI (at address %08lx) ...\n",
539 images->ep);
540 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
541
542 image_buf = map_sysmem(images->ep, images->os.image_len);
543
544 efi_ret = efi_run_image(image_buf, images->os.image_len);
545 if (efi_ret != EFI_SUCCESS) {
546 printf("## Failed to run EFI image: r = %lu\n",
547 efi_ret & ~EFI_ERROR_MASK);
548 return 1;
549 }
550
551 return 0;
552}
553#endif
554
Simon Glass3b5866d2014-06-12 07:24:46 -0600555static boot_os_fn *boot_os[] = {
556 [IH_OS_U_BOOT] = do_bootm_standalone,
557#ifdef CONFIG_BOOTM_LINUX
558 [IH_OS_LINUX] = do_bootm_linux,
559#endif
560#ifdef CONFIG_BOOTM_NETBSD
561 [IH_OS_NETBSD] = do_bootm_netbsd,
562#endif
563#ifdef CONFIG_LYNXKDI
564 [IH_OS_LYNXOS] = do_bootm_lynxkdi,
565#endif
566#ifdef CONFIG_BOOTM_RTEMS
567 [IH_OS_RTEMS] = do_bootm_rtems,
568#endif
569#if defined(CONFIG_BOOTM_OSE)
570 [IH_OS_OSE] = do_bootm_ose,
571#endif
572#if defined(CONFIG_BOOTM_PLAN9)
573 [IH_OS_PLAN9] = do_bootm_plan9,
574#endif
575#if defined(CONFIG_BOOTM_VXWORKS) && \
Bin Menge63488f2018-12-21 07:13:41 -0800576 (defined(CONFIG_PPC) || defined(CONFIG_ARM) || defined(CONFIG_RISCV))
Simon Glass3b5866d2014-06-12 07:24:46 -0600577 [IH_OS_VXWORKS] = do_bootm_vxworks,
578#endif
579#if defined(CONFIG_CMD_ELF)
580 [IH_OS_QNX] = do_bootm_qnxelf,
581#endif
582#ifdef CONFIG_INTEGRITY
583 [IH_OS_INTEGRITY] = do_bootm_integrity,
584#endif
Marek Vasut0e3b5122014-12-16 14:07:21 +0100585#ifdef CONFIG_BOOTM_OPENRTOS
586 [IH_OS_OPENRTOS] = do_bootm_openrtos,
587#endif
Bryan O'Donoghue04ca8152018-03-13 16:50:36 +0000588#ifdef CONFIG_BOOTM_OPTEE
589 [IH_OS_TEE] = do_bootm_tee,
590#endif
Cristian Ciocaltea6aca5982019-12-24 18:05:39 +0200591#ifdef CONFIG_BOOTM_EFI
592 [IH_OS_EFI] = do_bootm_efi,
593#endif
Simon Glass3b5866d2014-06-12 07:24:46 -0600594};
595
596/* Allow for arch specific config before we boot */
Jeroen Hofsteef7d4a492014-07-10 23:06:25 +0200597__weak void arch_preboot_os(void)
Simon Glass3b5866d2014-06-12 07:24:46 -0600598{
599 /* please define platform specific arch_preboot_os() */
600}
Simon Glass3b5866d2014-06-12 07:24:46 -0600601
Marek Vasut5b9fbd92018-10-04 21:16:31 +0200602/* Allow for board specific config before we boot */
603__weak void board_preboot_os(void)
604{
605 /* please define board specific board_preboot_os() */
606}
607
Simon Glass3b5866d2014-06-12 07:24:46 -0600608int boot_selected_os(int argc, char * const argv[], int state,
609 bootm_headers_t *images, boot_os_fn *boot_fn)
610{
611 arch_preboot_os();
Marek Vasut5b9fbd92018-10-04 21:16:31 +0200612 board_preboot_os();
Simon Glass3b5866d2014-06-12 07:24:46 -0600613 boot_fn(state, argc, argv, images);
614
615 /* Stand-alone may return when 'autostart' is 'no' */
616 if (images->os.type == IH_TYPE_STANDALONE ||
Simon Glass43cdb792016-07-03 09:40:35 -0600617 IS_ENABLED(CONFIG_SANDBOX) ||
Simon Glass3b5866d2014-06-12 07:24:46 -0600618 state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
619 return 0;
620 bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
Lukasz Majewski9167e102016-05-08 08:52:21 +0200621 debug("\n## Control returned to monitor - resetting...\n");
622
Simon Glass3b5866d2014-06-12 07:24:46 -0600623 return BOOTM_ERR_RESET;
624}
625
626boot_os_fn *bootm_os_get_boot_func(int os)
627{
628#ifdef CONFIG_NEEDS_MANUAL_RELOC
629 static bool relocated;
630
631 if (!relocated) {
632 int i;
633
634 /* relocate boot function table */
635 for (i = 0; i < ARRAY_SIZE(boot_os); i++)
636 if (boot_os[i] != NULL)
637 boot_os[i] += gd->reloc_off;
638
639 relocated = true;
640 }
641#endif
642 return boot_os[os];
643}