vbe: Split out reading a FIT into the common file
authorSimon Glass <sjg@chromium.org>
Thu, 16 Jan 2025 01:27:10 +0000 (18:27 -0700)
committerTom Rini <trini@konsulko.com>
Wed, 22 Jan 2025 15:47:49 +0000 (09:47 -0600)
Loading a FIT is useful for other VBE methods, such as ABrec. Create a
new function to handling reading it.

Signed-off-by: Simon Glass <sjg@chromium.org>
boot/vbe_common.c
boot/vbe_common.h
boot/vbe_simple_fw.c

index 672878f..0105d55 100644 (file)
@@ -6,7 +6,11 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#include <bootstage.h>
+#include <dm.h>
 #include <blk.h>
+#include <image.h>
+#include <mapmem.h>
 #include <memalign.h>
 #include <spl.h>
 #include <u-boot/crc.h>
@@ -100,3 +104,106 @@ int vbe_read_nvdata(struct udevice *blk, ulong offset, ulong size, u8 *buf)
 
        return 0;
 }
+
+int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
+                ulong *load_addrp, ulong *lenp, char **namep)
+{
+       ALLOC_CACHE_ALIGN_BUFFER(u8, sbuf, MMC_MAX_BLOCK_LEN);
+       ulong size, blknum, addr, len, load_addr, num_blks;
+       const char *fit_uname, *fit_uname_config;
+       struct bootm_headers images = {};
+       enum image_phase_t phase;
+       struct blk_desc *desc;
+       int node, ret;
+       void *buf;
+
+       desc = dev_get_uclass_plat(blk);
+
+       /* read in one block to find the FIT size */
+       blknum =  area_offset / desc->blksz;
+       log_debug("read at %lx, blknum %lx\n", area_offset, blknum);
+       ret = blk_read(blk, blknum, 1, sbuf);
+       if (ret < 0)
+               return log_msg_ret("rd", ret);
+
+       ret = fdt_check_header(sbuf);
+       if (ret < 0)
+               return log_msg_ret("fdt", -EINVAL);
+       size = fdt_totalsize(sbuf);
+       if (size > area_size)
+               return log_msg_ret("fdt", -E2BIG);
+       log_debug("FIT size %lx\n", size);
+
+       /*
+        * Load the FIT into the SPL memory. This is typically a FIT with
+        * external data, so this is quite small, perhaps a few KB.
+        */
+       addr = CONFIG_VAL(TEXT_BASE);
+       buf = map_sysmem(addr, size);
+       num_blks = DIV_ROUND_UP(size, desc->blksz);
+       log_debug("read %lx, %lx blocks to %lx / %p\n", size, num_blks, addr,
+                 buf);
+       ret = blk_read(blk, blknum, num_blks, buf);
+       if (ret < 0)
+               return log_msg_ret("rd", ret);
+
+       /* figure out the phase to load */
+       phase = IS_ENABLED(CONFIG_VPL_BUILD) ? IH_PHASE_SPL : IH_PHASE_U_BOOT;
+
+       /*
+        * Load the image from the FIT. We ignore any load-address information
+        * so in practice this simply locates the image in the external-data
+        * region and returns its address and size. Since we only loaded the FIT
+        * itself, only a part of the image will be present, at best.
+        */
+       fit_uname = NULL;
+       fit_uname_config = NULL;
+       log_debug("loading FIT\n");
+       ret = fit_image_load(&images, addr, &fit_uname, &fit_uname_config,
+                            IH_ARCH_SANDBOX, image_ph(phase, IH_TYPE_FIRMWARE),
+                            BOOTSTAGE_ID_FIT_SPL_START, FIT_LOAD_IGNORED,
+                            &load_addr, &len);
+       if (ret < 0)
+               return log_msg_ret("ld", ret);
+       node = ret;
+       log_debug("loaded to %lx\n", load_addr);
+
+       /* For FIT external data, read in the external data */
+       if (load_addr + len > addr + size) {
+               ulong base, full_size;
+               void *base_buf;
+
+               /* Find the start address to load from */
+               base = ALIGN_DOWN(load_addr, desc->blksz);
+
+               /*
+                * Get the total number of bytes to load, taking care of
+                * block alignment
+                */
+               full_size = load_addr + len - base;
+
+               /*
+                * Get the start block number, number of blocks and the address
+                * to load to, then load the blocks
+                */
+               blknum = (area_offset + base - addr) / desc->blksz;
+               num_blks = DIV_ROUND_UP(full_size, desc->blksz);
+               base_buf = map_sysmem(base, full_size);
+               ret = blk_read(blk, blknum, num_blks, base_buf);
+               log_debug("read %lx %lx, %lx blocks to %lx / %p: ret=%d\n",
+                         blknum, full_size, num_blks, base, base_buf, ret);
+               if (ret < 0)
+                       return log_msg_ret("rd", ret);
+       }
+       if (load_addrp)
+               *load_addrp = load_addr;
+       if (lenp)
+               *lenp = len;
+       if (namep) {
+               *namep = strdup(fdt_get_name(buf, node, NULL));
+               if (!namep)
+                       return log_msg_ret("nam", -ENOMEM);
+       }
+
+       return 0;
+}
index 37a8133..bfa3390 100644 (file)
@@ -94,4 +94,32 @@ int vbe_read_version(struct udevice *blk, ulong offset, char *version,
  */
 int vbe_read_nvdata(struct udevice *blk, ulong offset, ulong size, u8 *buf);
 
+/**
+ * vbe_read_fit() - Read an image from a FIT
+ *
+ * This handles most of the VBE logic for reading from a FIT. It reads the FIT
+ * metadata, decides which image to load and loads it to a suitable address,
+ * ready for jumping to the next phase of VBE.
+ *
+ * This supports transition from VPL to SPL as well as SPL to U-Boot proper. For
+ * now, TPL->VPL is not supported.
+ *
+ * Both embedded and external data are supported for the FIT
+ *
+ * @blk: Block device containing FIT
+ * @area_offset: Byte offset of the VBE area in @blk containing the FIT
+ * @area_size: Size of the VBE area
+ * @load_addrp: If non-null, returns the address where the image was loaded
+ * @lenp: If non-null, returns the size of the image loaded, in bytes
+ * @namep: If non-null, returns the name of the FIT-image node that was loaded
+ *     (allocated by this function)
+ * Return: 0 if OK, -EINVAL if the area does not contain an FDT (the underlying
+ * format for FIT), -E2BIG if the FIT extends past @area_size, -ENOMEM if there
+ * was not space to allocate the image-node name, other error if a read error
+ * occurred (see blk_read()), or something went wrong with the actually
+ * FIT-parsing (see fit_image_load()).
+ */
+int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
+                ulong *load_addrp, ulong *lenp, char **namep);
+
 #endif /* __VBE_ABREC_H */
