diff mbox series

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

Message ID 20240627113546.100333-1-mikhail.kshevetskiy@iopsys.eu
State Changes Requested
Headers show
Series [1/3] fit_dtb: relocate whole fit dtb image instead of selected dtb only | expand

Commit Message

Mikhail Kshevetskiy June 27, 2024, 11:35 a.m. UTC
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@iopsys.eu>
---
 boot/boot_fit.c    | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 common/board_f.c   | 34 ++++++++++++++++++++++++++++----
 include/boot_fit.h |  8 ++++++++
 3 files changed, 86 insertions(+), 4 deletions(-)

Comments

Simon Glass June 28, 2024, 7:33 a.m. UTC | #1
Hi Mikhail,

On Thu, 27 Jun 2024 at 12:35, Mikhail Kshevetskiy
<mikhail.kshevetskiy@iopsys.eu> wrote:
>
> 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@iopsys.eu>
> ---
>  boot/boot_fit.c    | 48 ++++++++++++++++++++++++++++++++++++++++++++++
>  common/board_f.c   | 34 ++++++++++++++++++++++++++++----
>  include/boot_fit.h |  8 ++++++++
>  3 files changed, 86 insertions(+), 4 deletions(-)
>

The current mechanism is in reloc_fdt() but it only happens during
relocation. What is the later stage you refer to? Is it after
relocation, or before?

Regards,
Simon
diff mbox series

Patch

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@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