When building with external data (-E or -p), an image sharing another
image's data through image-data still receives its own copy of the
payload in the external area. Skip such images while the data is moved
out of the FIT and point them at the referenced image's region
afterwards, through identical data-offset or data-position and
data-size values, so the payload is stored only once. This is the
resolved form the specification describes for external data: both
nodes reference the same region.

An image whose reference did not resolve cannot reach this point,
since fit_resolve_image_data() has already rejected the FIT.

Signed-off-by: Aristo Chen <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---

Changes in v2:
    v2: no changes

 tools/fit_image.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/tools/fit_image.c b/tools/fit_image.c
index f1c3ef3ee66..64e607ea55f 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -813,6 +813,14 @@ static int fit_extract_data(struct image_tool_params 
*params, const char *fname)
                data = fdt_getprop(fdt, node, FIT_DATA_PROP, &len);
                if (!data)
                        continue;
+               if (fdt_getprop(fdt, node, FIT_IMAGE_DATA_PROP, NULL)) {
+                       /*
+                        * This node shares another image's data, which gets
+                        * its own offset below; don't store a second copy
+                        */
+                       len = 0;
+                       continue;
+               }
 
                ret = fit_copy_image_data(fdt, node, buf, buf_ptr, data, &len);
                if (ret)
@@ -849,6 +857,44 @@ static int fit_extract_data(struct image_tool_params 
*params, const char *fname)
        /* Increment 'buf_ptr' for the trailing image. */
        buf_ptr += ALIGN(len, align_size);
 
+       /*
+        * Images sharing another image's data (image-data) reference the
+        * same region instead of storing a second copy
+        */
+       fdt_for_each_subnode(node, fdt, images) {
+               const char *prop, *ref;
+               int target, offset, size;
+
+               ref = fdt_getprop(fdt, node, FIT_IMAGE_DATA_PROP, NULL);
+               if (!ref || !fdt_getprop(fdt, node, FIT_DATA_PROP, NULL))
+                       continue;
+
+               prop = params->external_offset > 0 ? FIT_DATA_POSITION_PROP :
+                       FIT_DATA_OFFSET_PROP;
+               target = fdt_subnode_offset(fdt, images, ref);
+               offset = target >= 0 ? fdtdec_get_int(fdt, target, prop, -1) : 
-1;
+               size = target >= 0 ?
+                       fdtdec_get_int(fdt, target, FIT_DATA_SIZE_PROP, -1) : 
-1;
+               if (offset == -1 || size == -1) {
+                       fprintf(stderr,
+                               "Error: image '%s': no extracted data to share 
from image '%s'\n",
+                               fdt_get_name(fdt, node, NULL), ref);
+                       ret = -EINVAL;
+                       goto err_munmap;
+               }
+
+               ret = fdt_delprop(fdt, node, FIT_DATA_PROP);
+               if (!ret)
+                       ret = fdt_setprop_u32(fdt, node, prop, offset);
+               if (!ret)
+                       ret = fdt_setprop_u32(fdt, node, FIT_DATA_SIZE_PROP,
+                                             size);
+               if (ret) {
+                       ret = -EINVAL;
+                       goto err_munmap;
+               }
+       }
+
        /* Pack the FDT and place the data after it */
        fdt_pack(fdt);
 
-- 
2.43.0

Reply via email to