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 <lmb.h> 182e192b24SSimon Glass #include <malloc.h> 192e192b24SSimon Glass #include <mapmem.h> 202e192b24SSimon Glass #include <nand.h> 212e192b24SSimon Glass #include <asm/byteorder.h> 222e192b24SSimon Glass #include <linux/compiler.h> 232e192b24SSimon Glass #include <linux/ctype.h> 242e192b24SSimon Glass #include <linux/err.h> 252e192b24SSimon Glass #include <u-boot/zlib.h> 262e192b24SSimon Glass 272e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR; 282e192b24SSimon Glass 292e192b24SSimon Glass #if defined(CONFIG_CMD_IMI) 302e192b24SSimon Glass static int image_info(unsigned long addr); 312e192b24SSimon Glass #endif 322e192b24SSimon Glass 332e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) 342e192b24SSimon Glass #include <flash.h> 352e192b24SSimon Glass #include <mtd/cfi_flash.h> 362e192b24SSimon Glass extern flash_info_t flash_info[]; /* info for FLASH chips */ 372e192b24SSimon Glass #endif 382e192b24SSimon Glass 392e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND) 402e192b24SSimon Glass static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); 412e192b24SSimon Glass #endif 422e192b24SSimon Glass 432e192b24SSimon Glass bootm_headers_t images; /* pointers to os/initrd/fdt images */ 442e192b24SSimon Glass 452e192b24SSimon Glass /* we overload the cmd field with our state machine info instead of a 462e192b24SSimon Glass * function pointer */ 472e192b24SSimon Glass static cmd_tbl_t cmd_bootm_sub[] = { 482e192b24SSimon Glass U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""), 492e192b24SSimon Glass U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""), 502e192b24SSimon Glass #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH 512e192b24SSimon Glass U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""), 522e192b24SSimon Glass #endif 532e192b24SSimon Glass #ifdef CONFIG_OF_LIBFDT 542e192b24SSimon Glass U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""), 552e192b24SSimon Glass #endif 562e192b24SSimon Glass U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""), 572e192b24SSimon Glass U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""), 582e192b24SSimon Glass U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""), 592e192b24SSimon Glass U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""), 602e192b24SSimon Glass U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""), 612e192b24SSimon Glass }; 622e192b24SSimon Glass 632e192b24SSimon Glass static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, 642e192b24SSimon Glass char * const argv[]) 652e192b24SSimon Glass { 662e192b24SSimon Glass int ret = 0; 672e192b24SSimon Glass long state; 682e192b24SSimon Glass cmd_tbl_t *c; 692e192b24SSimon Glass 702e192b24SSimon Glass c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); 712e192b24SSimon Glass argc--; argv++; 722e192b24SSimon Glass 732e192b24SSimon Glass if (c) { 742e192b24SSimon Glass state = (long)c->cmd; 752e192b24SSimon Glass if (state == BOOTM_STATE_START) 762e192b24SSimon Glass state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER; 772e192b24SSimon Glass } else { 782e192b24SSimon Glass /* Unrecognized command */ 792e192b24SSimon Glass return CMD_RET_USAGE; 802e192b24SSimon Glass } 812e192b24SSimon Glass 822e192b24SSimon Glass if (((state & BOOTM_STATE_START) != BOOTM_STATE_START) && 832e192b24SSimon Glass images.state >= state) { 842e192b24SSimon Glass printf("Trying to execute a command out of order\n"); 852e192b24SSimon Glass return CMD_RET_USAGE; 862e192b24SSimon Glass } 872e192b24SSimon Glass 882e192b24SSimon Glass ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0); 892e192b24SSimon Glass 902e192b24SSimon Glass return ret; 912e192b24SSimon Glass } 922e192b24SSimon Glass 932e192b24SSimon Glass /*******************************************************************/ 942e192b24SSimon Glass /* bootm - boot application image from image in memory */ 952e192b24SSimon Glass /*******************************************************************/ 962e192b24SSimon Glass 972e192b24SSimon Glass int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 982e192b24SSimon Glass { 992e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC 1002e192b24SSimon Glass static int relocated = 0; 1012e192b24SSimon Glass 1022e192b24SSimon Glass if (!relocated) { 1032e192b24SSimon Glass int i; 1042e192b24SSimon Glass 1052e192b24SSimon Glass /* relocate names of sub-command table */ 1062e192b24SSimon Glass for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++) 1072e192b24SSimon Glass cmd_bootm_sub[i].name += gd->reloc_off; 1082e192b24SSimon Glass 1092e192b24SSimon Glass relocated = 1; 1102e192b24SSimon Glass } 1112e192b24SSimon Glass #endif 1122e192b24SSimon Glass 1132e192b24SSimon Glass /* determine if we have a sub command */ 1142e192b24SSimon Glass argc--; argv++; 1152e192b24SSimon Glass if (argc > 0) { 1162e192b24SSimon Glass char *endp; 1172e192b24SSimon Glass 1182e192b24SSimon Glass simple_strtoul(argv[0], &endp, 16); 1192e192b24SSimon Glass /* endp pointing to NULL means that argv[0] was just a 1202e192b24SSimon Glass * valid number, pass it along to the normal bootm processing 1212e192b24SSimon Glass * 1222e192b24SSimon Glass * If endp is ':' or '#' assume a FIT identifier so pass 1232e192b24SSimon Glass * along for normal processing. 1242e192b24SSimon Glass * 1252e192b24SSimon Glass * Right now we assume the first arg should never be '-' 1262e192b24SSimon Glass */ 1272e192b24SSimon Glass if ((*endp != 0) && (*endp != ':') && (*endp != '#')) 1282e192b24SSimon Glass return do_bootm_subcommand(cmdtp, flag, argc, argv); 1292e192b24SSimon Glass } 1302e192b24SSimon Glass 1312e192b24SSimon Glass return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START | 1322e192b24SSimon Glass BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER | 1332e192b24SSimon Glass BOOTM_STATE_LOADOS | 1342e192b24SSimon Glass #if defined(CONFIG_PPC) || defined(CONFIG_MIPS) 1352e192b24SSimon Glass BOOTM_STATE_OS_CMDLINE | 1362e192b24SSimon Glass #endif 1372e192b24SSimon Glass BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | 1382e192b24SSimon Glass BOOTM_STATE_OS_GO, &images, 1); 1392e192b24SSimon Glass } 1402e192b24SSimon Glass 1412e192b24SSimon Glass int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) 1422e192b24SSimon Glass { 1432e192b24SSimon Glass const char *ep = getenv("autostart"); 1442e192b24SSimon Glass 1452e192b24SSimon Glass if (ep && !strcmp(ep, "yes")) { 1462e192b24SSimon Glass char *local_args[2]; 1472e192b24SSimon Glass local_args[0] = (char *)cmd; 1482e192b24SSimon Glass local_args[1] = NULL; 1492e192b24SSimon Glass printf("Automatic boot of image at addr 0x%08lX ...\n", load_addr); 1502e192b24SSimon Glass return do_bootm(cmdtp, 0, 1, local_args); 1512e192b24SSimon Glass } 1522e192b24SSimon Glass 1532e192b24SSimon Glass return 0; 1542e192b24SSimon Glass } 1552e192b24SSimon Glass 1562e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP 1572e192b24SSimon Glass static char bootm_help_text[] = 1582e192b24SSimon Glass "[addr [arg ...]]\n - boot application image stored in memory\n" 1592e192b24SSimon Glass "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" 1602e192b24SSimon Glass "\t'arg' can be the address of an initrd image\n" 1612e192b24SSimon Glass #if defined(CONFIG_OF_LIBFDT) 1622e192b24SSimon Glass "\tWhen booting a Linux kernel which requires a flat device-tree\n" 1632e192b24SSimon Glass "\ta third argument is required which is the address of the\n" 1642e192b24SSimon Glass "\tdevice-tree blob. To boot that kernel without an initrd image,\n" 1652e192b24SSimon Glass "\tuse a '-' for the second argument. If you do not pass a third\n" 1662e192b24SSimon Glass "\ta bd_info struct will be passed instead\n" 1672e192b24SSimon Glass #endif 1682e192b24SSimon Glass #if defined(CONFIG_FIT) 1692e192b24SSimon Glass "\t\nFor the new multi component uImage format (FIT) addresses\n" 1702e192b24SSimon Glass "\tmust be extened to include component or configuration unit name:\n" 1712e192b24SSimon Glass "\taddr:<subimg_uname> - direct component image specification\n" 1722e192b24SSimon Glass "\taddr#<conf_uname> - configuration specification\n" 1732e192b24SSimon Glass "\tUse iminfo command to get the list of existing component\n" 1742e192b24SSimon Glass "\timages and configurations.\n" 1752e192b24SSimon Glass #endif 1762e192b24SSimon Glass "\nSub-commands to do part of the bootm sequence. The sub-commands " 1772e192b24SSimon Glass "must be\n" 1782e192b24SSimon Glass "issued in the order below (it's ok to not issue all sub-commands):\n" 1792e192b24SSimon Glass "\tstart [addr [arg ...]]\n" 1802e192b24SSimon Glass "\tloados - load OS image\n" 1812e192b24SSimon Glass #if defined(CONFIG_SYS_BOOT_RAMDISK_HIGH) 1822e192b24SSimon Glass "\tramdisk - relocate initrd, set env initrd_start/initrd_end\n" 1832e192b24SSimon Glass #endif 1842e192b24SSimon Glass #if defined(CONFIG_OF_LIBFDT) 1852e192b24SSimon Glass "\tfdt - relocate flat device tree\n" 1862e192b24SSimon Glass #endif 1872e192b24SSimon Glass "\tcmdline - OS specific command line processing/setup\n" 1882e192b24SSimon Glass "\tbdt - OS specific bd_t processing\n" 1892e192b24SSimon Glass "\tprep - OS specific prep before relocation or go\n" 1902e192b24SSimon Glass #if defined(CONFIG_TRACE) 1912e192b24SSimon Glass "\tfake - OS specific fake start without go\n" 1922e192b24SSimon Glass #endif 1932e192b24SSimon Glass "\tgo - start OS"; 1942e192b24SSimon Glass #endif 1952e192b24SSimon Glass 1962e192b24SSimon Glass U_BOOT_CMD( 1972e192b24SSimon Glass bootm, CONFIG_SYS_MAXARGS, 1, do_bootm, 1982e192b24SSimon Glass "boot application image from memory", bootm_help_text 1992e192b24SSimon Glass ); 2002e192b24SSimon Glass 2012e192b24SSimon Glass /*******************************************************************/ 2022e192b24SSimon Glass /* bootd - boot default image */ 2032e192b24SSimon Glass /*******************************************************************/ 2042e192b24SSimon Glass #if defined(CONFIG_CMD_BOOTD) 2052e192b24SSimon Glass int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2062e192b24SSimon Glass { 2072e192b24SSimon Glass return run_command(getenv("bootcmd"), flag); 2082e192b24SSimon Glass } 2092e192b24SSimon Glass 2102e192b24SSimon Glass U_BOOT_CMD( 2112e192b24SSimon Glass boot, 1, 1, do_bootd, 2122e192b24SSimon Glass "boot default, i.e., run 'bootcmd'", 2132e192b24SSimon Glass "" 2142e192b24SSimon Glass ); 2152e192b24SSimon Glass 2162e192b24SSimon Glass /* keep old command name "bootd" for backward compatibility */ 2172e192b24SSimon Glass U_BOOT_CMD( 2182e192b24SSimon Glass bootd, 1, 1, do_bootd, 2192e192b24SSimon Glass "boot default, i.e., run 'bootcmd'", 2202e192b24SSimon Glass "" 2212e192b24SSimon Glass ); 2222e192b24SSimon Glass 2232e192b24SSimon Glass #endif 2242e192b24SSimon Glass 2252e192b24SSimon Glass 2262e192b24SSimon Glass /*******************************************************************/ 2272e192b24SSimon Glass /* iminfo - print header info for a requested image */ 2282e192b24SSimon Glass /*******************************************************************/ 2292e192b24SSimon Glass #if defined(CONFIG_CMD_IMI) 2302e192b24SSimon Glass static int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2312e192b24SSimon Glass { 2322e192b24SSimon Glass int arg; 2332e192b24SSimon Glass ulong addr; 2342e192b24SSimon Glass int rcode = 0; 2352e192b24SSimon Glass 2362e192b24SSimon Glass if (argc < 2) { 2372e192b24SSimon Glass return image_info(load_addr); 2382e192b24SSimon Glass } 2392e192b24SSimon Glass 2402e192b24SSimon Glass for (arg = 1; arg < argc; ++arg) { 2412e192b24SSimon Glass addr = simple_strtoul(argv[arg], NULL, 16); 2422e192b24SSimon Glass if (image_info(addr) != 0) 2432e192b24SSimon Glass rcode = 1; 2442e192b24SSimon Glass } 2452e192b24SSimon Glass return rcode; 2462e192b24SSimon Glass } 2472e192b24SSimon Glass 2482e192b24SSimon Glass static int image_info(ulong addr) 2492e192b24SSimon Glass { 2502e192b24SSimon Glass void *hdr = (void *)addr; 2512e192b24SSimon Glass 2522e192b24SSimon Glass printf("\n## Checking Image at %08lx ...\n", addr); 2532e192b24SSimon Glass 2542e192b24SSimon Glass switch (genimg_get_format(hdr)) { 2552e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY) 2562e192b24SSimon Glass case IMAGE_FORMAT_LEGACY: 2572e192b24SSimon Glass puts(" Legacy image found\n"); 2582e192b24SSimon Glass if (!image_check_magic(hdr)) { 2592e192b24SSimon Glass puts(" Bad Magic Number\n"); 2602e192b24SSimon Glass return 1; 2612e192b24SSimon Glass } 2622e192b24SSimon Glass 2632e192b24SSimon Glass if (!image_check_hcrc(hdr)) { 2642e192b24SSimon Glass puts(" Bad Header Checksum\n"); 2652e192b24SSimon Glass return 1; 2662e192b24SSimon Glass } 2672e192b24SSimon Glass 2682e192b24SSimon Glass image_print_contents(hdr); 2692e192b24SSimon Glass 2702e192b24SSimon Glass puts(" Verifying Checksum ... "); 2712e192b24SSimon Glass if (!image_check_dcrc(hdr)) { 2722e192b24SSimon Glass puts(" Bad Data CRC\n"); 2732e192b24SSimon Glass return 1; 2742e192b24SSimon Glass } 2752e192b24SSimon Glass puts("OK\n"); 2762e192b24SSimon Glass return 0; 2772e192b24SSimon Glass #endif 278*4f1318b2SMichael Trimarchi #if defined(CONFIG_ANDROID_BOOT_IMAGE) 279*4f1318b2SMichael Trimarchi case IMAGE_FORMAT_ANDROID: 280*4f1318b2SMichael Trimarchi puts(" Android image found\n"); 281*4f1318b2SMichael Trimarchi android_print_contents(hdr); 282*4f1318b2SMichael Trimarchi return 0; 283*4f1318b2SMichael Trimarchi #endif 2842e192b24SSimon Glass #if defined(CONFIG_FIT) 2852e192b24SSimon Glass case IMAGE_FORMAT_FIT: 2862e192b24SSimon Glass puts(" FIT image found\n"); 2872e192b24SSimon Glass 2882e192b24SSimon Glass if (!fit_check_format(hdr)) { 2892e192b24SSimon Glass puts("Bad FIT image format!\n"); 2902e192b24SSimon Glass return 1; 2912e192b24SSimon Glass } 2922e192b24SSimon Glass 2932e192b24SSimon Glass fit_print_contents(hdr); 2942e192b24SSimon Glass 2952e192b24SSimon Glass if (!fit_all_image_verify(hdr)) { 2962e192b24SSimon Glass puts("Bad hash in FIT image!\n"); 2972e192b24SSimon Glass return 1; 2982e192b24SSimon Glass } 2992e192b24SSimon Glass 3002e192b24SSimon Glass return 0; 3012e192b24SSimon Glass #endif 3022e192b24SSimon Glass default: 3032e192b24SSimon Glass puts("Unknown image format!\n"); 3042e192b24SSimon Glass break; 3052e192b24SSimon Glass } 3062e192b24SSimon Glass 3072e192b24SSimon Glass return 1; 3082e192b24SSimon Glass } 3092e192b24SSimon Glass 3102e192b24SSimon Glass U_BOOT_CMD( 3112e192b24SSimon Glass iminfo, CONFIG_SYS_MAXARGS, 1, do_iminfo, 3122e192b24SSimon Glass "print header information for application image", 3132e192b24SSimon Glass "addr [addr ...]\n" 3142e192b24SSimon Glass " - print header information for application image starting at\n" 3152e192b24SSimon Glass " address 'addr' in memory; this includes verification of the\n" 3162e192b24SSimon Glass " image contents (magic number, header and payload checksums)" 3172e192b24SSimon Glass ); 3182e192b24SSimon Glass #endif 3192e192b24SSimon Glass 3202e192b24SSimon Glass 3212e192b24SSimon Glass /*******************************************************************/ 3222e192b24SSimon Glass /* imls - list all images found in flash */ 3232e192b24SSimon Glass /*******************************************************************/ 3242e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) 3252e192b24SSimon Glass static int do_imls_nor(void) 3262e192b24SSimon Glass { 3272e192b24SSimon Glass flash_info_t *info; 3282e192b24SSimon Glass int i, j; 3292e192b24SSimon Glass void *hdr; 3302e192b24SSimon Glass 3312e192b24SSimon Glass for (i = 0, info = &flash_info[0]; 3322e192b24SSimon Glass i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) { 3332e192b24SSimon Glass 3342e192b24SSimon Glass if (info->flash_id == FLASH_UNKNOWN) 3352e192b24SSimon Glass goto next_bank; 3362e192b24SSimon Glass for (j = 0; j < info->sector_count; ++j) { 3372e192b24SSimon Glass 3382e192b24SSimon Glass hdr = (void *)info->start[j]; 3392e192b24SSimon Glass if (!hdr) 3402e192b24SSimon Glass goto next_sector; 3412e192b24SSimon Glass 3422e192b24SSimon Glass switch (genimg_get_format(hdr)) { 3432e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY) 3442e192b24SSimon Glass case IMAGE_FORMAT_LEGACY: 3452e192b24SSimon Glass if (!image_check_hcrc(hdr)) 3462e192b24SSimon Glass goto next_sector; 3472e192b24SSimon Glass 3482e192b24SSimon Glass printf("Legacy Image at %08lX:\n", (ulong)hdr); 3492e192b24SSimon Glass image_print_contents(hdr); 3502e192b24SSimon Glass 3512e192b24SSimon Glass puts(" Verifying Checksum ... "); 3522e192b24SSimon Glass if (!image_check_dcrc(hdr)) { 3532e192b24SSimon Glass puts("Bad Data CRC\n"); 3542e192b24SSimon Glass } else { 3552e192b24SSimon Glass puts("OK\n"); 3562e192b24SSimon Glass } 3572e192b24SSimon Glass break; 3582e192b24SSimon Glass #endif 3592e192b24SSimon Glass #if defined(CONFIG_FIT) 3602e192b24SSimon Glass case IMAGE_FORMAT_FIT: 3612e192b24SSimon Glass if (!fit_check_format(hdr)) 3622e192b24SSimon Glass goto next_sector; 3632e192b24SSimon Glass 3642e192b24SSimon Glass printf("FIT Image at %08lX:\n", (ulong)hdr); 3652e192b24SSimon Glass fit_print_contents(hdr); 3662e192b24SSimon Glass break; 3672e192b24SSimon Glass #endif 3682e192b24SSimon Glass default: 3692e192b24SSimon Glass goto next_sector; 3702e192b24SSimon Glass } 3712e192b24SSimon Glass 3722e192b24SSimon Glass next_sector: ; 3732e192b24SSimon Glass } 3742e192b24SSimon Glass next_bank: ; 3752e192b24SSimon Glass } 3762e192b24SSimon Glass return 0; 3772e192b24SSimon Glass } 3782e192b24SSimon Glass #endif 3792e192b24SSimon Glass 3802e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS_NAND) 381151c06ecSScott Wood static int nand_imls_legacyimage(struct mtd_info *mtd, int nand_dev, 382151c06ecSScott Wood loff_t off, size_t len) 3832e192b24SSimon Glass { 3842e192b24SSimon Glass void *imgdata; 3852e192b24SSimon Glass int ret; 3862e192b24SSimon Glass 3872e192b24SSimon Glass imgdata = malloc(len); 3882e192b24SSimon Glass if (!imgdata) { 3892e192b24SSimon Glass printf("May be a Legacy Image at NAND device %d offset %08llX:\n", 3902e192b24SSimon Glass nand_dev, off); 3912e192b24SSimon Glass printf(" Low memory(cannot allocate memory for image)\n"); 3922e192b24SSimon Glass return -ENOMEM; 3932e192b24SSimon Glass } 3942e192b24SSimon Glass 395151c06ecSScott Wood ret = nand_read_skip_bad(mtd, off, &len, imgdata); 3962e192b24SSimon Glass if (ret < 0 && ret != -EUCLEAN) { 3972e192b24SSimon Glass free(imgdata); 3982e192b24SSimon Glass return ret; 3992e192b24SSimon Glass } 4002e192b24SSimon Glass 4012e192b24SSimon Glass if (!image_check_hcrc(imgdata)) { 4022e192b24SSimon Glass free(imgdata); 4032e192b24SSimon Glass return 0; 4042e192b24SSimon Glass } 4052e192b24SSimon Glass 4062e192b24SSimon Glass printf("Legacy Image at NAND device %d offset %08llX:\n", 4072e192b24SSimon Glass nand_dev, off); 4082e192b24SSimon Glass image_print_contents(imgdata); 4092e192b24SSimon Glass 4102e192b24SSimon Glass puts(" Verifying Checksum ... "); 4112e192b24SSimon Glass if (!image_check_dcrc(imgdata)) 4122e192b24SSimon Glass puts("Bad Data CRC\n"); 4132e192b24SSimon Glass else 4142e192b24SSimon Glass puts("OK\n"); 4152e192b24SSimon Glass 4162e192b24SSimon Glass free(imgdata); 4172e192b24SSimon Glass 4182e192b24SSimon Glass return 0; 4192e192b24SSimon Glass } 4202e192b24SSimon Glass 421151c06ecSScott Wood static int nand_imls_fitimage(struct mtd_info *mtd, int nand_dev, loff_t off, 4222e192b24SSimon Glass size_t len) 4232e192b24SSimon Glass { 4242e192b24SSimon Glass void *imgdata; 4252e192b24SSimon Glass int ret; 4262e192b24SSimon Glass 4272e192b24SSimon Glass imgdata = malloc(len); 4282e192b24SSimon Glass if (!imgdata) { 4292e192b24SSimon Glass printf("May be a FIT Image at NAND device %d offset %08llX:\n", 4302e192b24SSimon Glass nand_dev, off); 4312e192b24SSimon Glass printf(" Low memory(cannot allocate memory for image)\n"); 4322e192b24SSimon Glass return -ENOMEM; 4332e192b24SSimon Glass } 4342e192b24SSimon Glass 435151c06ecSScott Wood ret = nand_read_skip_bad(mtd, off, &len, imgdata); 4362e192b24SSimon Glass if (ret < 0 && ret != -EUCLEAN) { 4372e192b24SSimon Glass free(imgdata); 4382e192b24SSimon Glass return ret; 4392e192b24SSimon Glass } 4402e192b24SSimon Glass 4412e192b24SSimon Glass if (!fit_check_format(imgdata)) { 4422e192b24SSimon Glass free(imgdata); 4432e192b24SSimon Glass return 0; 4442e192b24SSimon Glass } 4452e192b24SSimon Glass 4462e192b24SSimon Glass printf("FIT Image at NAND device %d offset %08llX:\n", nand_dev, off); 4472e192b24SSimon Glass 4482e192b24SSimon Glass fit_print_contents(imgdata); 4492e192b24SSimon Glass free(imgdata); 4502e192b24SSimon Glass 4512e192b24SSimon Glass return 0; 4522e192b24SSimon Glass } 4532e192b24SSimon Glass 4542e192b24SSimon Glass static int do_imls_nand(void) 4552e192b24SSimon Glass { 456151c06ecSScott Wood struct mtd_info *mtd; 4572e192b24SSimon Glass int nand_dev = nand_curr_device; 4582e192b24SSimon Glass size_t len; 4592e192b24SSimon Glass loff_t off; 4602e192b24SSimon Glass u32 buffer[16]; 4612e192b24SSimon Glass 4622e192b24SSimon Glass if (nand_dev < 0 || nand_dev >= CONFIG_SYS_MAX_NAND_DEVICE) { 4632e192b24SSimon Glass puts("\nNo NAND devices available\n"); 4642e192b24SSimon Glass return -ENODEV; 4652e192b24SSimon Glass } 4662e192b24SSimon Glass 4672e192b24SSimon Glass printf("\n"); 4682e192b24SSimon Glass 4692e192b24SSimon Glass for (nand_dev = 0; nand_dev < CONFIG_SYS_MAX_NAND_DEVICE; nand_dev++) { 470b616d9b0SScott Wood mtd = nand_info[nand_dev]; 471151c06ecSScott Wood if (!mtd->name || !mtd->size) 4722e192b24SSimon Glass continue; 4732e192b24SSimon Glass 474151c06ecSScott Wood for (off = 0; off < mtd->size; off += mtd->erasesize) { 4752e192b24SSimon Glass const image_header_t *header; 4762e192b24SSimon Glass int ret; 4772e192b24SSimon Glass 478151c06ecSScott Wood if (nand_block_isbad(mtd, off)) 4792e192b24SSimon Glass continue; 4802e192b24SSimon Glass 4812e192b24SSimon Glass len = sizeof(buffer); 4822e192b24SSimon Glass 483151c06ecSScott Wood ret = nand_read(mtd, off, &len, (u8 *)buffer); 4842e192b24SSimon Glass if (ret < 0 && ret != -EUCLEAN) { 4852e192b24SSimon Glass printf("NAND read error %d at offset %08llX\n", 4862e192b24SSimon Glass ret, off); 4872e192b24SSimon Glass continue; 4882e192b24SSimon Glass } 4892e192b24SSimon Glass 4902e192b24SSimon Glass switch (genimg_get_format(buffer)) { 4912e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY) 4922e192b24SSimon Glass case IMAGE_FORMAT_LEGACY: 4932e192b24SSimon Glass header = (const image_header_t *)buffer; 4942e192b24SSimon Glass 4952e192b24SSimon Glass len = image_get_image_size(header); 496151c06ecSScott Wood nand_imls_legacyimage(mtd, nand_dev, off, len); 4972e192b24SSimon Glass break; 4982e192b24SSimon Glass #endif 4992e192b24SSimon Glass #if defined(CONFIG_FIT) 5002e192b24SSimon Glass case IMAGE_FORMAT_FIT: 5012e192b24SSimon Glass len = fit_get_size(buffer); 502151c06ecSScott Wood nand_imls_fitimage(mtd, nand_dev, off, len); 5032e192b24SSimon Glass break; 5042e192b24SSimon Glass #endif 5052e192b24SSimon Glass } 5062e192b24SSimon Glass } 5072e192b24SSimon Glass } 5082e192b24SSimon Glass 5092e192b24SSimon Glass return 0; 5102e192b24SSimon Glass } 5112e192b24SSimon Glass #endif 5122e192b24SSimon Glass 5132e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND) 5142e192b24SSimon Glass static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 5152e192b24SSimon Glass { 5162e192b24SSimon Glass int ret_nor = 0, ret_nand = 0; 5172e192b24SSimon Glass 5182e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS) 5192e192b24SSimon Glass ret_nor = do_imls_nor(); 5202e192b24SSimon Glass #endif 5212e192b24SSimon Glass 5222e192b24SSimon Glass #if defined(CONFIG_CMD_IMLS_NAND) 5232e192b24SSimon Glass ret_nand = do_imls_nand(); 5242e192b24SSimon Glass #endif 5252e192b24SSimon Glass 5262e192b24SSimon Glass if (ret_nor) 5272e192b24SSimon Glass return ret_nor; 5282e192b24SSimon Glass 5292e192b24SSimon Glass if (ret_nand) 5302e192b24SSimon Glass return ret_nand; 5312e192b24SSimon Glass 5322e192b24SSimon Glass return (0); 5332e192b24SSimon Glass } 5342e192b24SSimon Glass 5352e192b24SSimon Glass U_BOOT_CMD( 5362e192b24SSimon Glass imls, 1, 1, do_imls, 5372e192b24SSimon Glass "list all images found in flash", 5382e192b24SSimon Glass "\n" 5392e192b24SSimon Glass " - Prints information about all images found at sector/block\n" 5402e192b24SSimon Glass " boundaries in nor/nand flash." 5412e192b24SSimon Glass ); 5422e192b24SSimon Glass #endif 5432e192b24SSimon Glass 5442e192b24SSimon Glass #ifdef CONFIG_CMD_BOOTZ 5452e192b24SSimon Glass 5462e192b24SSimon Glass int __weak bootz_setup(ulong image, ulong *start, ulong *end) 5472e192b24SSimon Glass { 5482e192b24SSimon Glass /* Please define bootz_setup() for your platform */ 5492e192b24SSimon Glass 5502e192b24SSimon Glass puts("Your platform's zImage format isn't supported yet!\n"); 5512e192b24SSimon Glass return -1; 5522e192b24SSimon Glass } 5532e192b24SSimon Glass 5542e192b24SSimon Glass /* 5552e192b24SSimon Glass * zImage booting support 5562e192b24SSimon Glass */ 5572e192b24SSimon Glass static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc, 5582e192b24SSimon Glass char * const argv[], bootm_headers_t *images) 5592e192b24SSimon Glass { 5602e192b24SSimon Glass int ret; 5612e192b24SSimon Glass ulong zi_start, zi_end; 5622e192b24SSimon Glass 5632e192b24SSimon Glass ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, 5642e192b24SSimon Glass images, 1); 5652e192b24SSimon Glass 5662e192b24SSimon Glass /* Setup Linux kernel zImage entry point */ 5672e192b24SSimon Glass if (!argc) { 5682e192b24SSimon Glass images->ep = load_addr; 5692e192b24SSimon Glass debug("* kernel: default image load address = 0x%08lx\n", 5702e192b24SSimon Glass load_addr); 5712e192b24SSimon Glass } else { 5722e192b24SSimon Glass images->ep = simple_strtoul(argv[0], NULL, 16); 5732e192b24SSimon Glass debug("* kernel: cmdline image address = 0x%08lx\n", 5742e192b24SSimon Glass images->ep); 5752e192b24SSimon Glass } 5762e192b24SSimon Glass 5772e192b24SSimon Glass ret = bootz_setup(images->ep, &zi_start, &zi_end); 5782e192b24SSimon Glass if (ret != 0) 5792e192b24SSimon Glass return 1; 5802e192b24SSimon Glass 5812e192b24SSimon Glass lmb_reserve(&images->lmb, images->ep, zi_end - zi_start); 5822e192b24SSimon Glass 5832e192b24SSimon Glass /* 5842e192b24SSimon Glass * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not 5852e192b24SSimon Glass * have a header that provide this informaiton. 5862e192b24SSimon Glass */ 5872e192b24SSimon Glass if (bootm_find_images(flag, argc, argv)) 5882e192b24SSimon Glass return 1; 5892e192b24SSimon Glass 5902e192b24SSimon Glass return 0; 5912e192b24SSimon Glass } 5922e192b24SSimon Glass 5932e192b24SSimon Glass int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 5942e192b24SSimon Glass { 5952e192b24SSimon Glass int ret; 5962e192b24SSimon Glass 5972e192b24SSimon Glass /* Consume 'bootz' */ 5982e192b24SSimon Glass argc--; argv++; 5992e192b24SSimon Glass 6002e192b24SSimon Glass if (bootz_start(cmdtp, flag, argc, argv, &images)) 6012e192b24SSimon Glass return 1; 6022e192b24SSimon Glass 6032e192b24SSimon Glass /* 6042e192b24SSimon Glass * We are doing the BOOTM_STATE_LOADOS state ourselves, so must 6052e192b24SSimon Glass * disable interrupts ourselves 6062e192b24SSimon Glass */ 6072e192b24SSimon Glass bootm_disable_interrupts(); 6082e192b24SSimon Glass 6092e192b24SSimon Glass images.os.os = IH_OS_LINUX; 6102e192b24SSimon Glass ret = do_bootm_states(cmdtp, flag, argc, argv, 6112e192b24SSimon Glass BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | 6122e192b24SSimon Glass BOOTM_STATE_OS_GO, 6132e192b24SSimon Glass &images, 1); 6142e192b24SSimon Glass 6152e192b24SSimon Glass return ret; 6162e192b24SSimon Glass } 6172e192b24SSimon Glass 6182e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP 6192e192b24SSimon Glass static char bootz_help_text[] = 6202e192b24SSimon Glass "[addr [initrd[:size]] [fdt]]\n" 6212e192b24SSimon Glass " - boot Linux zImage stored in memory\n" 6222e192b24SSimon Glass "\tThe argument 'initrd' is optional and specifies the address\n" 6232e192b24SSimon Glass "\tof the initrd in memory. The optional argument ':size' allows\n" 6242e192b24SSimon Glass "\tspecifying the size of RAW initrd.\n" 6252e192b24SSimon Glass #if defined(CONFIG_OF_LIBFDT) 6262e192b24SSimon Glass "\tWhen booting a Linux kernel which requires a flat device-tree\n" 6272e192b24SSimon Glass "\ta third argument is required which is the address of the\n" 6282e192b24SSimon Glass "\tdevice-tree blob. To boot that kernel without an initrd image,\n" 6292e192b24SSimon Glass "\tuse a '-' for the second argument. If you do not pass a third\n" 6302e192b24SSimon Glass "\ta bd_info struct will be passed instead\n" 6312e192b24SSimon Glass #endif 6322e192b24SSimon Glass ""; 6332e192b24SSimon Glass #endif 6342e192b24SSimon Glass 6352e192b24SSimon Glass U_BOOT_CMD( 6362e192b24SSimon Glass bootz, CONFIG_SYS_MAXARGS, 1, do_bootz, 6372e192b24SSimon Glass "boot Linux zImage image from memory", bootz_help_text 6382e192b24SSimon Glass ); 6392e192b24SSimon Glass #endif /* CONFIG_CMD_BOOTZ */ 6402e192b24SSimon Glass 6412e192b24SSimon Glass #ifdef CONFIG_CMD_BOOTI 6422e192b24SSimon Glass /* See Documentation/arm64/booting.txt in the Linux kernel */ 6432e192b24SSimon Glass struct Image_header { 6442e192b24SSimon Glass uint32_t code0; /* Executable code */ 6452e192b24SSimon Glass uint32_t code1; /* Executable code */ 6462e192b24SSimon Glass uint64_t text_offset; /* Image load offset, LE */ 6472e192b24SSimon Glass uint64_t image_size; /* Effective Image size, LE */ 6482e192b24SSimon Glass uint64_t res1; /* reserved */ 6492e192b24SSimon Glass uint64_t res2; /* reserved */ 6502e192b24SSimon Glass uint64_t res3; /* reserved */ 6512e192b24SSimon Glass uint64_t res4; /* reserved */ 6522e192b24SSimon Glass uint32_t magic; /* Magic number */ 6532e192b24SSimon Glass uint32_t res5; 6542e192b24SSimon Glass }; 6552e192b24SSimon Glass 6562e192b24SSimon Glass #define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 6572e192b24SSimon Glass 6582e192b24SSimon Glass static int booti_setup(bootm_headers_t *images) 6592e192b24SSimon Glass { 6602e192b24SSimon Glass struct Image_header *ih; 6612e192b24SSimon Glass uint64_t dst; 662f9a90aceSAndre Przywara uint64_t image_size; 6632e192b24SSimon Glass 6642e192b24SSimon Glass ih = (struct Image_header *)map_sysmem(images->ep, 0); 6652e192b24SSimon Glass 6662e192b24SSimon Glass if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) { 6672e192b24SSimon Glass puts("Bad Linux ARM64 Image magic!\n"); 6682e192b24SSimon Glass return 1; 6692e192b24SSimon Glass } 6702e192b24SSimon Glass 6712e192b24SSimon Glass if (ih->image_size == 0) { 6722e192b24SSimon Glass puts("Image lacks image_size field, assuming 16MiB\n"); 673f9a90aceSAndre Przywara image_size = 16 << 20; 674f9a90aceSAndre Przywara } else { 675f9a90aceSAndre Przywara image_size = le64_to_cpu(ih->image_size); 6762e192b24SSimon Glass } 6772e192b24SSimon Glass 6782e192b24SSimon Glass /* 6792e192b24SSimon Glass * If we are not at the correct run-time location, set the new 6802e192b24SSimon Glass * correct location and then move the image there. 6812e192b24SSimon Glass */ 682f9a90aceSAndre Przywara dst = gd->bd->bi_dram[0].start + le64_to_cpu(ih->text_offset); 68362022d52SMasahiro Yamada 68462022d52SMasahiro Yamada unmap_sysmem(ih); 68562022d52SMasahiro Yamada 6862e192b24SSimon Glass if (images->ep != dst) { 6872e192b24SSimon Glass void *src; 6882e192b24SSimon Glass 6892e192b24SSimon Glass debug("Moving Image from 0x%lx to 0x%llx\n", images->ep, dst); 6902e192b24SSimon Glass 6912e192b24SSimon Glass src = (void *)images->ep; 6922e192b24SSimon Glass images->ep = dst; 693f9a90aceSAndre Przywara memmove((void *)dst, src, image_size); 6942e192b24SSimon Glass } 6952e192b24SSimon Glass 6962e192b24SSimon Glass return 0; 6972e192b24SSimon Glass } 6982e192b24SSimon Glass 6992e192b24SSimon Glass /* 7002e192b24SSimon Glass * Image booting support 7012e192b24SSimon Glass */ 7022e192b24SSimon Glass static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc, 7032e192b24SSimon Glass char * const argv[], bootm_headers_t *images) 7042e192b24SSimon Glass { 7052e192b24SSimon Glass int ret; 7062e192b24SSimon Glass struct Image_header *ih; 7072e192b24SSimon Glass 7082e192b24SSimon Glass ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, 7092e192b24SSimon Glass images, 1); 7102e192b24SSimon Glass 7112e192b24SSimon Glass /* Setup Linux kernel Image entry point */ 7122e192b24SSimon Glass if (!argc) { 7132e192b24SSimon Glass images->ep = load_addr; 7142e192b24SSimon Glass debug("* kernel: default image load address = 0x%08lx\n", 7152e192b24SSimon Glass load_addr); 7162e192b24SSimon Glass } else { 7172e192b24SSimon Glass images->ep = simple_strtoul(argv[0], NULL, 16); 7182e192b24SSimon Glass debug("* kernel: cmdline image address = 0x%08lx\n", 7192e192b24SSimon Glass images->ep); 7202e192b24SSimon Glass } 7212e192b24SSimon Glass 7222e192b24SSimon Glass ret = booti_setup(images); 7232e192b24SSimon Glass if (ret != 0) 7242e192b24SSimon Glass return 1; 7252e192b24SSimon Glass 7262e192b24SSimon Glass ih = (struct Image_header *)map_sysmem(images->ep, 0); 7272e192b24SSimon Glass 7282e192b24SSimon Glass lmb_reserve(&images->lmb, images->ep, le32_to_cpu(ih->image_size)); 7292e192b24SSimon Glass 73062022d52SMasahiro Yamada unmap_sysmem(ih); 73162022d52SMasahiro Yamada 7322e192b24SSimon Glass /* 7332e192b24SSimon Glass * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not 7342e192b24SSimon Glass * have a header that provide this informaiton. 7352e192b24SSimon Glass */ 7362e192b24SSimon Glass if (bootm_find_images(flag, argc, argv)) 7372e192b24SSimon Glass return 1; 7382e192b24SSimon Glass 7392e192b24SSimon Glass return 0; 7402e192b24SSimon Glass } 7412e192b24SSimon Glass 7422e192b24SSimon Glass int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 7432e192b24SSimon Glass { 7442e192b24SSimon Glass int ret; 7452e192b24SSimon Glass 7462e192b24SSimon Glass /* Consume 'booti' */ 7472e192b24SSimon Glass argc--; argv++; 7482e192b24SSimon Glass 7492e192b24SSimon Glass if (booti_start(cmdtp, flag, argc, argv, &images)) 7502e192b24SSimon Glass return 1; 7512e192b24SSimon Glass 7522e192b24SSimon Glass /* 7532e192b24SSimon Glass * We are doing the BOOTM_STATE_LOADOS state ourselves, so must 7542e192b24SSimon Glass * disable interrupts ourselves 7552e192b24SSimon Glass */ 7562e192b24SSimon Glass bootm_disable_interrupts(); 7572e192b24SSimon Glass 7582e192b24SSimon Glass images.os.os = IH_OS_LINUX; 7592e192b24SSimon Glass ret = do_bootm_states(cmdtp, flag, argc, argv, 7602e192b24SSimon Glass BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | 7612e192b24SSimon Glass BOOTM_STATE_OS_GO, 7622e192b24SSimon Glass &images, 1); 7632e192b24SSimon Glass 7642e192b24SSimon Glass return ret; 7652e192b24SSimon Glass } 7662e192b24SSimon Glass 7672e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP 7682e192b24SSimon Glass static char booti_help_text[] = 7692e192b24SSimon Glass "[addr [initrd[:size]] [fdt]]\n" 7706f6051faSKarsten Merker " - boot arm64 Linux Image stored in memory\n" 7712e192b24SSimon Glass "\tThe argument 'initrd' is optional and specifies the address\n" 7726f6051faSKarsten Merker "\tof an initrd in memory. The optional parameter ':size' allows\n" 7736f6051faSKarsten Merker "\tspecifying the size of a RAW initrd.\n" 7742e192b24SSimon Glass #if defined(CONFIG_OF_LIBFDT) 7756f6051faSKarsten Merker "\tSince booting a Linux kernel requires a flat device-tree, a\n" 7766f6051faSKarsten Merker "\tthird argument providing the address of the device-tree blob\n" 7776f6051faSKarsten Merker "\tis required. To boot a kernel with a device-tree blob but\n" 7786f6051faSKarsten Merker "\twithout an initrd image, use a '-' for the initrd argument.\n" 7792e192b24SSimon Glass #endif 7802e192b24SSimon Glass ""; 7812e192b24SSimon Glass #endif 7822e192b24SSimon Glass 7832e192b24SSimon Glass U_BOOT_CMD( 7842e192b24SSimon Glass booti, CONFIG_SYS_MAXARGS, 1, do_booti, 7852e192b24SSimon Glass "boot arm64 Linux Image image from memory", booti_help_text 7862e192b24SSimon Glass ); 7872e192b24SSimon Glass #endif /* CONFIG_CMD_BOOTI */ 788