[PATCH 1/3] fit_dtb: relocate whole fit dtb image instead of selected dtb only

Mikhail Kshevetskiy mikhail.kshevetskiy at iopsys.eu
Thu Jun 27 13:35:44 CEST 2024


U-Boot with linked fit dtb image may be loaded by a bootloader to
a low memory. On a later stage U-Boot will relocate itself and used
dtb.

There is no problem until we decide to reselect dtb on a later stage.
In this case dtb placed in the low memory address may be selected.
But this data can be overwritted by flash reading or network file
transfer. Thus we will use damaged dtb.

To fix it move the whole fit dtb image instead of just used dtb.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
---
 boot/boot_fit.c    | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 common/board_f.c   | 34 ++++++++++++++++++++++++++++----
 include/boot_fit.h |  8 ++++++++
 3 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/boot/boot_fit.c b/boot/boot_fit.c
index 9d394126563..e9aac61c6a8 100644
--- a/boot/boot_fit.c
+++ b/boot/boot_fit.c
@@ -13,6 +13,54 @@
 #include <log.h>
 #include <linux/libfdt.h>
 
+int dtb_fit_image_size(const void *fit)
+{
+	struct legacy_img_hdr	*header;
+	int			fdt_size, blob_total_size;
+	int			images, conf, node;
+	int			blob_offset, blob_len;
+
+	header = (struct legacy_img_hdr *)fit;
+	if (image_get_magic(header) != FDT_MAGIC) {
+		debug("No FIT image appended to U-Boot\n");
+		return -EINVAL;
+	}
+
+	fdt_size = fdt_totalsize(fit);
+	fdt_size = (fdt_size + 3) & ~3;
+
+	conf = fdt_path_offset(fit, FIT_CONFS_PATH);
+	if (conf < 0) {
+		debug("%s: Cannot find /configurations node: %d\n", __func__, conf);
+		return -EINVAL;
+	}
+
+	images = fdt_path_offset(fit, FIT_IMAGES_PATH);
+	if (images < 0) {
+		debug("%s: Cannot find /images node: %d\n", __func__, images);
+		return -EINVAL;
+	}
+
+	blob_total_size = 0;
+	node = fdt_first_subnode(fit, images);
+	while (node >= 0) {
+		blob_offset = fdt_getprop_u32(fit, node, "data-offset");
+		if (blob_offset == FDT_ERROR)
+			return -ENOENT;
+
+		blob_len = fdt_getprop_u32(fit, node, "data-size");
+		if (blob_len < 0)
+			return blob_len;
+
+		if (blob_total_size < blob_offset + blob_len)
+			blob_total_size = blob_offset + blob_len;
+
+		node = fdt_next_subnode(fit, node);
+	}
+
+	return fdt_size + blob_total_size;
+}
+
 static int fdt_offset(const void *fit)
 {
 	int images, node, fdt_len, fdt_node, fdt_offset;
diff --git a/common/board_f.c b/common/board_f.c
index 039d6d712d0..89a1a0b563c 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -49,6 +49,7 @@
 #include <dm/root.h>
 #include <linux/errno.h>
 #include <linux/log2.h>
+#include <boot_fit.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -574,7 +575,24 @@ static int reserve_fdt(void)
 		 * section, then it will be relocated with other data.
 		 */
 		if (gd->fdt_blob) {
-			gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32);
+			if (gd_multi_dtb_fit()) {
+				int dtb_fit_size = dtb_fit_image_size(gd_multi_dtb_fit());
+
+				if (dtb_fit_size < 0) {
+					/*
+					 * Fallback to default:
+					 *   - switch to non-multi dtb case (single dtb)
+					 *   - reserve space for current dtb only
+					 */
+					gd_set_multi_dtb_fit(NULL);
+					gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32);
+				} else {
+					/* reserve space for the whole dtb fit image */
+					gd->fdt_size = ALIGN(dtb_fit_size, 32);
+				}
+			} else {
+				gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32);
+			}
 
 			gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size);
 			gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
@@ -668,9 +686,17 @@ static int reloc_fdt(void)
 {
 	if (!IS_ENABLED(CONFIG_OF_EMBED)) {
 		if (gd->new_fdt) {
-			memcpy(gd->new_fdt, gd->fdt_blob,
-			       fdt_totalsize(gd->fdt_blob));
-			gd->fdt_blob = gd->new_fdt;
+			if (gd_multi_dtb_fit()) {
+				memcpy(gd->new_fdt, gd_multi_dtb_fit(),
+				       dtb_fit_image_size(gd_multi_dtb_fit()));
+				gd->fdt_blob = gd->new_fdt + (gd->fdt_blob -
+					       gd_multi_dtb_fit());
+				gd_set_multi_dtb_fit(gd->new_fdt);
+			} else {
+				memcpy(gd->new_fdt, gd->fdt_blob,
+				       fdt_totalsize(gd->fdt_blob));
+				gd->fdt_blob = gd->new_fdt;
+			}
 		}
 	}
 
diff --git a/include/boot_fit.h b/include/boot_fit.h
index 092cfb0b7fb..bf146286a70 100644
--- a/include/boot_fit.h
+++ b/include/boot_fit.h
@@ -4,6 +4,14 @@
  * Written by Franklin Cooper Jr. <fcooper at ti.com>
  */
 
+/**
+ * dtb_fit_image_size - Find a size of a DTB FIT image
+ * @fit:	pointer to the FIT image
+ *
+ * Return: a size of DTB FIT image (negative value on error)
+ */
+int dtb_fit_image_size(const void *fit);
+
 /**
  * locate_dtb_in_fit - Find a DTB matching the board in a FIT image
  * @fit:	pointer to the FIT image
-- 
2.43.0



More information about the U-Boot mailing list