]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/cmd_bootm.c
net: phy: don't try autonegotiation if it is not enabled in the PHY
[karo-tx-uboot.git] / common / cmd_bootm.c
index ba0bcd4e324561ba05615e60f48f7f7347dd925e..046e22ff48f57efd4e9957d311b64377c2e048dd 100644 (file)
@@ -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+
  */
 
 
@@ -309,33 +293,53 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
        return 0;
 }
 
-static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
-                           char * const argv[])
+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, IH_ARCH_DEFAULT, &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
        }
 
@@ -345,8 +349,10 @@ static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
 #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;
@@ -374,7 +380,6 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
                        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:
@@ -464,7 +469,17 @@ 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;
@@ -504,19 +519,40 @@ static cmd_tbl_t cmd_bootm_sub[] = {
 };
 
 static int boot_selected_os(int argc, char * const argv[], int state,
-               bootm_headers_t *images, boot_os_fn *boot_fn, ulong *iflag)
+               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();
+       iflag = disable_interrupts();
 #ifdef CONFIG_NETCONSOLE
        /* Stop the ethernet stack if NetConsole could have left it up */
        eth_halt();
@@ -534,19 +570,7 @@ static int boot_selected_os(int argc, char * const argv[], int state,
         */
        usb_stop();
 #endif
-#ifdef CONFIG_SILENT_CONSOLE
-       if (images->os.os == IH_OS_LINUX)
-               fixup_silent_linux();
-#endif
-       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;
+       return iflag;
 }
 
 /**
@@ -558,6 +582,10 @@ static int boot_selected_os(int argc, char * const argv[], int state,
  * 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)
@@ -576,7 +604,7 @@ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc,
 {
        boot_os_fn *boot_fn;
        ulong iflag = 0;
-       int ret = 0;
+       int ret = 0, need_boot_fn;
 
        images->state |= states;
 
@@ -599,11 +627,19 @@ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc,
        if (!ret && (states & BOOTM_STATE_LOADOS)) {
                ulong load_end;
 
-               ret = bootm_load_os(images->os, &load_end, 0);
-               if (!ret) {
+               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 */
@@ -631,7 +667,10 @@ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc,
        if (ret)
                return ret;
        boot_fn = boot_os[images->os.os];
-       if (boot_fn == NULL) {
+       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",
@@ -654,41 +693,32 @@ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc,
                char *cmd_list = getenv("fakegocmd");
 
                ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
-                               images, boot_fn, &iflag);
+                               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, &iflag);
+                               images, boot_fn);
 
        /* Deal with any fallout */
-       if (ret < 0) {
-               if (ret == BOOTM_ERR_UNIMPLEMENTED) {
-                       if (iflag)
-                               enable_interrupts();
-                       bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
-                       return 1;
-               } else if (ret == BOOTM_ERR_OVERLAP) {
-                       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");
-                       } else {
-                               puts("ERROR: new format image overwritten - must RESET the board to recover\n");
-                               bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
-                               ret = BOOTM_ERR_RESET;
-                       }
-               }
-               if (ret == BOOTM_ERR_RESET)
-                       do_reset(cmdtp, flag, argc, argv);
-       }
+err:
        if (iflag)
                enable_interrupts();
-       if (ret)
-               puts("subcommand not supported\n");
+
+       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;
 }
@@ -937,7 +967,7 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
        case IMAGE_FORMAT_FIT:
                os_noffset = fit_image_load(images, FIT_KERNEL_PROP,
                                img_addr,
-                               &fit_uname_kernel, fit_uname_config,
+                               &fit_uname_kernel, &fit_uname_config,
                                IH_ARCH_DEFAULT, IH_TYPE_KERNEL,
                                BOOTSTAGE_ID_FIT_KERNEL_START,
                                FIT_LOAD_IGNORED, os_data, os_len);
@@ -946,6 +976,7 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
 
                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
@@ -1421,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;
 
@@ -1500,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;
 
@@ -1522,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;
 
@@ -1555,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;
 
@@ -1589,6 +1628,8 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],
        void (*entry_point)(void);
        char *s;
 
+       if (flag & BOOTM_STATE_OS_PREP)
+               return 0;
        if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
                return 1;
 
@@ -1636,6 +1677,8 @@ static int do_bootm_vxworks(int flag, int argc, char * const argv[],
 {
        char str[80];
 
+       if (flag & BOOTM_STATE_OS_PREP)
+               return 0;
        if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
                return 1;
 
@@ -1659,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;
 
@@ -1684,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;
 
@@ -1713,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
@@ -1730,44 +1775,63 @@ 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;
+       ulong zi_start, zi_end;
 
        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);
 
-       ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_FINDOTHER,
-                             images, 1);
+       /*
+        * 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;
 
-       return ret;
+#if defined(CONFIG_OF_LIBFDT)
+       if (bootm_find_fdt(flag, argc, argv))
+               return 1;
+#endif
+
+       return 0;
 }
 
 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 are doing the BOOTM_STATE_LOADOS state ourselves, so must
+        * disable interrupts ourselves
+        */
+       bootm_disable_interrupts();
+
+       images.os.os = IH_OS_LINUX;
        ret = do_bootm_states(cmdtp, flag, argc, argv,
-                             BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO,
+                             BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
+                             BOOTM_STATE_OS_GO,
                              &images, 1);
 
        return ret;