]> Git Repo - u-boot.git/blobdiff - boot/bootm.c
bootm: Move do_bootm_states() comment to header file
[u-boot.git] / boot / bootm.c
index 598f880d86ddf4124cbdd53a8668274a5572e4c9..875f8a1c2a567664eaa1e22fb2e6274b352df702 100644 (file)
@@ -6,6 +6,7 @@
 
 #ifndef USE_HOSTCC
 #include <common.h>
+#include <bootm.h>
 #include <bootstage.h>
 #include <cli.h>
 #include <command.h>
@@ -102,28 +103,30 @@ static struct legacy_img_hdr *image_get_kernel(ulong img_addr, int verify)
 #endif
 
 /**
- * boot_get_kernel - find kernel image
+ * boot_get_kernel() - find kernel image
+ *
+ * @addr_fit: first argument to bootm: address, fit configuration, etc.
  * @os_data: pointer to a ulong variable, will hold os data start address
  * @os_len: pointer to a ulong variable, will hold os data length
+ *     address and length, otherwise NULL
+ *     pointer to image header if valid image was found, plus kernel start
+ * @kernp: image header if valid image was found, otherwise NULL
  *
  * boot_get_kernel() tries to find a kernel image, verifies its integrity
  * and locates kernel data.
  *
- * returns:
- *     pointer to image header if valid image was found, plus kernel start
- *     address and length, otherwise NULL
+ * Return: 0 on success, -ve on error. -EPROTOTYPE means that the image is in
+ * a wrong or unsupported format
  */
-static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
-                                  char *const argv[], struct bootm_headers *images,
-                                  ulong *os_data, ulong *os_len)
+static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images,
+                          ulong *os_data, ulong *os_len, const void **kernp)
 {
 #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
        struct legacy_img_hdr   *hdr;
 #endif
        ulong           img_addr;
        const void *buf;
-       const char      *fit_uname_config = NULL;
-       const char      *fit_uname_kernel = NULL;
+       const char *fit_uname_config = NULL, *fit_uname_kernel = NULL;
 #if CONFIG_IS_ENABLED(FIT)
        int             os_noffset;
 #endif
@@ -132,8 +135,7 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
        const void *boot_img;
        const void *vendor_boot_img;
 #endif
-       img_addr = genimg_get_kernel_addr_fit(argc < 1 ? NULL : argv[0],
-                                             &fit_uname_config,
+       img_addr = genimg_get_kernel_addr_fit(addr_fit, &fit_uname_config,
                                              &fit_uname_kernel);
 
        if (IS_ENABLED(CONFIG_CMD_BOOTM_PRE_LOAD))
@@ -151,7 +153,7 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
                       img_addr);
                hdr = image_get_kernel(img_addr, images->verify);
                if (!hdr)
-                       return NULL;
+                       return -EINVAL;
                bootstage_mark(BOOTSTAGE_ID_CHECK_IMAGETYPE);
 
                /* get os_data and os_len */
@@ -169,10 +171,8 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
                        *os_len = image_get_data_size(hdr);
                        break;
                default:
-                       printf("Wrong Image Type for %s command\n",
-                              cmdtp->name);
                        bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE);
