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