xref: /openbmc/u-boot/cmd/bootm.c (revision c2e7e72b)
12e192b24SSimon Glass /*
22e192b24SSimon Glass  * (C) Copyright 2000-2009
32e192b24SSimon Glass  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
42e192b24SSimon Glass  *
52e192b24SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
62e192b24SSimon Glass  */
72e192b24SSimon Glass 
82e192b24SSimon Glass /*
92e192b24SSimon Glass  * Boot support
102e192b24SSimon Glass  */
112e192b24SSimon Glass #include <common.h>
122e192b24SSimon Glass #include <bootm.h>
132e192b24SSimon Glass #include <command.h>
142e192b24SSimon Glass #include <environment.h>
152e192b24SSimon Glass #include <errno.h>
162e192b24SSimon Glass #include <image.h>
172e192b24SSimon Glass #include <malloc.h>
182e192b24SSimon Glass #include <nand.h>
192e192b24SSimon Glass #include <asm/byteorder.h>
202e192b24SSimon Glass #include <linux/ctype.h>
212e192b24SSimon Glass #include <linux/err.h>
222e192b24SSimon Glass #include <u-boot/zlib.h>
232e192b24SSimon Glass 
242e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR;
252e192b24SSimon Glass 
262e192b24SSimon Glass #if defined(CONFIG_CMD_IMI)
272e192b24SSimon Glass static int image_info(unsigned long addr);
282e192b24SSimon Glass #endif
292e192b24SSimon Glass 
302e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS)
312e192b24SSimon Glass #include <flash.h>
322e192b24SSimon Glass #include <mtd/cfi_flash.h>
332e192b24SSimon Glass extern flash_info_t flash_info[]; /* info for FLASH chips */
342e192b24SSimon Glass #endif
352e192b24SSimon Glass 
362e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
372e192b24SSimon Glass static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
382e192b24SSimon Glass #endif
392e192b24SSimon Glass 
402e192b24SSimon Glass /* we overload the cmd field with our state machine info instead of a
412e192b24SSimon Glass  * function pointer */
422e192b24SSimon Glass static cmd_tbl_t cmd_bootm_sub[] = {
432e192b24SSimon Glass 	U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""),
442e192b24SSimon Glass 	U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""),
452e192b24SSimon Glass #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
462e192b24SSimon Glass 	U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""),
472e192b24SSimon Glass #endif
482e192b24SSimon Glass #ifdef CONFIG_OF_LIBFDT
492e192b24SSimon Glass 	U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""),
502e192b24SSimon Glass #endif
512e192b24SSimon Glass 	U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),
522e192b24SSimon Glass 	U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),
532e192b24SSimon Glass 	U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""),
542e192b24SSimon Glass 	U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),
552e192b24SSimon Glass 	U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),
562e192b24SSimon Glass };
572e192b24SSimon Glass 
582e192b24SSimon Glass static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
592e192b24SSimon Glass 			char * const argv[])
602e192b24SSimon Glass {
612e192b24SSimon Glass 	int ret = 0;
622e192b24SSimon Glass 	long state;
632e192b24SSimon Glass 	cmd_tbl_t *c;
642e192b24SSimon Glass 
652e192b24SSimon Glass 	c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
662e192b24SSimon Glass 	argc--; argv++;
672e192b24SSimon Glass 
682e192b24SSimon Glass 	if (c) {
692e192b24SSimon Glass 		state = (long)c->cmd;
702e192b24SSimon Glass 		if (state == BOOTM_STATE_START)
712e192b24SSimon Glass 			state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER;
722e192b24SSimon Glass 	} else {
732e192b24SSimon Glass 		/* Unrecognized command */
742e192b24SSimon Glass 		return CMD_RET_USAGE;
752e192b24SSimon Glass 	}
762e192b24SSimon Glass 
772e192b24SSimon Glass 	if (((state & BOOTM_STATE_START) != BOOTM_STATE_START) &&
782e192b24SSimon Glass 	    images.state >= state) {
792e192b24SSimon Glass 		printf("Trying to execute a command out of order\n");
802e192b24SSimon Glass 		return CMD_RET_USAGE;
812e192b24SSimon Glass 	}
822e192b24SSimon Glass 
832e192b24SSimon Glass 	ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0);
842e192b24SSimon Glass 
852e192b24SSimon Glass 	return ret;
862e192b24SSimon Glass }
872e192b24SSimon Glass 
882e192b24SSimon Glass /*******************************************************************/
892e192b24SSimon Glass /* bootm - boot application image from image in memory */
902e192b24SSimon Glass /*******************************************************************/
912e192b24SSimon Glass 
922e192b24SSimon Glass int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
932e192b24SSimon Glass {
942e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC
952e192b24SSimon Glass 	static int relocated = 0;
962e192b24SSimon Glass 
972e192b24SSimon Glass 	if (!relocated) {
982e192b24SSimon Glass 		int i;
992e192b24SSimon Glass 
1002e192b24SSimon Glass 		/* relocate names of sub-command table */
1012e192b24SSimon Glass 		for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++)
1022e192b24SSimon Glass 			cmd_bootm_sub[i].name += gd->reloc_off;
1032e192b24SSimon Glass 
1042e192b24SSimon Glass 		relocated = 1;
1052e192b24SSimon Glass 	}
1062e192b24SSimon Glass #endif
1072e192b24SSimon Glass 
1082e192b24SSimon Glass 	/* determine if we have a sub command */
1092e192b24SSimon Glass 	argc--; argv++;
1102e192b24SSimon Glass 	if (argc > 0) {
1112e192b24SSimon Glass 		char *endp;
1122e192b24SSimon Glass 
1132e192b24SSimon Glass 		simple_strtoul(argv[0], &endp, 16);
1142e192b24SSimon Glass 		/* endp pointing to NULL means that argv[0] was just a
1152e192b24SSimon Glass 		 * valid number, pass it along to the normal bootm processing
1162e192b24SSimon Glass 		 *
1172e192b24SSimon Glass 		 * If endp is ':' or '#' assume a FIT identifier so pass
1182e192b24SSimon Glass 		 * along for normal processing.
1192e192b24SSimon Glass 		 *
1202e192b24SSimon Glass 		 * Right now we assume the first arg should never be '-'
1212e192b24SSimon Glass 		 */
1222e192b24SSimon Glass 		if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
1232e192b24SSimon Glass 			return do_bootm_subcommand(cmdtp, flag, argc, argv);
1242e192b24SSimon Glass 	}
1252e192b24SSimon Glass 
1262e192b24SSimon Glass 	return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
1272e192b24SSimon Glass 		BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
1282e192b24SSimon Glass 		BOOTM_STATE_LOADOS |
129*c2e7e72bSRick Altherr #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
130*c2e7e72bSRick Altherr 		BOOTM_STATE_RAMDISK |
131*c2e7e72bSRick Altherr #endif
1322e192b24SSimon Glass #if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
1332e192b24SSimon Glass 		BOOTM_STATE_OS_CMDLINE |
1342e192b24SSimon Glass #endif
1352e192b24SSimon Glass 		BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
1362e192b24SSimon Glass 		BOOTM_STATE_OS_GO, &images, 1);
1372e192b24SSimon Glass }
1382e192b24SSimon Glass 
1392e192b24SSimon Glass int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
1402e192b24SSimon Glass {
1412e192b24SSimon Glass 	const char *ep = getenv("autostart");
1422e192b24SSimon Glass 
1432e192b24SSimon Glass 	if (ep && !strcmp(ep, "yes")) {
1442e192b24SSimon Glass 		char *local_args[2];
1452e192b24SSimon Glass 		local_args[0] = (char *)cmd;
1462e192b24SSimon Glass 		local_args[1] = NULL;
1472e192b24SSimon Glass 		printf("Automatic boot of image at addr 0x%08lX ...\n", load_addr);
1482e192b24SSimon Glass 		return do_bootm(cmdtp, 0, 1, local_args);
1492e192b24SSimon Glass 	}
1502e192b24SSimon Glass 
1512e192b24SSimon Glass 	return 0;
1522e192b24SSimon Glass }
1532e192b24SSimon Glass 
1542e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP
1552e192b24SSimon Glass static char bootm_help_text[] =
1562e192b24SSimon Glass 	"[addr [arg ...]]\n    - boot application image stored in memory\n"
1572e192b24SSimon Glass 	"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
1582e192b24SSimon Glass 	"\t'arg' can be the address of an initrd image\n"
1592e192b24SSimon Glass #if defined(CONFIG_OF_LIBFDT)
1602e192b24SSimon Glass 	"\tWhen booting a Linux kernel which requires a flat device-tree\n"
1612e192b24SSimon Glass 	"\ta third argument is required which is the address of the\n"
1622e192b24SSimon Glass 	"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
1632e192b24SSimon Glass 	"\tuse a '-' for the second argument. If you do not pass a third\n"
1642e192b24SSimon Glass 	"\ta bd_info struct will be passed instead\n"
1652e192b24SSimon Glass #endif
1662e192b24SSimon Glass #if defined(CONFIG_FIT)
1672e192b24SSimon Glass 	"\t\nFor the new multi component uImage format (FIT) addresses\n"
168da1a3bd4SVagrant Cascadian 	"\tmust be extended to include component or configuration unit name:\n"
1692e192b24SSimon Glass 	"\taddr:<subimg_uname> - direct component image specification\n"
1702e192b24SSimon Glass 	"\taddr#<conf_uname>   - configuration specification\n"
1712e192b24SSimon Glass 	"\tUse iminfo command to get the list of existing component\n"
1722e192b24SSimon Glass 	"\timages and configurations.\n"
1732e192b24SSimon Glass #endif
1742e192b24SSimon Glass 	"\nSub-commands to do part of the bootm sequence.  The sub-commands "
1752e192b24SSimon Glass 	"must be\n"
1762e192b24SSimon Glass 	"issued in the order below (it's ok to not issue all sub-commands):\n"
1772e192b24SSimon Glass 	"\tstart [addr [arg ...]]\n"
1782e192b24SSimon Glass 	"\tloados  - load OS image\n"
1792e192b24SSimon Glass #if defined(CONFIG_SYS_BOOT_RAMDISK_HIGH)
1802e192b24SSimon Glass 	"\tramdisk - relocate initrd, set env initrd_start/initrd_end\n"
1812e192b24SSimon Glass #endif
1822e192b24SSimon Glass #if defined(CONFIG_OF_LIBFDT)
1832e192b24SSimon Glass 	"\tfdt     - relocate flat device tree\n"
1842e192b24SSimon Glass #endif
1852e192b24SSimon Glass 	"\tcmdline - OS specific command line processing/setup\n"
1862e192b24SSimon Glass 	"\tbdt     - OS specific bd_t processing\n"
1872e192b24SSimon Glass 	"\tprep    - OS specific prep before relocation or go\n"
1882e192b24SSimon Glass #if defined(CONFIG_TRACE)
1892e192b24SSimon Glass 	"\tfake    - OS specific fake start without go\n"
1902e192b24SSimon Glass #endif
1912e192b24SSimon Glass 	"\tgo      - start OS";
1922e192b24SSimon Glass #endif
1932e192b24SSimon Glass 
1942e192b24SSimon Glass U_BOOT_CMD(
1952e192b24SSimon Glass 	bootm,	CONFIG_SYS_MAXARGS,	1,	do_bootm,
1962e192b24SSimon Glass 	"boot application image from memory", bootm_help_text
1972e192b24SSimon Glass );
1982e192b24SSimon Glass 
1992e192b24SSimon Glass /*******************************************************************/
2002e192b24SSimon Glass /* bootd - boot default image */
2012e192b24SSimon Glass /*******************************************************************/
2022e192b24SSimon Glass #if defined(CONFIG_CMD_BOOTD)
2032e192b24SSimon Glass int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2042e192b24SSimon Glass {
2052e192b24SSimon Glass 	return run_command(getenv("bootcmd"), flag);
2062e192b24SSimon Glass }
2072e192b24SSimon Glass 
2082e192b24SSimon Glass U_BOOT_CMD(
2092e192b24SSimon Glass 	boot,	1,	1,	do_bootd,
2102e192b24SSimon Glass 	"boot default, i.e., run 'bootcmd'",
2112e192b24SSimon Glass 	""
2122e192b24SSimon Glass );
2132e192b24SSimon Glass 
2142e192b24SSimon Glass /* keep old command name "bootd" for backward compatibility */
2152e192b24SSimon Glass U_BOOT_CMD(
2162e192b24SSimon Glass 	bootd, 1,	1,	do_bootd,
2172e192b24SSimon Glass 	"boot default, i.e., run 'bootcmd'",
2182e192b24SSimon Glass 	""
2192e192b24SSimon Glass );
2202e192b24SSimon Glass 
2212e192b24SSimon Glass #endif
2222e192b24SSimon Glass 
2232e192b24SSimon Glass 
2242e192b24SSimon Glass /*******************************************************************/
2252e192b24SSimon Glass /* iminfo - print header info for a requested image */
2262e192b24SSimon Glass /*******************************************************************/
2272e192b24SSimon Glass #if defined(CONFIG_CMD_IMI)
2282e192b24SSimon Glass static int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
2292e192b24SSimon Glass {
2302e192b24SSimon Glass 	int	arg;
2312e192b24SSimon Glass 	ulong	addr;
2322e192b24SSimon Glass 	int	rcode = 0;
2332e192b24SSimon Glass 
2342e192b24SSimon Glass 	if (argc < 2) {
2352e192b24SSimon Glass 		return image_info(load_addr);
2362e192b24SSimon Glass 	}
2372e192b24SSimon Glass 
2382e192b24SSimon Glass 	for (arg = 1; arg < argc; ++arg) {
2392e192b24SSimon Glass 		addr = simple_strtoul(argv[arg], NULL, 16);
2402e192b24SSimon Glass 		if (image_info(addr) != 0)
2412e192b24SSimon Glass 			rcode = 1;
2422e192b24SSimon Glass 	}
2432e192b24SSimon Glass 	return rcode;
2442e192b24SSimon Glass }
2452e192b24SSimon Glass 
2462e192b24SSimon Glass static int image_info(ulong addr)
2472e192b24SSimon Glass {
2482e192b24SSimon Glass 	void *hdr = (void *)addr;
2492e192b24SSimon Glass 
2502e192b24SSimon Glass 	printf("\n## Checking Image at %08lx ...\n", addr);
2512e192b24SSimon Glass 
2522e192b24SSimon Glass 	switch (genimg_get_format(hdr)) {
2532e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
2542e192b24SSimon Glass 	case IMAGE_FORMAT_LEGACY:
2552e192b24SSimon Glass 		puts("   Legacy image found\n");
2562e192b24SSimon Glass 		if (!image_check_magic(hdr)) {
2572e192b24SSimon Glass 			puts("   Bad Magic Number\n");
2582e192b24SSimon Glass 			return 1;
2592e192b24SSimon Glass 		}
2602e192b24SSimon Glass 
2612e192b24SSimon Glass 		if (!image_check_hcrc(hdr)) {
2622e192b24SSimon Glass 			puts("   Bad Header Checksum\n");
2632e192b24SSimon Glass 			return 1;
2642e192b24SSimon Glass 		}
2652e192b24SSimon Glass 
2662e192b24SSimon Glass 		image_print_contents(hdr);
2672e192b24SSimon Glass 
2682e192b24SSimon Glass 		puts("   Verifying Checksum ... ");
2692e192b24SSimon Glass 		if (!image_check_dcrc(hdr)) {
2702e192b24SSimon Glass 			puts("   Bad Data CRC\n");
2712e192b24SSimon Glass 			return 1;
2722e192b24SSimon Glass 		}
2732e192b24SSimon Glass 		puts("OK\n");
2742e192b24SSimon Glass 		return 0;
2752e192b24SSimon Glass #endif
2764f1318b2SMichael Trimarchi #if defined(CONFIG_ANDROID_BOOT_IMAGE)
2774f1318b2SMichael Trimarchi 	case IMAGE_FORMAT_ANDROID:
2784f1318b2SMichael Trimarchi 		puts("   Android image found\n");
2794f1318b2SMichael Trimarchi 		android_print_contents(hdr);
2804f1318b2SMichael Trimarchi 		return 0;
2814f1318b2SMichael Trimarchi #endif
2822e192b24SSimon Glass #if defined(CONFIG_FIT)
2832e192b24SSimon Glass 	case IMAGE_FORMAT_FIT:
2842e192b24SSimon Glass 		puts("   FIT image found\n");
2852e192b24SSimon Glass 
2862e192b24SSimon Glass 		if (!fit_check_format(hdr)) {
2872e192b24SSimon Glass 			puts("Bad FIT image format!\n");
2882e192b24SSimon Glass 			return 1;
2892e192b24SSimon Glass 		}
2902e192b24SSimon Glass 
2912e192b24SSimon Glass 		fit_print_contents(hdr);
2922e192b24SSimon Glass 
2932e192b24SSimon Glass 		if (!fit_all_image_verify(hdr)) {
2942e192b24SSimon Glass 			puts("Bad hash in FIT image!\n");
2952e192b24SSimon Glass 			return 1;
2962e192b24SSimon Glass 		}
2972e192b24SSimon Glass 
2982e192b24SSimon Glass 		return 0;
2992e192b24SSimon Glass #endif
3002e192b24SSimon Glass 	default:
3012e192b24SSimon Glass 		puts("Unknown image format!\n");
3022e192b24SSimon Glass 		break;
3032e192b24SSimon Glass 	}
3042e192b24SSimon Glass 
3052e192b24SSimon Glass 	return 1;
3062e192b24SSimon Glass }
3072e192b24SSimon Glass 
3082e192b24SSimon Glass U_BOOT_CMD(
3092e192b24SSimon Glass 	iminfo,	CONFIG_SYS_MAXARGS,	1,	do_iminfo,
3102e192b24SSimon Glass 	"print header information for application image",
3112e192b24SSimon Glass 	"addr [addr ...]\n"
3122e192b24SSimon Glass 	"    - print header information for application image starting at\n"
3132e192b24SSimon Glass 	"      address 'addr' in memory; this includes verification of the\n"
3142e192b24SSimon Glass 	"      image contents (magic number, header and payload checksums)"
3152e192b24SSimon Glass );
3162e192b24SSimon Glass #endif
3172e192b24SSimon Glass 
3182e192b24SSimon Glass 
3192e192b24SSimon Glass /*******************************************************************/
3202e192b24SSimon Glass /* imls - list all images found in flash */
3212e192b24SSimon Glass /*******************************************************************/
3222e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS)
3232e192b24SSimon Glass static int do_imls_nor(void)
3242e192b24SSimon Glass {
3252e192b24SSimon Glass 	flash_info_t *info;
3262e192b24SSimon Glass 	int i, j;
3272e192b24SSimon Glass 	void *hdr;
3282e192b24SSimon Glass 
3292e192b24SSimon Glass 	for (i = 0, info = &flash_info[0];
3302e192b24SSimon Glass 		i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
3312e192b24SSimon Glass 
3322e192b24SSimon Glass 		if (info->flash_id == FLASH_UNKNOWN)
3332e192b24SSimon Glass 			goto next_bank;
3342e192b24SSimon Glass 		for (j = 0; j < info->sector_count; ++j) {
3352e192b24SSimon Glass 
3362e192b24SSimon Glass 			hdr = (void *)info->start[j];
3372e192b24SSimon Glass 			if (!hdr)
3382e192b24SSimon Glass 				goto next_sector;
3392e192b24SSimon Glass 
3402e192b24SSimon Glass 			switch (genimg_get_format(hdr)) {
3412e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
3422e192b24SSimon Glass 			case IMAGE_FORMAT_LEGACY:
3432e192b24SSimon Glass 				if (!image_check_hcrc(hdr))
3442e192b24SSimon Glass 					goto next_sector;
3452e192b24SSimon Glass 
3462e192b24SSimon Glass 				printf("Legacy Image at %08lX:\n", (ulong)hdr);
3472e192b24SSimon Glass 				image_print_contents(hdr);
3482e192b24SSimon Glass 
3492e192b24SSimon Glass 				puts("   Verifying Checksum ... ");
3502e192b24SSimon Glass 				if (!image_check_dcrc(hdr)) {
3512e192b24SSimon Glass 					puts("Bad Data CRC\n");
3522e192b24SSimon Glass 				} else {
3532e192b24SSimon Glass 					puts("OK\n");
3542e192b24SSimon Glass 				}
3552e192b24SSimon Glass 				break;
3562e192b24SSimon Glass #endif
3572e192b24SSimon Glass #if defined(CONFIG_FIT)
3582e192b24SSimon Glass 			case IMAGE_FORMAT_FIT:
3592e192b24SSimon Glass 				if (!fit_check_format(hdr))
3602e192b24SSimon Glass 					goto next_sector;
3612e192b24SSimon Glass 
3622e192b24SSimon Glass 				printf("FIT Image at %08lX:\n", (ulong)hdr);
3632e192b24SSimon Glass 				fit_print_contents(hdr);
3642e192b24SSimon Glass 				break;
3652e192b24SSimon Glass #endif
3662e192b24SSimon Glass 			default:
3672e192b24SSimon Glass 				goto next_sector;
3682e192b24SSimon Glass 			}
3692e192b24SSimon Glass 
3702e192b24SSimon Glass next_sector:		;
3712e192b24SSimon Glass 		}
3722e192b24SSimon Glass next_bank:	;
3732e192b24SSimon Glass 	}
3742e192b24SSimon Glass 	return 0;
3752e192b24SSimon Glass }
3762e192b24SSimon Glass #endif
3772e192b24SSimon Glass 
3782e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS_NAND)
379151c06ecSScott Wood static int nand_imls_legacyimage(struct mtd_info *mtd, int nand_dev,
380151c06ecSScott Wood 				 loff_t off, size_t len)
3812e192b24SSimon Glass {
3822e192b24SSimon Glass 	void *imgdata;
3832e192b24SSimon Glass 	int ret;
3842e192b24SSimon Glass 
3852e192b24SSimon Glass 	imgdata = malloc(len);
3862e192b24SSimon Glass 	if (!imgdata) {
3872e192b24SSimon Glass 		printf("May be a Legacy Image at NAND device %d offset %08llX:\n",
3882e192b24SSimon Glass 				nand_dev, off);
3892e192b24SSimon Glass 		printf("   Low memory(cannot allocate memory for image)\n");
3902e192b24SSimon Glass 		return -ENOMEM;
3912e192b24SSimon Glass 	}
3922e192b24SSimon Glass 
393151c06ecSScott Wood 	ret = nand_read_skip_bad(mtd, off, &len, imgdata);
3942e192b24SSimon Glass 	if (ret < 0 && ret != -EUCLEAN) {
3952e192b24SSimon Glass 		free(imgdata);
3962e192b24SSimon Glass 		return ret;
3972e192b24SSimon Glass 	}
3982e192b24SSimon Glass 
3992e192b24SSimon Glass 	if (!image_check_hcrc(imgdata)) {
4002e192b24SSimon Glass 		free(imgdata);
4012e192b24SSimon Glass 		return 0;
4022e192b24SSimon Glass 	}
4032e192b24SSimon Glass 
4042e192b24SSimon Glass 	printf("Legacy Image at NAND device %d offset %08llX:\n",
4052e192b24SSimon Glass 			nand_dev, off);
4062e192b24SSimon Glass 	image_print_contents(imgdata);
4072e192b24SSimon Glass 
4082e192b24SSimon Glass 	puts("   Verifying Checksum ... ");
4092e192b24SSimon Glass 	if (!image_check_dcrc(imgdata))
4102e192b24SSimon Glass 		puts("Bad Data CRC\n");
4112e192b24SSimon Glass 	else
4122e192b24SSimon Glass 		puts("OK\n");
4132e192b24SSimon Glass 
4142e192b24SSimon Glass 	free(imgdata);
4152e192b24SSimon Glass 
4162e192b24SSimon Glass 	return 0;
4172e192b24SSimon Glass }
4182e192b24SSimon Glass 
419151c06ecSScott Wood static int nand_imls_fitimage(struct mtd_info *mtd, int nand_dev, loff_t off,
4202e192b24SSimon Glass 			      size_t len)
4212e192b24SSimon Glass {
4222e192b24SSimon Glass 	void *imgdata;
4232e192b24SSimon Glass 	int ret;
4242e192b24SSimon Glass 
4252e192b24SSimon Glass 	imgdata = malloc(len);
4262e192b24SSimon Glass 	if (!imgdata) {
4272e192b24SSimon Glass 		printf("May be a FIT Image at NAND device %d offset %08llX:\n",
4282e192b24SSimon Glass 				nand_dev, off);
4292e192b24SSimon Glass 		printf("   Low memory(cannot allocate memory for image)\n");
4302e192b24SSimon Glass 		return -ENOMEM;
4312e192b24SSimon Glass 	}
4322e192b24SSimon Glass 
433151c06ecSScott Wood 	ret = nand_read_skip_bad(mtd, off, &len, imgdata);
4342e192b24SSimon Glass 	if (ret < 0 && ret != -EUCLEAN) {
4352e192b24SSimon Glass 		free(imgdata);
4362e192b24SSimon Glass 		return ret;
4372e192b24SSimon Glass 	}
4382e192b24SSimon Glass 
4392e192b24SSimon Glass 	if (!fit_check_format(imgdata)) {
4402e192b24SSimon Glass 		free(imgdata);
4412e192b24SSimon Glass 		return 0;
4422e192b24SSimon Glass 	}
4432e192b24SSimon Glass 
4442e192b24SSimon Glass 	printf("FIT Image at NAND device %d offset %08llX:\n", nand_dev, off);
4452e192b24SSimon Glass 
4462e192b24SSimon Glass 	fit_print_contents(imgdata);
4472e192b24SSimon Glass 	free(imgdata);
4482e192b24SSimon Glass 
4492e192b24SSimon Glass 	return 0;
4502e192b24SSimon Glass }
4512e192b24SSimon Glass 
4522e192b24SSimon Glass static int do_imls_nand(void)
4532e192b24SSimon Glass {
454151c06ecSScott Wood 	struct mtd_info *mtd;
4552e192b24SSimon Glass 	int nand_dev = nand_curr_device;
4562e192b24SSimon Glass 	size_t len;
4572e192b24SSimon Glass 	loff_t off;
4582e192b24SSimon Glass 	u32 buffer[16];
4592e192b24SSimon Glass 
4602e192b24SSimon Glass 	if (nand_dev < 0 || nand_dev >= CONFIG_SYS_MAX_NAND_DEVICE) {
4612e192b24SSimon Glass 		puts("\nNo NAND devices available\n");
4622e192b24SSimon Glass 		return -ENODEV;
4632e192b24SSimon Glass 	}
4642e192b24SSimon Glass 
4652e192b24SSimon Glass 	printf("\n");
4662e192b24SSimon Glass 
4672e192b24SSimon Glass 	for (nand_dev = 0; nand_dev < CONFIG_SYS_MAX_NAND_DEVICE; nand_dev++) {
468b616d9b0SScott Wood 		mtd = nand_info[nand_dev];
469151c06ecSScott Wood 		if (!mtd->name || !mtd->size)
4702e192b24SSimon Glass 			continue;
4712e192b24SSimon Glass 
472151c06ecSScott Wood 		for (off = 0; off < mtd->size; off += mtd->erasesize) {
4732e192b24SSimon Glass 			const image_header_t *header;
4742e192b24SSimon Glass 			int ret;
4752e192b24SSimon Glass 
476151c06ecSScott Wood 			if (nand_block_isbad(mtd, off))
4772e192b24SSimon Glass 				continue;
4782e192b24SSimon Glass 
4792e192b24SSimon Glass 			len = sizeof(buffer);
4802e192b24SSimon Glass 
481151c06ecSScott Wood 			ret = nand_read(mtd, off, &len, (u8 *)buffer);
4822e192b24SSimon Glass 			if (ret < 0 && ret != -EUCLEAN) {
4832e192b24SSimon Glass 				printf("NAND read error %d at offset %08llX\n",
4842e192b24SSimon Glass 						ret, off);
4852e192b24SSimon Glass 				continue;
4862e192b24SSimon Glass 			}
4872e192b24SSimon Glass 
4882e192b24SSimon Glass 			switch (genimg_get_format(buffer)) {
4892e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
4902e192b24SSimon Glass 			case IMAGE_FORMAT_LEGACY:
4912e192b24SSimon Glass 				header = (const image_header_t *)buffer;
4922e192b24SSimon Glass 
4932e192b24SSimon Glass 				len = image_get_image_size(header);
494151c06ecSScott Wood 				nand_imls_legacyimage(mtd, nand_dev, off, len);
4952e192b24SSimon Glass 				break;
4962e192b24SSimon Glass #endif
4972e192b24SSimon Glass #if defined(CONFIG_FIT)
4982e192b24SSimon Glass 			case IMAGE_FORMAT_FIT:
4992e192b24SSimon Glass 				len = fit_get_size(buffer);
500151c06ecSScott Wood 				nand_imls_fitimage(mtd, nand_dev, off, len);
5012e192b24SSimon Glass 				break;
5022e192b24SSimon Glass #endif
5032e192b24SSimon Glass 			}
5042e192b24SSimon Glass 		}
5052e192b24SSimon Glass 	}
5062e192b24SSimon Glass 
5072e192b24SSimon Glass 	return 0;
5082e192b24SSimon Glass }
5092e192b24SSimon Glass #endif
5102e192b24SSimon Glass 
5112e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
5122e192b24SSimon Glass static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
5132e192b24SSimon Glass {
5142e192b24SSimon Glass 	int ret_nor = 0, ret_nand = 0;
5152e192b24SSimon Glass 
5162e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS)
5172e192b24SSimon Glass 	ret_nor = do_imls_nor();
5182e192b24SSimon Glass #endif
5192e192b24SSimon Glass 
5202e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS_NAND)
5212e192b24SSimon Glass 	ret_nand = do_imls_nand();
5222e192b24SSimon Glass #endif
5232e192b24SSimon Glass 
5242e192b24SSimon Glass 	if (ret_nor)
5252e192b24SSimon Glass 		return ret_nor;
5262e192b24SSimon Glass 
5272e192b24SSimon Glass 	if (ret_nand)
5282e192b24SSimon Glass 		return ret_nand;
5292e192b24SSimon Glass 
5302e192b24SSimon Glass 	return (0);
5312e192b24SSimon Glass }
5322e192b24SSimon Glass 
5332e192b24SSimon Glass U_BOOT_CMD(
5342e192b24SSimon Glass 	imls,	1,		1,	do_imls,
5352e192b24SSimon Glass 	"list all images found in flash",
5362e192b24SSimon Glass 	"\n"
5372e192b24SSimon Glass 	"    - Prints information about all images found at sector/block\n"
5382e192b24SSimon Glass 	"      boundaries in nor/nand flash."
5392e192b24SSimon Glass );
5402e192b24SSimon Glass #endif
541