-                       return NULL;
+                       return -EPROTOTYPE;
                }
 
                /*
@@ -197,7 +197,7 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
                                BOOTSTAGE_ID_FIT_KERNEL_START,
                                FIT_LOAD_IGNORED, os_data, os_len);
                if (os_noffset < 0)
-                       return NULL;
+                       return -ENOENT;
 
                images->fit_hdr_os = map_sysmem(img_addr, 0);
                images->fit_uname_os = fit_uname_kernel;
@@ -206,7 +206,9 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
                break;
 #endif
 #ifdef CONFIG_ANDROID_BOOT_IMAGE
-       case IMAGE_FORMAT_ANDROID:
+       case IMAGE_FORMAT_ANDROID: {
+               int ret;
+
                boot_img = buf;
                vendor_boot_img = NULL;
                if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
@@ -214,25 +216,27 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
                        vendor_boot_img = map_sysmem(get_avendor_bootimg_addr(), 0);
                }
                printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
-               if (android_image_get_kernel(boot_img, vendor_boot_img, images->verify,
-                                            os_data, os_len))
-                       return NULL;
+               ret = android_image_get_kernel(boot_img, vendor_boot_img,
+                                              images->verify, os_data, os_len);
                if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
                        unmap_sysmem(vendor_boot_img);
                        unmap_sysmem(boot_img);
                }
+               if (ret)
+                       return ret;
                break;
+       }
 #endif
        default:
-               printf("Wrong Image Format for %s command\n", cmdtp->name);
-               bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
-               return NULL;
+               bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE);
+               return -EPROTOTYPE;
        }
 
        debug("   kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
              *os_data, *os_len, *os_len);
+       *kernp = buf;
 
-       return buf;
+       return 0;
 }
 
 #ifdef CONFIG_LMB
@@ -301,8 +305,14 @@ static int bootm_pre_load(const char *addr_str)
        return ret;
 }
 
-static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
-                        char *const argv[])
+/**
+ * bootm_find_os(): Find the OS to boot
+ *
+ * @cmd_name: Command name that started this boot, e.g. "bootm"
+ * @addr_fit: Address and/or FIT specifier (first arg of bootm command)
+ * Return: 0 on success, -ve on error
+ */
+static int bootm_find_os(const char *cmd_name, const char *addr_fit)
 {
        const void *os_hdr;
 #ifdef CONFIG_ANDROID_BOOT_IMAGE
@@ -313,10 +323,13 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
        int ret;
 
        /* get kernel image header, start address and length */
-       os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
-                       &images, &images.os.image_start, &images.os.image_len);
-       if (images.os.image_len == 0) {
-               puts("ERROR: can't get kernel image!\n");
+       ret = boot_get_kernel(addr_fit, &images, &images.os.image_start,
+                             &images.os.image_len, &os_hdr);
+       if (ret) {
+               if (ret == -EPROTOTYPE)
+                       printf("Wrong Image Type for %s command\n", cmd_name);
+
+               printf("ERROR %dE: can't get kernel image!\n", ret);
                return 1;
        }
 
@@ -431,24 +444,8 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
        }
 
        if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
-               if (IS_ENABLED(CONFIG_CMD_BOOTI) &&
-                   images.os.arch == IH_ARCH_ARM64 &&
-                   images.os.os == IH_OS_LINUX) {
-                       ulong image_addr;
-                       ulong image_size;
-
-                       ret = booti_setup(images.os.image_start, &image_addr,
-                                         &image_size, true);
-                       if (ret != 0)
-                               return 1;
-
-                       images.os.type = IH_TYPE_KERNEL;
-                       images.os.load = image_addr;
-                       images.ep = image_addr;
-               } else {
-                       images.os.load = images.os.image_start;
-                       images.ep += images.os.image_start;
-               }
+               images.os.load = images.os.image_start;
+               images.ep += images.os.image_start;
        }
 
        images.os.start = map_to_sysmem(os_hdr);
@@ -457,30 +454,58 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
 }
 
 /**
- * bootm_find_images - wrapper to find and locate various images
- * @flag: Ignored Argument
- * @argc: command argument count
- * @argv: command argument list
- * @start: OS image start address
- * @size: OS image size
- *
- * boot_find_images() will attempt to load an available ramdisk,
- * flattened device tree, as well as specifically marked
- * "loadable" images (loadables are FIT only)
+ * check_overlap() - Check if an image overlaps the OS
  *
- * Note: bootm_find_images will skip an image if it is not found
- *
- * @return:
- *     0, if all existing images were loaded correctly
- *     1, if an image is found but corrupted, or invalid
+ * @name: Name of image to check (used to print error)
+ * @base: Base address of image
+ * @end: End address of image (+1)
+ * @os_start: Start of OS
+ * @os_size: Size of OS in bytes
+ * Return: 0 if OK, -EXDEV if the image overlaps the OS
  */
-int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
-                     ulong size)
+static int check_overlap(const char *name, ulong base, ulong end,
+                        ulong os_start, ulong os_size)
 {
+       ulong os_end;
+
+       if (!base)
+               return 0;
+       os_end = os_start + os_size;
+
+       if ((base >= os_start && base < os_end) ||
+           (end > os_start && end <= os_end) ||
+           (base < os_start && end >= os_end)) {
+               printf("ERROR: %s image overlaps OS image (OS=%lx..%lx)\n",
+                      name, os_start, os_end);
+
+               return -EXDEV;
+       }
+
+       return 0;
+}
+
+int bootm_find_images(ulong img_addr, const char *conf_ramdisk,
+                     const char *conf_fdt, ulong start, ulong size)
+{
+       const char *select = conf_ramdisk;
+       char addr_str[17];
+       void *buf;
        int ret;
 
+       if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE)) {
+               /* Look for an Android boot image */
+               buf = map_sysmem(images.os.start, 0);
+               if (buf && genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) {
+                       strcpy(addr_str, simple_xtoa(img_addr));
+                       select = addr_str;
+               }
+       }
+
+       if (conf_ramdisk)
+               select = conf_ramdisk;
+
        /* find ramdisk */
