X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fcmd_bootm.c;h=046e22ff48f57efd4e9957d311b64377c2e048dd;hb=0c9e2dc612e8b970ea2d13712b0e0f3f1282be4f;hp=7ae5d5b29404f0cfc30e32d2f07b1c3adcc3e0af;hpb=1e362dc3e799fd86722a60f5639e52a67dfc0658;p=karo-tx-uboot.git diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 7ae5d5b294..046e22ff48 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -2,23 +2,7 @@ * (C) Copyright 2000-2009 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ @@ -36,6 +20,7 @@ #include #include #include +#include #include #if defined(CONFIG_CMD_USB) @@ -47,7 +32,6 @@ #endif #if defined(CONFIG_OF_LIBFDT) -#include #include #include #endif @@ -80,19 +64,20 @@ static int image_info(unsigned long addr); #include #include extern flash_info_t flash_info[]; /* info for FLASH chips */ -static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #endif -#ifdef CONFIG_SILENT_CONSOLE -static void fixup_silent_linux(void); +#if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND) +static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #endif -static image_header_t *image_get_kernel(ulong img_addr, int verify); -#if defined(CONFIG_FIT) -static int fit_check_kernel(const void *fit, int os_noffset, int verify); +#include +#include + +#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) +static void fixup_silent_linux(void); #endif -static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, +static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images, ulong *os_data, ulong *os_len); @@ -103,9 +88,18 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, * - verified image architecture (PPC) and type (KERNEL or MULTI), * - loaded (first part of) image to header load address, * - disabled interrupts. + * + * @flag: Flags indicating what to do (BOOTM_STATE_...) + * @argc: Number of arguments. Note that the arguments are shifted down + * so that 0 is the first argument not processed by U-Boot, and + * argc is adjusted accordingly. This avoids confusion as to how + * many arguments are available for the OS. + * @images: Pointers to os/initrd/fdt + * @return 1 on error. On success the OS boots so this function does + * not return. */ typedef int boot_os_fn(int flag, int argc, char * const argv[], - bootm_headers_t *images); /* pointers to os/initrd/fdt */ + bootm_headers_t *images); #ifdef CONFIG_BOOTM_LINUX extern boot_os_fn do_bootm_linux; @@ -123,6 +117,9 @@ static boot_os_fn do_bootm_rtems; #if defined(CONFIG_BOOTM_OSE) static boot_os_fn do_bootm_ose; #endif +#if defined(CONFIG_BOOTM_PLAN9) +static boot_os_fn do_bootm_plan9; +#endif #if defined(CONFIG_CMD_ELF) static boot_os_fn do_bootm_vxworks; static boot_os_fn do_bootm_qnxelf; @@ -149,6 +146,9 @@ static boot_os_fn *boot_os[] = { #if defined(CONFIG_BOOTM_OSE) [IH_OS_OSE] = do_bootm_ose, #endif +#if defined(CONFIG_BOOTM_PLAN9) + [IH_OS_PLAN9] = do_bootm_plan9, +#endif #if defined(CONFIG_CMD_ELF) [IH_OS_VXWORKS] = do_bootm_vxworks, [IH_OS_QNX] = do_bootm_qnxelf, @@ -192,15 +192,21 @@ static inline void boot_start_lmb(bootm_headers_t *images) { } static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - void *os_hdr; - int ret; - memset((void *)&images, 0, sizeof(images)); images.verify = getenv_yesno("verify"); boot_start_lmb(&images); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start"); + images.state = BOOTM_STATE_START; + + return 0; +} + +static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + const void *os_hdr; /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, @@ -263,8 +269,10 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] images.ep = image_get_ep(&images.legacy_hdr_os_copy); #if defined(CONFIG_FIT) } else if (images.fit_uname_os) { + int ret; + ret = fit_image_get_entry(images.fit_hdr_os, - images.fit_noffset_os, &images.ep); + images.fit_noffset_os, &images.ep); if (ret) { puts("Can't get entry point property!\n"); return 1; @@ -280,42 +288,71 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] images.ep += images.os.load; } + images.os.start = (ulong)os_hdr; + + return 0; +} + +static int bootm_find_ramdisk(int flag, int argc, char * const argv[]) +{ + int ret; + + /* find ramdisk */ + ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH, + &images.rd_start, &images.rd_end); + if (ret) { + puts("Ramdisk image is corrupt or invalid\n"); + return 1; + } + + return 0; +} + +#if defined(CONFIG_OF_LIBFDT) +static int bootm_find_fdt(int flag, int argc, char * const argv[]) +{ + int ret; + + /* find flattened device tree */ + ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images, + &images.ft_addr, &images.ft_len); + if (ret) { + puts("Could not find a valid device tree\n"); + return 1; + } + + set_working_fdt_addr(images.ft_addr); + + return 0; +} +#endif + +static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ if (((images.os.type == IH_TYPE_KERNEL) || (images.os.type == IH_TYPE_KERNEL_NOLOAD) || (images.os.type == IH_TYPE_MULTI)) && (images.os.os == IH_OS_LINUX)) { - /* find ramdisk */ - ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH, - &images.rd_start, &images.rd_end); - if (ret) { - puts("Ramdisk image is corrupt or invalid\n"); + if (bootm_find_ramdisk(flag, argc, argv)) return 1; - } #if defined(CONFIG_OF_LIBFDT) - /* find flattened device tree */ - ret = boot_get_fdt(flag, argc, argv, &images, - &images.ft_addr, &images.ft_len); - if (ret) { - puts("Could not find a valid device tree\n"); + if (bootm_find_fdt(flag, argc, argv)) return 1; - } - - set_working_fdt_addr(images.ft_addr); #endif } - images.os.start = (ulong)os_hdr; - images.state = BOOTM_STATE_START; - return 0; } #define BOOTM_ERR_RESET -1 #define BOOTM_ERR_OVERLAP -2 #define BOOTM_ERR_UNIMPLEMENTED -3 -static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) +static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end, + int boot_progress) { + image_info_t os = images->os; uint8_t comp = os.comp; ulong load = os.load; ulong blob_start = os.start; @@ -324,12 +361,15 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) ulong image_len = os.image_len; __maybe_unused uint unc_len = CONFIG_SYS_BOOTM_LEN; int no_overlap = 0; + void *load_buf, *image_buf; #if defined(CONFIG_LZMA) || defined(CONFIG_LZO) int ret; #endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */ const char *type_name = genimg_get_type_name(os.type); + load_buf = map_sysmem(load, image_len); + image_buf = map_sysmem(image_start, image_len); switch (comp) { case IH_COMP_NONE: if (load == blob_start || load == image_start) { @@ -337,17 +377,14 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) no_overlap = 1; } else { printf(" Loading %s ... ", type_name); - memmove_wd((void *)load, (void *)image_start, - image_len, CHUNKSZ); + memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); } *load_end = load + image_len; - puts("OK\n"); break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: printf(" Uncompressing %s ... ", type_name); - if (gunzip((void *)load, unc_len, - (uchar *)image_start, &image_len) != 0) { + if (gunzip(load_buf, unc_len, image_buf, &image_len) != 0) { puts("GUNZIP: uncompress, out-of-mem or overwrite " "error - must RESET board to recover\n"); if (boot_progress) @@ -366,9 +403,9 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) * use slower decompression algorithm which requires * at most 2300 KB of memory. */ - int i = BZ2_bzBuffToBuffDecompress((char *)load, - &unc_len, (char *)image_start, image_len, - CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); + int i = BZ2_bzBuffToBuffDecompress(load_buf, &unc_len, + image_buf, image_len, + CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf("BUNZIP2: uncompress or overwrite error %d " "- must RESET board to recover\n", i); @@ -385,9 +422,8 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) SizeT lzma_len = unc_len; printf(" Uncompressing %s ... ", type_name); - ret = lzmaBuffToBuffDecompress( - (unsigned char *)load, &lzma_len, - (unsigned char *)image_start, image_len); + ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, + image_buf, image_len); unc_len = lzma_len; if (ret != SZ_OK) { printf("LZMA: uncompress or overwrite error %d " @@ -403,9 +439,8 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) case IH_COMP_LZO: printf(" Uncompressing %s ... ", type_name); - ret = lzop_decompress((const unsigned char *)image_start, - image_len, (unsigned char *)load, - &unc_len); + ret = lzop_decompress(image_buf, image_len, load_buf, + &unc_len); if (ret != LZO_E_OK) { printf("LZO: uncompress or overwrite error %d " "- must RESET board to recover\n", ret); @@ -434,26 +469,34 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end); - return BOOTM_ERR_OVERLAP; + /* Check what type of image this is. */ + if (images->legacy_hdr_valid) { + if (image_get_type(&images->legacy_hdr_os_copy) + == IH_TYPE_MULTI) + puts("WARNING: legacy format multi component image overwritten\n"); + return BOOTM_ERR_OVERLAP; + } else { + puts("ERROR: new format image overwritten - must RESET the board to recover\n"); + bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); + return BOOTM_ERR_RESET; + } } return 0; } -static int bootm_start_standalone(ulong iflag, int argc, char * const argv[]) +static int bootm_start_standalone(int argc, char * const argv[]) { char *s; int (*appl)(int, char * const []); /* Don't start if "autostart" is set to "no" */ if (((s = getenv("autostart")) != NULL) && (strcmp(s, "no") == 0)) { - char buf[32]; - sprintf(buf, "%lX", images.os.image_len); - setenv("filesize", buf); + setenv_hex("filesize", images.os.image_len); return 0; } appl = (int (*)(int, char * const []))(ulong)ntohl(images.ep); - (*appl)(argc-1, &argv[1]); + (*appl)(argc, argv); return 0; } @@ -471,111 +514,240 @@ static cmd_tbl_t cmd_bootm_sub[] = { U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""), U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""), U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""), + U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""), U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""), }; +static int boot_selected_os(int argc, char * const argv[], int state, + bootm_headers_t *images, boot_os_fn *boot_fn) +{ + if (images->os.type == IH_TYPE_STANDALONE) { + /* This may return when 'autostart' is 'no' */ + bootm_start_standalone(argc, argv); + return 0; + } + arch_preboot_os(); + boot_fn(state, argc, argv, images); + if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ + return 0; + bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); +#ifdef DEBUG + puts("\n## Control returned to monitor - resetting...\n"); +#endif + return BOOTM_ERR_RESET; +} + +/** + * bootm_disable_interrupts() - Disable interrupts in preparation for load/boot + * + * @return interrupt flag (0 if interrupts were disabled, non-zero if they were + * enabled) + */ +static ulong bootm_disable_interrupts(void) +{ + ulong iflag; + + /* + * We have reached the point of no return: we are going to + * overwrite all exception vector code, so we cannot easily + * recover from any failures any more... + */ + iflag = disable_interrupts(); +#ifdef CONFIG_NETCONSOLE + /* Stop the ethernet stack if NetConsole could have left it up */ + eth_halt(); +#endif + +#if defined(CONFIG_CMD_USB) + /* + * turn off USB to prevent the host controller from writing to the + * SDRAM while Linux is booting. This could happen (at least for OHCI + * controller), because the HCCA (Host Controller Communication Area) + * lies within the SDRAM and the host controller writes continously to + * this area (as busmaster!). The HccaFrameNumber is for example + * updated every 1 ms within the HCCA structure in SDRAM! For more + * details see the OpenHCI specification. + */ + usb_stop(); +#endif + return iflag; +} + +/** + * Execute selected states of the bootm command. + * + * Note the arguments to this state must be the first argument, Any 'bootm' + * or sub-command arguments must have already been taken. + * + * Note that if states contains more than one flag it MUST contain + * BOOTM_STATE_START, since this handles and consumes the command line args. + * + * Also note that aside from boot_os_fn functions and bootm_load_os no other + * functions we store the return value of in 'ret' may use a negative return + * value, without special handling. + * + * @param cmdtp Pointer to bootm command table entry + * @param flag Command flags (CMD_FLAG_...) + * @param argc Number of subcommand arguments (0 = no arguments) + * @param argv Arguments + * @param states Mask containing states to run (BOOTM_STATE_...) + * @param images Image header information + * @param boot_progress 1 to show boot progress, 0 to not do this + * @return 0 if ok, something else on error. Some errors will cause this + * function to perform a reboot! If states contains BOOTM_STATE_OS_GO + * then the intent is to boot an OS, so this function will not return + * unless the image type is standalone. + */ +static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[], int states, bootm_headers_t *images, + int boot_progress) +{ + boot_os_fn *boot_fn; + ulong iflag = 0; + int ret = 0, need_boot_fn; + + images->state |= states; + + /* + * Work through the states and see how far we get. We stop on + * any error. + */ + if (states & BOOTM_STATE_START) + ret = bootm_start(cmdtp, flag, argc, argv); + + if (!ret && (states & BOOTM_STATE_FINDOS)) + ret = bootm_find_os(cmdtp, flag, argc, argv); + + if (!ret && (states & BOOTM_STATE_FINDOTHER)) { + ret = bootm_find_other(cmdtp, flag, argc, argv); + argc = 0; /* consume the args */ + } + + /* Load the OS */ + if (!ret && (states & BOOTM_STATE_LOADOS)) { + ulong load_end; + + iflag = bootm_disable_interrupts(); + ret = bootm_load_os(images, &load_end, 0); + if (ret == 0) + lmb_reserve(&images->lmb, images->os.load, + (load_end - images->os.load)); + else if (ret && ret != BOOTM_ERR_OVERLAP) + goto err; + else if (ret == BOOTM_ERR_OVERLAP) + ret = 0; +#ifdef CONFIG_SILENT_CONSOLE + if (images->os.os == IH_OS_LINUX) + fixup_silent_linux(); +#endif + } + + /* Relocate the ramdisk */ +#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH + if (!ret && (states & BOOTM_STATE_RAMDISK)) { + ulong rd_len = images->rd_end - images->rd_start; + + ret = boot_ramdisk_high(&images->lmb, images->rd_start, + rd_len, &images->initrd_start, &images->initrd_end); + if (!ret) { + setenv_hex("initrd_start", images->initrd_start); + setenv_hex("initrd_end", images->initrd_end); + } + } +#endif +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) + if (!ret && (states & BOOTM_STATE_FDT)) { + boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); + ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, + &images->ft_len); + } +#endif + + /* From now on, we need the OS boot function */ + if (ret) + return ret; + boot_fn = boot_os[images->os.os]; + need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE | + BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | + BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); + if (boot_fn == NULL && need_boot_fn) { + if (iflag) + enable_interrupts(); + printf("ERROR: booting os '%s' (%d) is not supported\n", + genimg_get_os_name(images->os.os), images->os.os); + bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); + return 1; + } + + /* Call various other states that are not generally used */ + if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) + ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); + if (!ret && (states & BOOTM_STATE_OS_BD_T)) + ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); + if (!ret && (states & BOOTM_STATE_OS_PREP)) + ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); + +#ifdef CONFIG_TRACE + /* Pretend to run the OS, then run a user command */ + if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { + char *cmd_list = getenv("fakegocmd"); + + ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, + images, boot_fn); + if (!ret && cmd_list) + ret = run_command_list(cmd_list, -1, flag); + } +#endif + + /* Check for unsupported subcommand. */ + if (ret) { + puts("subcommand not supported\n"); + return ret; + } + + /* Now run the OS! We hope this doesn't return */ + if (!ret && (states & BOOTM_STATE_OS_GO)) + ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, + images, boot_fn); + + /* Deal with any fallout */ +err: + if (iflag) + enable_interrupts(); + + if (ret == BOOTM_ERR_UNIMPLEMENTED) + bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); + else if (ret == BOOTM_ERR_RESET) + do_reset(cmdtp, flag, argc, argv); + + return ret; +} + static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; long state; cmd_tbl_t *c; - boot_os_fn *boot_fn; - c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); + c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); + argc--; argv++; if (c) { state = (long)c->cmd; - - /* treat start special since it resets the state machine */ - if (state == BOOTM_STATE_START) { - argc--; - argv++; - return bootm_start(cmdtp, flag, argc, argv); - } + if (state == BOOTM_STATE_START) + state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER; } else { /* Unrecognized command */ return CMD_RET_USAGE; } - if (images.state < BOOTM_STATE_START || - images.state >= state) { + if (state != BOOTM_STATE_START && images.state >= state) { printf("Trying to execute a command out of order\n"); return CMD_RET_USAGE; } - images.state |= state; - boot_fn = boot_os[images.os.os]; - - switch (state) { - ulong load_end; - case BOOTM_STATE_START: - /* should never occur */ - break; - case BOOTM_STATE_LOADOS: - ret = bootm_load_os(images.os, &load_end, 0); - if (ret) - return ret; - - lmb_reserve(&images.lmb, images.os.load, - (load_end - images.os.load)); - break; -#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH - case BOOTM_STATE_RAMDISK: - { - ulong rd_len = images.rd_end - images.rd_start; - char str[17]; - - ret = boot_ramdisk_high(&images.lmb, images.rd_start, - rd_len, &images.initrd_start, &images.initrd_end); - if (ret) - return ret; - - sprintf(str, "%lx", images.initrd_start); - setenv("initrd_start", str); - sprintf(str, "%lx", images.initrd_end); - setenv("initrd_end", str); - } - break; -#endif -#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) - case BOOTM_STATE_FDT: - { - boot_fdt_add_mem_rsv_regions(&images.lmb, - images.ft_addr); - ret = boot_relocate_fdt(&images.lmb, - &images.ft_addr, &images.ft_len); - break; - } -#endif - case BOOTM_STATE_OS_CMDLINE: - ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images); - if (ret) - printf("cmdline subcommand not supported\n"); - break; - case BOOTM_STATE_OS_BD_T: - ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images); - if (ret) - printf("bdt subcommand not supported\n"); - break; - case BOOTM_STATE_OS_PREP: - ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images); - if (ret) - printf("prep subcommand not supported\n"); - break; - case BOOTM_STATE_OS_GO: - disable_interrupts(); -#ifdef CONFIG_NETCONSOLE - /* - * Stop the ethernet stack if NetConsole could have - * left it up - */ - eth_halt(); -#endif - arch_preboot_os(); - boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images); - break; - } + ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0); return ret; } @@ -586,10 +758,6 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - ulong iflag; - ulong load_end = 0; - int ret; - boot_os_fn *boot_fn; #ifdef CONFIG_NEEDS_MANUAL_RELOC static int relocated = 0; @@ -610,11 +778,12 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif /* determine if we have a sub command */ - if (argc > 1) { + argc--; argv++; + if (argc > 0) { char *endp; - simple_strtoul(argv[1], &endp, 16); - /* endp pointing to NULL means that argv[1] was just a + simple_strtoul(argv[0], &endp, 16); + /* endp pointing to NULL means that argv[0] was just a * valid number, pass it along to the normal bootm processing * * If endp is ':' or '#' assume a FIT identifier so pass @@ -626,101 +795,10 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return do_bootm_subcommand(cmdtp, flag, argc, argv); } - if (bootm_start(cmdtp, flag, argc, argv)) - return 1; - - /* - * We have reached the point of no return: we are going to - * overwrite all exception vector code, so we cannot easily - * recover from any failures any more... - */ - iflag = disable_interrupts(); - -#ifdef CONFIG_NETCONSOLE - /* Stop the ethernet stack if NetConsole could have left it up */ - eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) - /* - * turn off USB to prevent the host controller from writing to the - * SDRAM while Linux is booting. This could happen (at least for OHCI - * controller), because the HCCA (Host Controller Communication Area) - * lies within the SDRAM and the host controller writes continously to - * this area (as busmaster!). The HccaFrameNumber is for example - * updated every 1 ms within the HCCA structure in SDRAM! For more - * details see the OpenHCI specification. - */ - usb_stop(); -#endif - - ret = bootm_load_os(images.os, &load_end, 1); - - if (ret < 0) { - if (ret == BOOTM_ERR_RESET) - do_reset(cmdtp, flag, argc, argv); - if (ret == BOOTM_ERR_OVERLAP) { - if (images.legacy_hdr_valid) { - image_header_t *hdr; - hdr = &images.legacy_hdr_os_copy; - if (image_get_type(hdr) == IH_TYPE_MULTI) - puts("WARNING: legacy format multi " - "component image " - "overwritten\n"); - } else { - puts("ERROR: new format image overwritten - " - "must RESET the board to recover\n"); - bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); - do_reset(cmdtp, flag, argc, argv); - } - } - if (ret == BOOTM_ERR_UNIMPLEMENTED) { - if (iflag) - enable_interrupts(); - bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); - return 1; - } - } - - lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load)); - - if (images.os.type == IH_TYPE_STANDALONE) { - if (iflag) - enable_interrupts(); - /* This may return when 'autostart' is 'no' */ - bootm_start_standalone(iflag, argc, argv); - return 0; - } - - bootstage_mark(BOOTSTAGE_ID_CHECK_BOOT_OS); - -#ifdef CONFIG_SILENT_CONSOLE - if (images.os.os == IH_OS_LINUX) - fixup_silent_linux(); -#endif - - boot_fn = boot_os[images.os.os]; - - if (boot_fn == NULL) { - if (iflag) - enable_interrupts(); - printf("ERROR: booting os '%s' (%d) is not supported\n", - genimg_get_os_name(images.os.os), images.os.os); - bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); - return 1; - } - - arch_preboot_os(); - - boot_fn(0, argc, argv, &images); - - bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); -#ifdef DEBUG - puts("\n## Control returned to monitor - resetting...\n"); -#endif - do_reset(cmdtp, flag, argc, argv); - - return 1; + return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START | + BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER | + BOOTM_STATE_LOADOS | BOOTM_STATE_OS_PREP | + BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1); } int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) @@ -789,54 +867,6 @@ static image_header_t *image_get_kernel(ulong img_addr, int verify) return hdr; } -/** - * fit_check_kernel - verify FIT format kernel subimage - * @fit_hdr: pointer to the FIT image header - * os_noffset: kernel subimage node offset within FIT image - * @verify: data CRC verification flag - * - * fit_check_kernel() verifies integrity of the kernel subimage and from - * specified FIT image. - * - * returns: - * 1, on success - * 0, on failure - */ -#if defined(CONFIG_FIT) -static int fit_check_kernel(const void *fit, int os_noffset, int verify) -{ - fit_image_print(fit, os_noffset, " "); - - if (verify) { - puts(" Verifying Hash Integrity ... "); - if (!fit_image_check_hashes(fit, os_noffset)) { - puts("Bad Data Hash\n"); - bootstage_error(BOOTSTAGE_ID_FIT_CHECK_HASH); - return 0; - } - puts("OK\n"); - } - bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_ARCH); - - if (!fit_image_check_target_arch(fit, os_noffset)) { - puts("Unsupported Architecture\n"); - bootstage_error(BOOTSTAGE_ID_FIT_CHECK_ARCH); - return 0; - } - - bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_KERNEL); - if (!fit_image_check_type(fit, os_noffset, IH_TYPE_KERNEL) && - !fit_image_check_type(fit, os_noffset, IH_TYPE_KERNEL_NOLOAD)) { - puts("Not a kernel image\n"); - bootstage_error(BOOTSTAGE_ID_FIT_CHECK_KERNEL); - return 0; - } - - bootstage_mark(BOOTSTAGE_ID_FIT_CHECKED); - return 1; -} -#endif /* CONFIG_FIT */ - /** * boot_get_kernel - find kernel image * @os_data: pointer to a ulong variable, will hold os data start address @@ -849,39 +879,36 @@ static int fit_check_kernel(const void *fit, int os_noffset, int verify) * pointer to image header if valid image was found, plus kernel start * address and length, otherwise NULL */ -static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, +static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images, ulong *os_data, ulong *os_len) { image_header_t *hdr; ulong img_addr; + const void *buf; #if defined(CONFIG_FIT) - void *fit_hdr; const char *fit_uname_config = NULL; const char *fit_uname_kernel = NULL; - const void *data; - size_t len; - int cfg_noffset; int os_noffset; #endif /* find out kernel image address */ - if (argc < 2) { + if (argc < 1) { img_addr = load_addr; debug("* kernel: default image load address = 0x%08lx\n", load_addr); #if defined(CONFIG_FIT) - } else if (fit_parse_conf(argv[1], load_addr, &img_addr, + } else if (fit_parse_conf(argv[0], load_addr, &img_addr, &fit_uname_config)) { debug("* kernel: config '%s' from image at 0x%08lx\n", fit_uname_config, img_addr); - } else if (fit_parse_subimage(argv[1], load_addr, &img_addr, + } else if (fit_parse_subimage(argv[0], load_addr, &img_addr, &fit_uname_kernel)) { debug("* kernel: subimage '%s' from image at 0x%08lx\n", fit_uname_kernel, img_addr); #endif } else { - img_addr = simple_strtoul(argv[1], NULL, 16); + img_addr = simple_strtoul(argv[0], NULL, 16); debug("* kernel: cmdline image address = 0x%08lx\n", img_addr); } @@ -892,7 +919,8 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, /* check image type, for FIT images get FIT kernel node */ *os_data = *os_len = 0; - switch (genimg_get_format((void *)img_addr)) { + buf = map_sysmem(img_addr, 0); + switch (genimg_get_format(buf)) { case IMAGE_FORMAT_LEGACY: printf("## Booting kernel from Legacy Image at %08lx ...\n", img_addr); @@ -937,85 +965,18 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: - fit_hdr = (void *)img_addr; - printf("## Booting kernel from FIT Image at %08lx ...\n", - img_addr); - - if (!fit_check_format(fit_hdr)) { - puts("Bad FIT kernel image format!\n"); - bootstage_error(BOOTSTAGE_ID_FIT_FORMAT); - return NULL; - } - bootstage_mark(BOOTSTAGE_ID_FIT_FORMAT); - - if (!fit_uname_kernel) { - /* - * no kernel image node unit name, try to get config - * node first. If config unit node name is NULL - * fit_conf_get_node() will try to find default config - * node - */ - bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); -#ifdef CONFIG_FIT_BEST_MATCH - if (fit_uname_config) - cfg_noffset = - fit_conf_get_node(fit_hdr, - fit_uname_config); - else - cfg_noffset = - fit_conf_find_compat(fit_hdr, - gd->fdt_blob); -#else - cfg_noffset = fit_conf_get_node(fit_hdr, - fit_uname_config); -#endif - if (cfg_noffset < 0) { - bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); - return NULL; - } - /* save configuration uname provided in the first - * bootm argument - */ - images->fit_uname_cfg = fdt_get_name(fit_hdr, - cfg_noffset, - NULL); - printf(" Using '%s' configuration\n", - images->fit_uname_cfg); - bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); - - os_noffset = fit_conf_get_kernel_node(fit_hdr, - cfg_noffset); - fit_uname_kernel = fit_get_name(fit_hdr, os_noffset, - NULL); - } else { - /* get kernel component image node offset */ - bootstage_mark(BOOTSTAGE_ID_FIT_UNIT_NAME); - os_noffset = fit_image_get_node(fit_hdr, - fit_uname_kernel); - } - if (os_noffset < 0) { - bootstage_error(BOOTSTAGE_ID_FIT_CONFIG); + os_noffset = fit_image_load(images, FIT_KERNEL_PROP, + img_addr, + &fit_uname_kernel, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_KERNEL, + BOOTSTAGE_ID_FIT_KERNEL_START, + FIT_LOAD_IGNORED, os_data, os_len); + if (os_noffset < 0) return NULL; - } - - printf(" Trying '%s' kernel subimage\n", fit_uname_kernel); - - bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_SUBIMAGE); - if (!fit_check_kernel(fit_hdr, os_noffset, images->verify)) - return NULL; - - /* get kernel image data address and length */ - if (fit_image_get_data(fit_hdr, os_noffset, &data, &len)) { - puts("Could not find kernel subimage data!\n"); - bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO_ERR); - return NULL; - } - bootstage_mark(BOOTSTAGE_ID_FIT_KERNEL_INFO); - *os_len = len; - *os_data = (ulong)data; - images->fit_hdr_os = fit_hdr; + images->fit_hdr_os = map_sysmem(img_addr, 0); images->fit_uname_os = fit_uname_kernel; + images->fit_uname_cfg = fit_uname_config; images->fit_noffset_os = os_noffset; break; #endif @@ -1028,7 +989,7 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, debug(" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n", *os_data, *os_len, *os_len); - return (void *)img_addr; + return buf; } #ifdef CONFIG_SYS_LONGHELP @@ -1056,7 +1017,7 @@ static char bootm_help_text[] = "issued in the order below (it's ok to not issue all sub-commands):\n" "\tstart [addr [arg ...]]\n" "\tloados - load OS image\n" -#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC) +#if defined(CONFIG_SYS_BOOT_RAMDISK_HIGH) "\tramdisk - relocate initrd, set env initrd_start/initrd_end\n" #endif #if defined(CONFIG_OF_LIBFDT) @@ -1163,7 +1124,7 @@ static int image_info(ulong addr) fit_print_contents(hdr); - if (!fit_all_image_check_hashes(hdr)) { + if (!fit_all_image_verify(hdr)) { puts("Bad hash in FIT image!\n"); return 1; } @@ -1193,7 +1154,7 @@ U_BOOT_CMD( /* imls - list all images found in flash */ /*******************************************************************/ #if defined(CONFIG_CMD_IMLS) -static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_imls_nor(void) { flash_info_t *info; int i, j; @@ -1242,6 +1203,161 @@ next_sector: ; } next_bank: ; } + return 0; +} +#endif + +#if defined(CONFIG_CMD_IMLS_NAND) +static int nand_imls_legacyimage(nand_info_t *nand, int nand_dev, loff_t off, + size_t len) +{ + void *imgdata; + int ret; + + imgdata = malloc(len); + if (!imgdata) { + printf("May be a Legacy Image at NAND device %d offset %08llX:\n", + nand_dev, off); + printf(" Low memory(cannot allocate memory for image)\n"); + return -ENOMEM; + } + + ret = nand_read_skip_bad(nand, off, &len, + imgdata); + if (ret < 0 && ret != -EUCLEAN) { + free(imgdata); + return ret; + } + + if (!image_check_hcrc(imgdata)) { + free(imgdata); + return 0; + } + + printf("Legacy Image at NAND device %d offset %08llX:\n", + nand_dev, off); + image_print_contents(imgdata); + + puts(" Verifying Checksum ... "); + if (!image_check_dcrc(imgdata)) + puts("Bad Data CRC\n"); + else + puts("OK\n"); + + free(imgdata); + + return 0; +} + +static int nand_imls_fitimage(nand_info_t *nand, int nand_dev, loff_t off, + size_t len) +{ + void *imgdata; + int ret; + + imgdata = malloc(len); + if (!imgdata) { + printf("May be a FIT Image at NAND device %d offset %08llX:\n", + nand_dev, off); + printf(" Low memory(cannot allocate memory for image)\n"); + return -ENOMEM; + } + + ret = nand_read_skip_bad(nand, off, &len, + imgdata); + if (ret < 0 && ret != -EUCLEAN) { + free(imgdata); + return ret; + } + + if (!fit_check_format(imgdata)) { + free(imgdata); + return 0; + } + + printf("FIT Image at NAND device %d offset %08llX:\n", nand_dev, off); + + fit_print_contents(imgdata); + free(imgdata); + + return 0; +} + +static int do_imls_nand(void) +{ + nand_info_t *nand; + int nand_dev = nand_curr_device; + size_t len; + loff_t off; + u32 buffer[16]; + + if (nand_dev < 0 || nand_dev >= CONFIG_SYS_MAX_NAND_DEVICE) { + puts("\nNo NAND devices available\n"); + return -ENODEV; + } + + printf("\n"); + + for (nand_dev = 0; nand_dev < CONFIG_SYS_MAX_NAND_DEVICE; nand_dev++) { + nand = &nand_info[nand_dev]; + if (!nand->name || !nand->size) + continue; + + for (off = 0; off < nand->size; off += nand->erasesize) { + const image_header_t *header; + int ret; + + if (nand_block_isbad(nand, off)) + continue; + + len = sizeof(buffer); + + ret = nand_read(nand, off, &len, (u8 *)buffer); + if (ret < 0 && ret != -EUCLEAN) { + printf("NAND read error %d at offset %08llX\n", + ret, off); + continue; + } + + switch (genimg_get_format(buffer)) { + case IMAGE_FORMAT_LEGACY: + header = (const image_header_t *)buffer; + + len = image_get_image_size(header); + nand_imls_legacyimage(nand, nand_dev, off, len); + break; +#if defined(CONFIG_FIT) + case IMAGE_FORMAT_FIT: + len = fit_get_size(buffer); + nand_imls_fitimage(nand, nand_dev, off, len); + break; +#endif + } + } + } + + return 0; +} +#endif + +#if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND) +static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret_nor = 0, ret_nand = 0; + +#if defined(CONFIG_CMD_IMLS) + ret_nor = do_imls_nor(); +#endif + +#if defined(CONFIG_CMD_IMLS_NAND) + ret_nand = do_imls_nand(); +#endif + + if (ret_nor) + return ret_nor; + + if (ret_nand) + return ret_nand; return (0); } @@ -1250,18 +1366,23 @@ U_BOOT_CMD( imls, 1, 1, do_imls, "list all images found in flash", "\n" - " - Prints information about all images found at sector\n" - " boundaries in flash." + " - Prints information about all images found at sector/block\n" + " boundaries in nor/nand flash." ); #endif /*******************************************************************/ /* helper routines */ /*******************************************************************/ -#ifdef CONFIG_SILENT_CONSOLE +#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) + +#define CONSOLE_ARG "console=" +#define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1) + static void fixup_silent_linux(void) { - char buf[256], *start, *end; + char *buf; + const char *env_val; char *cmdline = getenv("bootargs"); /* Only fix cmdline when requested */ @@ -1269,28 +1390,53 @@ static void fixup_silent_linux(void) return; debug("before silent fix-up: %s\n", cmdline); - if (cmdline) { - start = strstr(cmdline, "console="); + if (cmdline && (cmdline[0] != '\0')) { + char *start = strstr(cmdline, CONSOLE_ARG); + + /* Allocate space for maximum possible new command line */ + buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_LEN + 1); + if (!buf) { + debug("%s: out of memory\n", __func__); + return; + } + if (start) { - end = strchr(start, ' '); - strncpy(buf, cmdline, (start - cmdline + 8)); + char *end = strchr(start, ' '); + int num_start_bytes = start - cmdline + CONSOLE_ARG_LEN; + + strncpy(buf, cmdline, num_start_bytes); if (end) - strcpy(buf + (start - cmdline + 8), end); + strcpy(buf + num_start_bytes, end); else - buf[start - cmdline + 8] = '\0'; + buf[num_start_bytes] = '\0'; } else { - strcpy(buf, cmdline); - strcat(buf, " console="); + sprintf(buf, "%s %s", cmdline, CONSOLE_ARG); } + env_val = buf; } else { - strcpy(buf, "console="); + buf = NULL; + env_val = CONSOLE_ARG; } - setenv("bootargs", buf); - debug("after silent fix-up: %s\n", buf); + setenv("bootargs", env_val); + debug("after silent fix-up: %s\n", env_val); + free(buf); } #endif /* CONFIG_SILENT_CONSOLE */ +#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9) +static void copy_args(char *dest, int argc, char * const argv[], char delim) +{ + int i; + + for (i = 0; i < argc; i++) { + if (i > 0) + *dest++ = delim; + strcpy(dest, argv[i]); + dest += strlen(argv[i]); + } +} +#endif /*******************************************************************/ /* OS booting routines */ @@ -1306,6 +1452,8 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[], char *consdev; char *cmdline; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1346,20 +1494,14 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[], consdev = "scc3"; #endif - if (argc > 2) { + if (argc > 0) { ulong len; int i; - for (i = 2, len = 0; i < argc; i += 1) + for (i = 0, len = 0; i < argc; i += 1) len += strlen(argv[i]) + 1; cmdline = malloc(len); - - for (i = 2, len = 0; i < argc; i += 1) { - if (i > 2) - cmdline[len++] = ' '; - strcpy(&cmdline[len], argv[i]); - len += strlen(argv[i]); - } + copy_args(cmdline, argc, argv, ' '); } else if ((cmdline = getenv("bootargs")) == NULL) { cmdline = ""; } @@ -1391,6 +1533,8 @@ static int do_bootm_lynxkdi(int flag, int argc, char * const argv[], { image_header_t *hdr = &images->legacy_hdr_os_copy; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1413,6 +1557,8 @@ static int do_bootm_rtems(int flag, int argc, char * const argv[], { void (*entry_point)(bd_t *); + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1446,6 +1592,8 @@ static int do_bootm_ose(int flag, int argc, char * const argv[], { void (*entry_point)(void); + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1473,12 +1621,64 @@ static int do_bootm_ose(int flag, int argc, char * const argv[], } #endif /* CONFIG_BOOTM_OSE */ +#if defined(CONFIG_BOOTM_PLAN9) +static int do_bootm_plan9(int flag, int argc, char * const argv[], + bootm_headers_t *images) +{ + void (*entry_point)(void); + char *s; + + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) + return 1; + +#if defined(CONFIG_FIT) + if (!images->legacy_hdr_valid) { + fit_unsupported_reset("Plan 9"); + return 1; + } +#endif + + /* See README.plan9 */ + s = getenv("confaddr"); + if (s != NULL) { + char *confaddr = (char *)simple_strtoul(s, NULL, 16); + + if (argc > 0) { + copy_args(confaddr, argc, argv, '\n'); + } else { + s = getenv("bootargs"); + if (s != NULL) + strcpy(confaddr, s); + } + } + + entry_point = (void (*)(void))images->ep; + + printf("## Transferring control to Plan 9 (at address %08lx) ...\n", + (ulong)entry_point); + + bootstage_mark(BOOTSTAGE_ID_RUN_OS); + + /* + * Plan 9 Parameters: + * None + */ + (*entry_point)(); + + return 1; +} +#endif /* CONFIG_BOOTM_PLAN9 */ + #if defined(CONFIG_CMD_ELF) static int do_bootm_vxworks(int flag, int argc, char * const argv[], bootm_headers_t *images) { char str[80]; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1502,6 +1702,8 @@ static int do_bootm_qnxelf(int flag, int argc, char * const argv[], char *local_args[2]; char str[16]; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1527,6 +1729,8 @@ static int do_bootm_integrity(int flag, int argc, char * const argv[], { void (*entry_point)(void); + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1556,15 +1760,13 @@ static int do_bootm_integrity(int flag, int argc, char * const argv[], #ifdef CONFIG_CMD_BOOTZ -static int __bootz_setup(void *image, void **start, void **end) +int __weak bootz_setup(ulong image, ulong *start, ulong *end) { /* Please define bootz_setup() for your platform */ puts("Your platform's zImage format isn't supported yet!\n"); return -1; } -int bootz_setup(void *image, void **start, void **end) - __attribute__((weak, alias("__bootz_setup"))); /* * zImage booting support @@ -1573,96 +1775,66 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images) { int ret; - void *zi_start, *zi_end; - - memset(images, 0, sizeof(bootm_headers_t)); + ulong zi_start, zi_end; - boot_start_lmb(images); + ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, + images, 1); /* Setup Linux kernel zImage entry point */ - if (argc < 2) { + if (!argc) { images->ep = load_addr; debug("* kernel: default image load address = 0x%08lx\n", load_addr); } else { - images->ep = simple_strtoul(argv[1], NULL, 16); + images->ep = simple_strtoul(argv[0], NULL, 16); debug("* kernel: cmdline image address = 0x%08lx\n", images->ep); } - ret = bootz_setup((void *)images->ep, &zi_start, &zi_end); + ret = bootz_setup(images->ep, &zi_start, &zi_end); if (ret != 0) return 1; lmb_reserve(&images->lmb, images->ep, zi_end - zi_start); - /* Find ramdisk */ - ret = boot_get_ramdisk(argc, argv, images, IH_INITRD_ARCH, - &images->rd_start, &images->rd_end); - if (ret) { - puts("Ramdisk image is corrupt or invalid\n"); + /* + * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not + * have a header that provide this informaiton. + */ + if (bootm_find_ramdisk(flag, argc, argv)) return 1; - } #if defined(CONFIG_OF_LIBFDT) - /* find flattened device tree */ - ret = boot_get_fdt(flag, argc, argv, images, - &images->ft_addr, &images->ft_len); - if (ret) { - puts("Could not find a valid device tree\n"); + if (bootm_find_fdt(flag, argc, argv)) return 1; - } - - set_working_fdt_addr(images->ft_addr); #endif return 0; } -static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - bootm_headers_t images; + int ret; + + /* Consume 'bootz' */ + argc--; argv++; if (bootz_start(cmdtp, flag, argc, argv, &images)) return 1; /* - * We have reached the point of no return: we are going to - * overwrite all exception vector code, so we cannot easily - * recover from any failures any more... - */ - disable_interrupts(); - -#ifdef CONFIG_NETCONSOLE - /* Stop the ethernet stack if NetConsole could have left it up */ - eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) - /* - * turn off USB to prevent the host controller from writing to the - * SDRAM while Linux is booting. This could happen (at least for OHCI - * controller), because the HCCA (Host Controller Communication Area) - * lies within the SDRAM and the host controller writes continously to - * this area (as busmaster!). The HccaFrameNumber is for example - * updated every 1 ms within the HCCA structure in SDRAM! For more - * details see the OpenHCI specification. + * We are doing the BOOTM_STATE_LOADOS state ourselves, so must + * disable interrupts ourselves */ - usb_stop(); -#endif - -#ifdef CONFIG_SILENT_CONSOLE - fixup_silent_linux(); -#endif - arch_preboot_os(); + bootm_disable_interrupts(); - do_bootm_linux(0, argc, argv, &images); -#ifdef DEBUG - puts("\n## Control returned to monitor - resetting...\n"); -#endif - do_reset(cmdtp, flag, argc, argv); + images.os.os = IH_OS_LINUX; + ret = do_bootm_states(cmdtp, flag, argc, argv, + BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | + BOOTM_STATE_OS_GO, + &images, 1); - return 1; + return ret; } #ifdef CONFIG_SYS_LONGHELP