[PATCH 02/15] vbe: Split out reading a FIT into a common file
Simon Glass
sjg at chromium.org
Thu Jan 9 13:29:57 CET 2025
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 at chromium.org>
---
boot/vbe_common.c | 103 +++++++++++++++++++++++++++++++++++++++++++
boot/vbe_common.h | 28 ++++++++++++
boot/vbe_simple_fw.c | 94 ++-------------------------------------
3 files changed, 135 insertions(+), 90 deletions(-)
diff --git a/boot/vbe_common.c b/boot/vbe_common.c
index 5f31cde0288..c009337ef3f 100644
--- a/boot/vbe_common.c
+++ b/boot/vbe_common.c
@@ -18,6 +18,109 @@
#include <u-boot/crc.h>
#include "vbe_common.h"
+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;
+}
+
int vbe_read_version(struct udevice *blk, ulong offset, char *version,
int max_size)
{
diff --git a/boot/vbe_common.h b/boot/vbe_common.h
index df133fbf05f..403391ff1ea 100644
--- a/boot/vbe_common.h
+++ b/boot/vbe_common.h
@@ -140,4 +140,32 @@ int vbe_read_version(struct udevice *blk, ulong offset, char *version,
*/
int vbe_get_blk(const char *storage, struct udevice **blkp);
+/**
+ * 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 */
diff --git a/boot/vbe_simple_fw.c b/boot/vbe_simple_fw.c
index da9701f9eb9..0bf25ccad23 100644
--- a/boot/vbe_simple_fw.c
+++ b/boot/vbe_simple_fw.c
@@ -38,109 +38,23 @@
*/
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;
--
2.34.1
More information about the U-Boot
mailing list