-       ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
+       ret = boot_get_ramdisk(select, &images, IH_INITRD_ARCH,
                               &images.rd_start, &images.rd_end);
        if (ret) {
                puts("Ramdisk image is corrupt or invalid\n");
@@ -488,46 +513,33 @@ int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
        }
 
        /* check if ramdisk overlaps OS image */
-       if (images.rd_start && (((ulong)images.rd_start >= start &&
-                                (ulong)images.rd_start < start + size) ||
-                               ((ulong)images.rd_end > start &&
-                                (ulong)images.rd_end <= start + size) ||
-                               ((ulong)images.rd_start < start &&
-                                (ulong)images.rd_end >= start + size))) {
-               printf("ERROR: RD image overlaps OS image (OS=0x%lx..0x%lx)\n",
-                      start, start + size);
+       if (check_overlap("RD", images.rd_start, images.rd_end, start, size))
                return 1;
-       }
 
-#if CONFIG_IS_ENABLED(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");
-               return 1;
-       }
+       if (CONFIG_IS_ENABLED(OF_LIBFDT)) {
+               buf = map_sysmem(img_addr, 0);
 
-       /* check if FDT overlaps OS image */
-       if (images.ft_addr &&
-           (((ulong)images.ft_addr >= start &&
-             (ulong)images.ft_addr < start + size) ||
-            ((ulong)images.ft_addr + images.ft_len >= start &&
-             (ulong)images.ft_addr + images.ft_len < start + size))) {
-               printf("ERROR: FDT image overlaps OS image (OS=0x%lx..0x%lx)\n",
-                      start, start + size);
-               return 1;
-       }
+               /* find flattened device tree */
+               ret = boot_get_fdt(buf, conf_fdt, IH_ARCH_DEFAULT, &images,
+                                  &images.ft_addr, &images.ft_len);
+               if (ret) {
+                       puts("Could not find a valid device tree\n");
+                       return 1;
+               }
 
-       if (IS_ENABLED(CONFIG_CMD_FDT))
-               set_working_fdt_addr(map_to_sysmem(images.ft_addr));
-#endif
+               /* check if FDT overlaps OS image */
+               if (check_overlap("FDT", map_to_sysmem(images.ft_addr),
+                                 images.ft_len, start, size))
+                       return 1;
+
+               if (IS_ENABLED(CONFIG_CMD_FDT))
+                       set_working_fdt_addr(map_to_sysmem(images.ft_addr));
+       }
 
 #if CONFIG_IS_ENABLED(FIT)
        if (IS_ENABLED(CONFIG_FPGA)) {
                /* find bitstreams */
-               ret = boot_get_fpga(argc, argv, &images, IH_ARCH_DEFAULT,
-                                   NULL, NULL);
+               ret = boot_get_fpga(&images);
                if (ret) {
                        printf("FPGA image is corrupted or invalid\n");
                        return 1;
@@ -535,8 +547,7 @@ int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
        }
 
        /* find all of the loadables */
-       ret = boot_get_loadable(argc, argv, &images, IH_ARCH_DEFAULT,
-                              NULL, NULL);
+       ret = boot_get_loadable(&images);
        if (ret) {
                printf("Loadable(s) is corrupt or invalid\n");
                return 1;
@@ -546,15 +557,17 @@ int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
        return 0;
 }
 
-static int bootm_find_other(struct cmd_tbl *cmdtp, int flag, int argc,
-                           char *const argv[])
+static int bootm_find_other(ulong img_addr, const char *conf_ramdisk,
+                           const char *conf_fdt)
 {
-       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 ||
-                images.os.os == IH_OS_VXWORKS))
-               return bootm_find_images(flag, argc, argv, 0, 0);
+       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 || images.os.os == IH_OS_VXWORKS ||
+            images.os.os == IH_OS_EFI || images.os.os == IH_OS_TEE)) {
+               return bootm_find_images(img_addr, conf_ramdisk, conf_fdt, 0,
+                                        0);
+       }
 
        return 0;
 }
@@ -617,6 +630,24 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
        void *load_buf, *image_buf;
        int err;
 
+       /*
+        * For a "noload" compressed kernel we need to allocate a buffer large
+        * enough to decompress in to and use that as the load address now.
+        * Assume that the kernel compression is at most a factor of 4 since
+        * zstd almost achieves that.
+        * Use an alignment of 2MB since this might help arm64
+        */
+       if (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp != IH_COMP_NONE) {
+               ulong req_size = ALIGN(image_len * 4, SZ_1M);
+
+               load = lmb_alloc(&images->lmb, req_size, SZ_2M);
+               if (!load)
+                       return 1;
+               os.load = load;
+               debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n",
+                     req_size, load, image_len);
+       }
+
        load_buf = map_sysmem(load, 0);
        image_buf = map_sysmem(os.image_start, image_len);
        err = image_decomp(os.comp, load, os.image_start, os.type,
@@ -657,6 +688,31 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
                }
        }
 
