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.kshevets...@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. <fcoo...@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

Reply via email to