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