+       if (IS_ENABLED(CONFIG_CMD_BOOTI) && images->os.arch == IH_ARCH_ARM64 &&
+           images->os.os == IH_OS_LINUX) {
+               ulong relocated_addr;
+               ulong image_size;
+               int ret;
+
+               ret = booti_setup(load, &relocated_addr, &image_size, false);
+               if (ret) {
+                       printf("Failed to prep arm64 kernel (err=%d)\n", ret);
+                       return BOOTM_ERR_RESET;
+               }
+
+               /* Handle BOOTM_STATE_LOADOS */
+               if (relocated_addr != load) {
+                       printf("Moving Image from 0x%lx to 0x%lx, end=%lx\n",
+                              load, relocated_addr,
+                              relocated_addr + image_size);
+                       memmove((void *)relocated_addr, load_buf, image_size);
+               }
+
+               images->ep = relocated_addr;
+               images->os.start = relocated_addr;
+               images->os.end = relocated_addr + image_size;
+       }
+
        lmb_reserve(&images->lmb, images->os.load, (load_end -
                                                    images->os.load));
        return 0;
@@ -934,35 +990,11 @@ unmap_image:
        return ret;
 }
 
-/**
- * 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.
- */
 int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
                    char *const argv[], int states, struct bootm_headers *images,
                    int boot_progress)
 {
+       struct bootm_info bmi;
        boot_os_fn *boot_fn;
        ulong iflag = 0;
        int ret = 0, need_boot_fn;
@@ -980,10 +1012,15 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
                ret = bootm_pre_load(argv[0]);
 
        if (!ret && (states & BOOTM_STATE_FINDOS))
-               ret = bootm_find_os(cmdtp, flag, argc, argv);
+               ret = bootm_find_os(cmdtp->name, argv[0]);
+
+       if (!ret && (states & BOOTM_STATE_FINDOTHER)) {
+               ulong img_addr;
 
-       if (!ret && (states & BOOTM_STATE_FINDOTHER))
-               ret = bootm_find_other(cmdtp, flag, argc, argv);
+               img_addr = argc ? hextoul(argv[0], NULL) : image_load_addr;
+               ret = bootm_find_other(img_addr, cmd_arg1(argc, argv),
+                                      cmd_arg2(argc, argv));
+       }
 
        if (IS_ENABLED(CONFIG_MEASURED_BOOT) && !ret &&
            (states & BOOTM_STATE_MEASURE))
@@ -1036,12 +1073,15 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
                return 1;
        }
 
+       bmi.images = images;
+       bmi.argc = argc;
+       bmi.argv = argv;
 
        /* 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);
+               ret = boot_fn(BOOTM_STATE_OS_CMDLINE, &bmi);
        if (!ret && (states & BOOTM_STATE_OS_BD_T))
-               ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
+               ret = boot_fn(BOOTM_STATE_OS_BD_T, &bmi);
        if (!ret && (states & BOOTM_STATE_OS_PREP)) {
                ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX);
                if (ret) {
@@ -1049,7 +1089,7 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
                        ret = CMD_RET_FAILURE;
                        goto err;
                }
-               ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
+               ret = boot_fn(BOOTM_STATE_OS_PREP, &bmi);
        }
 
 #ifdef CONFIG_TRACE
@@ -1080,10 +1120,12 @@ err:
        if (iflag)
                enable_interrupts();
 
-       if (ret == BOOTM_ERR_UNIMPLEMENTED)
+       if (ret == BOOTM_ERR_UNIMPLEMENTED) {
                bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
-       else if (ret == BOOTM_ERR_RESET)
-               do_reset(cmdtp, flag, argc, argv);
+       } else if (ret == BOOTM_ERR_RESET) {
+               printf("Resetting the board...\n");
+               reset_cpu();
+       }
 
        return ret;
 }
@@ -1125,6 +1167,14 @@ int bootm_boot_start(ulong addr, const char *cmdline)
        return ret;
 }
 
+void bootm_init(struct bootm_info *bmi)
+{
+       memset(bmi, '\0', sizeof(struct bootm_info));
+       bmi->boot_progress = true;
+       if (IS_ENABLED(CONFIG_CMD_BOOTM))
+               bmi->images = &images;
+}
+
 /**
  * switch_to_non_secure_mode() - switch to non-secure mode
  *
This page took 0.043528 seconds and 4 git commands to generate.