bootm_os.c 14 KB

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