index da9701f..0bf25cc 100644 (file)
  */
 int vbe_simple_read_bootflow_fw(struct udevice *dev, struct bootflow *bflow)
 {
-       ALLOC_CACHE_ALIGN_BUFFER(u8, sbuf, MMC_MAX_BLOCK_LEN);
        struct udevice *media = dev_get_parent(bflow->dev);
        struct udevice *meth = bflow->method;
        struct simple_priv *priv = dev_get_priv(meth);
-       const char *fit_uname, *fit_uname_config;
-       struct bootm_headers images = {};
-       ulong offset, size, blknum, addr, len, load_addr, num_blks;
-       enum image_phase_t phase;
-       struct blk_desc *desc;
+       ulong len, load_addr;
        struct udevice *blk;
-       int node, ret;
-       void *buf;
+       int ret;
 
        log_debug("media=%s\n", media->name);
        ret = blk_get_from_parent(media, &blk);
        if (ret)
                return log_msg_ret("med", ret);
        log_debug("blk=%s\n", blk->name);
-       desc = dev_get_uclass_plat(blk);
-
-       offset = priv->area_start + priv->skip_offset;
-
-       /* read in one block to find the FIT size */
-       blknum =  offset / desc->blksz;
-       log_debug("read at %lx, blknum %lx\n", offset, blknum);
-       ret = blk_read(blk, blknum, 1, sbuf);
-       if (ret < 0)
-               return log_msg_ret("rd", ret);
-
-       ret = fdt_check_header(sbuf);
-       if (ret < 0)
-               return log_msg_ret("fdt", -EINVAL);
-       size = fdt_totalsize(sbuf);
-       if (size > priv->area_size)
-               return log_msg_ret("fdt", -E2BIG);
-       log_debug("FIT size %lx\n", size);
-
-       /*
-        * Load the FIT into the SPL memory. This is typically a FIT with
-        * external data, so this is quite small, perhaps a few KB.
-        */
-       addr = CONFIG_VAL(TEXT_BASE);
-       buf = map_sysmem(addr, size);
-       num_blks = DIV_ROUND_UP(size, desc->blksz);
-       log_debug("read %lx, %lx blocks to %lx / %p\n", size, num_blks, addr,
-                 buf);
-       ret = blk_read(blk, blknum, num_blks, buf);
-       if (ret < 0)
-               return log_msg_ret("rd", ret);
 
-       /* figure out the phase to load */
-       phase = IS_ENABLED(CONFIG_VPL_BUILD) ? IH_PHASE_SPL : IH_PHASE_U_BOOT;
-
-       /*
-        * Load the image from the FIT. We ignore any load-address information
-        * so in practice this simply locates the image in the external-data
-        * region and returns its address and size. Since we only loaded the FIT
-        * itself, only a part of the image will be present, at best.
-        */
-       fit_uname = NULL;
-       fit_uname_config = NULL;
-       log_debug("loading FIT\n");
-       ret = fit_image_load(&images, addr, &fit_uname, &fit_uname_config,
-                            IH_ARCH_SANDBOX, image_ph(phase, IH_TYPE_FIRMWARE),
-                            BOOTSTAGE_ID_FIT_SPL_START, FIT_LOAD_IGNORED,
-                            &load_addr, &len);
-       if (ret < 0)
-               return log_msg_ret("ld", ret);
-       node = ret;
-       log_debug("loaded to %lx\n", load_addr);
-
-       /* For FIT external data, read in the external data */
-       if (load_addr + len > addr + size) {
-               ulong base, full_size;
-               void *base_buf;
-
-               /* Find the start address to load from */
-               base = ALIGN_DOWN(load_addr, desc->blksz);
-
-               /*
-                * Get the total number of bytes to load, taking care of
-                * block alignment
-                */
-               full_size = load_addr + len - base;
-
-               /*
-                * Get the start block number, number of blocks and the address
-                * to load to, then load the blocks
-                */
-               blknum = (offset + base - addr) / desc->blksz;
-               num_blks = DIV_ROUND_UP(full_size, desc->blksz);
-               base_buf = map_sysmem(base, full_size);
-               ret = blk_read(blk, blknum, num_blks, base_buf);
-               log_debug("read %lx %lx, %lx blocks to %lx / %p: ret=%d\n",
-                         blknum, full_size, num_blks, base, base_buf, ret);
-               if (ret < 0)
-                       return log_msg_ret("rd", ret);
-       }
+       ret = vbe_read_fit(blk, priv->area_start + priv->skip_offset,
+                          priv->area_size, &load_addr, &len, &bflow->name);
 
        /* set up the bootflow with the info we obtained */
-       bflow->name = strdup(fdt_get_name(buf, node, NULL));
-       if (!bflow->name)
-               return log_msg_ret("name", -ENOMEM);
        bflow->blk = blk;
        bflow->buf = map_sysmem(load_addr, len);
        bflow->size = len;