Merge branch '2020-06-03-misc-bugfixes'
[oweals/u-boot.git] / tools / fit_image.c
index 4dc8bd8862454598d1bf5383b259707a06cfccba..a082d9386d200d095753eae45fec826b1a718269 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2008 Semihalf
  *
  *             some functions added to address abstraction
  *
  * All rights reserved.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include "imagetool.h"
 #include "fit_common.h"
 #include "mkimage.h"
 #include <image.h>
+#include <string.h>
 #include <stdarg.h>
 #include <version.h>
 #include <u-boot/crc.h>
@@ -34,7 +34,8 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
        void *ptr;
        int ret = 0;
 
-       tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true);
+       tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true,
+                      false);
        if (tfd < 0)
                return -EIO;
 
@@ -42,7 +43,8 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
                struct stat dest_sbuf;
 
                destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
-                                 &dest_blob, &dest_sbuf, false);
+                                 &dest_blob, &dest_sbuf, false,
+                                 false);
                if (destfd < 0) {
                        ret = -EIO;
                        goto err_keydest;
@@ -52,15 +54,25 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
 
        /* for first image creation, add a timestamp at offset 0 i.e., root  */
        if (params->datafile) {
-               time_t time = imagetool_get_source_date(params, sbuf.st_mtime);
+               time_t time = imagetool_get_source_date(params->cmdname,
+                                                       sbuf.st_mtime);
                ret = fit_set_timestamp(ptr, 0, time);
        }
 
+       if (!ret) {
+               ret = fit_cipher_data(params->keydir, dest_blob, ptr,
+                                     params->comment,
+                                     params->require_keys,
+                                     params->engine_id,
+                                     params->cmdname);
+       }
+
        if (!ret) {
                ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
                                                params->comment,
                                                params->require_keys,
-                                               params->engine_id);
+                                               params->engine_id,
+                                               params->cmdname);
        }
 
        if (dest_blob) {
@@ -71,7 +83,6 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
 err_keydest:
        munmap(ptr, sbuf.st_size);
        close(tfd);
-
        return ret;
 }
 
@@ -100,7 +111,7 @@ static int fit_calc_size(struct image_tool_params *params)
                if (size < 0)
                        return -1;
 
-               /* Add space for properties */
+               /* Add space for properties and hash node */
                total_size += size + 300;
        }
 
@@ -181,11 +192,23 @@ static void get_basename(char *str, int size, const char *fname)
        str[len] = '\0';
 }
 
+/**
+ * add_crc_node() - Add a hash node to request a CRC checksum for an image
+ *
+ * @fdt: Device tree to add to (in sequential-write mode)
+ */
+static void add_crc_node(void *fdt)
+{
+       fdt_begin_node(fdt, "hash-1");
+       fdt_property_string(fdt, FIT_ALGO_PROP, "crc32");
+       fdt_end_node(fdt);
+}
+
 /**
  * fit_write_images() - Write out a list of images to the FIT
  *
  * We always include the main image (params->datafile). If there are device
- * tree files, we include an fdt@ node for each of those too.
+ * tree files, we include an fdt- node for each of those too.
  */
 static int fit_write_images(struct image_tool_params *params, char *fdt)
 {
@@ -199,25 +222,27 @@ static int fit_write_images(struct image_tool_params *params, char *fdt)
 
        /* First the main image */
        typename = genimg_get_type_short_name(params->fit_image_type);
-       snprintf(str, sizeof(str), "%s@1", typename);
+       snprintf(str, sizeof(str), "%s-1", typename);
        fdt_begin_node(fdt, str);
-       fdt_property_string(fdt, "description", params->imagename);
-       fdt_property_string(fdt, "type", typename);
-       fdt_property_string(fdt, "arch",
+       fdt_property_string(fdt, FIT_DESC_PROP, params->imagename);
+       fdt_property_string(fdt, FIT_TYPE_PROP, typename);
+       fdt_property_string(fdt, FIT_ARCH_PROP,
                            genimg_get_arch_short_name(params->arch));
-       fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
-       fdt_property_string(fdt, "compression",
+       fdt_property_string(fdt, FIT_OS_PROP,
+                           genimg_get_os_short_name(params->os));
+       fdt_property_string(fdt, FIT_COMP_PROP,
                            genimg_get_comp_short_name(params->comp));
-       fdt_property_u32(fdt, "load", params->addr);
-       fdt_property_u32(fdt, "entry", params->ep);
+       fdt_property_u32(fdt, FIT_LOAD_PROP, params->addr);
+       fdt_property_u32(fdt, FIT_ENTRY_PROP, params->ep);
 
        /*
         * Put data last since it is large. SPL may only load the first part
         * of the DT, so this way it can access all the above fields.
         */
-       ret = fdt_property_file(params, fdt, "data", params->datafile);
+       ret = fdt_property_file(params, fdt, FIT_DATA_PROP, params->datafile);
        if (ret)
                return ret;
+       add_crc_node(fdt);
        fdt_end_node(fdt);
 
        /* Now the device tree files if available */
@@ -225,33 +250,40 @@ static int fit_write_images(struct image_tool_params *params, char *fdt)
        for (cont = params->content_head; cont; cont = cont->next) {
                if (cont->type != IH_TYPE_FLATDT)
                        continue;
-               snprintf(str, sizeof(str), "%s@%d", FIT_FDT_PROP, ++upto);
+               typename = genimg_get_type_short_name(cont->type);
+               snprintf(str, sizeof(str), "%s-%d", FIT_FDT_PROP, ++upto);
                fdt_begin_node(fdt, str);
 
                get_basename(str, sizeof(str), cont->fname);
-               fdt_property_string(fdt, "description", str);
-               ret = fdt_property_file(params, fdt, "data", cont->fname);
+               fdt_property_string(fdt, FIT_DESC_PROP, str);
+               ret = fdt_property_file(params, fdt, FIT_DATA_PROP,
+                                       cont->fname);
                if (ret)
                        return ret;
-               fdt_property_string(fdt, "type", typename);
-               fdt_property_string(fdt, "arch",
+               fdt_property_string(fdt, FIT_TYPE_PROP, typename);
+               fdt_property_string(fdt, FIT_ARCH_PROP,
                                    genimg_get_arch_short_name(params->arch));
-               fdt_property_string(fdt, "compression",
+               fdt_property_string(fdt, FIT_COMP_PROP,
                                    genimg_get_comp_short_name(IH_COMP_NONE));
+               add_crc_node(fdt);
                fdt_end_node(fdt);
        }
 
        /* And a ramdisk file if available */
        if (params->fit_ramdisk) {
-               fdt_begin_node(fdt, FIT_RAMDISK_PROP "@1");
+               fdt_begin_node(fdt, FIT_RAMDISK_PROP "-1");
 
-               fdt_property_string(fdt, "type", FIT_RAMDISK_PROP);
-               fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
+               fdt_property_string(fdt, FIT_TYPE_PROP, FIT_RAMDISK_PROP);
+               fdt_property_string(fdt, FIT_OS_PROP,
+                                   genimg_get_os_short_name(params->os));
+               fdt_property_string(fdt, FIT_ARCH_PROP,
+                                   genimg_get_arch_short_name(params->arch));
 
-               ret = fdt_property_file(params, fdt, "data", params->fit_ramdisk);
+               ret = fdt_property_file(params, fdt, FIT_DATA_PROP,
+                                       params->fit_ramdisk);
                if (ret)
                        return ret;
-
+               add_crc_node(fdt);
                fdt_end_node(fdt);
        }
 
@@ -277,41 +309,42 @@ static void fit_write_configs(struct image_tool_params *params, char *fdt)
        int upto;
 
        fdt_begin_node(fdt, "configurations");
-       fdt_property_string(fdt, "default", "conf@1");
+       fdt_property_string(fdt, FIT_DEFAULT_PROP, "conf-1");
 
        upto = 0;
        for (cont = params->content_head; cont; cont = cont->next) {
                if (cont->type != IH_TYPE_FLATDT)
                        continue;
                typename = genimg_get_type_short_name(cont->type);
-               snprintf(str, sizeof(str), "conf@%d", ++upto);
+               snprintf(str, sizeof(str), "conf-%d", ++upto);
                fdt_begin_node(fdt, str);
 
                get_basename(str, sizeof(str), cont->fname);
-               fdt_property_string(fdt, "description", str);
+               fdt_property_string(fdt, FIT_DESC_PROP, str);
 
                typename = genimg_get_type_short_name(params->fit_image_type);
-               snprintf(str, sizeof(str), "%s@1", typename);
+               snprintf(str, sizeof(str), "%s-1", typename);
                fdt_property_string(fdt, typename, str);
+               fdt_property_string(fdt, FIT_LOADABLE_PROP, str);
 
                if (params->fit_ramdisk)
                        fdt_property_string(fdt, FIT_RAMDISK_PROP,
-                                           FIT_RAMDISK_PROP "@1");
+                                           FIT_RAMDISK_PROP "-1");
 
-               snprintf(str, sizeof(str), FIT_FDT_PROP "@%d", upto);
+               snprintf(str, sizeof(str), FIT_FDT_PROP "-%d", upto);
                fdt_property_string(fdt, FIT_FDT_PROP, str);
                fdt_end_node(fdt);
        }
 
        if (!upto) {
-               fdt_begin_node(fdt, "conf@1");
+               fdt_begin_node(fdt, "conf-1");
                typename = genimg_get_type_short_name(params->fit_image_type);
-               snprintf(str, sizeof(str), "%s@1", typename);
+               snprintf(str, sizeof(str), "%s-1", typename);
                fdt_property_string(fdt, typename, str);
 
                if (params->fit_ramdisk)
                        fdt_property_string(fdt, FIT_RAMDISK_PROP,
-                                           FIT_RAMDISK_PROP "@1");
+                                           FIT_RAMDISK_PROP "-1");
 
                fdt_end_node(fdt);
        }
@@ -328,7 +361,7 @@ static int fit_build_fdt(struct image_tool_params *params, char *fdt, int size)
                return ret;
        fdt_finish_reservemap(fdt);
        fdt_begin_node(fdt, "");
-       fdt_property_strf(fdt, "description",
+       fdt_property_strf(fdt, FIT_DESC_PROP,
                          "%s image with one or more FDT blobs",
                          genimg_get_type_name(params->fit_image_type));
        fdt_property_strf(fdt, "creator", "U-Boot mkimage %s", PLAIN_VERSION);
@@ -372,7 +405,7 @@ static int fit_build(struct image_tool_params *params, const char *fname)
        if (fd < 0) {
                fprintf(stderr, "%s: Can't open %s: %s\n",
                        params->cmdname, fname, strerror(errno));
-               goto err;
+               goto err_buf;
        }
        ret = write(fd, buf, size);
        if (ret != size) {
@@ -404,7 +437,7 @@ err_buf:
  */
 static int fit_extract_data(struct image_tool_params *params, const char *fname)
 {
-       void *buf;
+       void *buf = NULL;
        int buf_ptr;
        int fit_size, new_size;
        int fd;
@@ -413,26 +446,33 @@ static int fit_extract_data(struct image_tool_params *params, const char *fname)
        int ret;
        int images;
        int node;
+       int image_number;
+       int align_size;
 
-       fd = mmap_fdt(params->cmdname, fname, 0, &fdt, &sbuf, false);
+       align_size = params->bl_len ? params->bl_len : 4;
+       fd = mmap_fdt(params->cmdname, fname, 0, &fdt, &sbuf, false, false);
        if (fd < 0)
                return -EIO;
        fit_size = fdt_totalsize(fdt);
 
-       /* Allocate space to hold the image data we will extract */
-       buf = malloc(fit_size);
-       if (!buf) {
-               ret = -ENOMEM;
-               goto err_munmap;
-       }
-       buf_ptr = 0;
-
        images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
        if (images < 0) {
                debug("%s: Cannot find /images node: %d\n", __func__, images);
                ret = -EINVAL;
                goto err_munmap;
        }
+       image_number = fdtdec_get_child_count(fdt, images);
+
+       /*
+        * Allocate space to hold the image data we will extract,
+        * extral space allocate for image alignment to prevent overflow.
+        */
+       buf = malloc(fit_size + (align_size * image_number));
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err_munmap;
+       }
+       buf_ptr = 0;
 
        for (node = fdt_first_subnode(fdt, images);
             node >= 0;
@@ -440,36 +480,37 @@ static int fit_extract_data(struct image_tool_params *params, const char *fname)
                const char *data;
                int len;
 
-               data = fdt_getprop(fdt, node, "data", &len);
+               data = fdt_getprop(fdt, node, FIT_DATA_PROP, &len);
                if (!data)
                        continue;
                memcpy(buf + buf_ptr, data, len);
                debug("Extracting data size %x\n", len);
 
-               ret = fdt_delprop(fdt, node, "data");
+               ret = fdt_delprop(fdt, node, FIT_DATA_PROP);
                if (ret) {
                        ret = -EPERM;
                        goto err_munmap;
                }
                if (params->external_offset > 0) {
                        /* An external offset positions the data absolutely. */
-                       fdt_setprop_u32(fdt, node, "data-position",
+                       fdt_setprop_u32(fdt, node, FIT_DATA_POSITION_PROP,
                                        params->external_offset + buf_ptr);
                } else {
-                       fdt_setprop_u32(fdt, node, "data-offset", buf_ptr);
+                       fdt_setprop_u32(fdt, node, FIT_DATA_OFFSET_PROP,
+                                       buf_ptr);
                }
-               fdt_setprop_u32(fdt, node, "data-size", len);
-
-               buf_ptr += (len + 3) & ~3;
+               fdt_setprop_u32(fdt, node, FIT_DATA_SIZE_PROP, len);
+               buf_ptr += ALIGN(len, align_size);
        }
 
        /* Pack the FDT and place the data after it */
        fdt_pack(fdt);
 
+       new_size = fdt_totalsize(fdt);
+       new_size = ALIGN(new_size, align_size);
+       fdt_set_totalsize(fdt, new_size);
        debug("Size reduced from %x to %x\n", fit_size, fdt_totalsize(fdt));
        debug("External data size %x\n", buf_ptr);
-       new_size = fdt_totalsize(fdt);
-       new_size = (new_size + 3) & ~3;
        munmap(fdt, sbuf.st_size);
 
        if (ftruncate(fd, new_size)) {
@@ -501,14 +542,14 @@ static int fit_extract_data(struct image_tool_params *params, const char *fname)
                ret = -EIO;
                goto err;
        }
+       free(buf);
        close(fd);
        return 0;
 
 err_munmap:
        munmap(fdt, sbuf.st_size);
 err:
-       if (buf)
-               free(buf);
+       free(buf);
        close(fd);
        return ret;
 }
@@ -523,11 +564,11 @@ static int fit_import_data(struct image_tool_params *params, const char *fname)
        int images;
        int node;
 
-       fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false);
+       fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false, false);
        if (fd < 0)
                return -EIO;
        fit_size = fdt_totalsize(old_fdt);
-       data_base = (fit_size + 3) & ~3;
+       data_base = ALIGN(fit_size, 4);
 
        /* Allocate space to hold the new FIT */
        size = sbuf.st_size + 16384;
@@ -536,21 +577,21 @@ static int fit_import_data(struct image_tool_params *params, const char *fname)
                fprintf(stderr, "%s: Failed to allocate memory (%d bytes)\n",
                        __func__, size);
                ret = -ENOMEM;
-               goto err;
+               goto err_munmap;
        }
        ret = fdt_open_into(old_fdt, fdt, size);
        if (ret) {
                debug("%s: Failed to expand FIT: %s\n", __func__,
                      fdt_strerror(errno));
                ret = -EINVAL;
-               goto err;
+               goto err_munmap;
        }
 
        images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
        if (images < 0) {
                debug("%s: Cannot find /images node: %d\n", __func__, images);
                ret = -EINVAL;
-               goto err;
+               goto err_munmap;
        }
 
        for (node = fdt_first_subnode(fdt, images);
@@ -571,11 +612,13 @@ static int fit_import_data(struct image_tool_params *params, const char *fname)
                        debug("%s: Failed to write property: %s\n", __func__,
                              fdt_strerror(ret));
                        ret = -EINVAL;
-                       goto err;
+                       goto err_munmap;
                }
        }
 
        munmap(old_fdt, sbuf.st_size);
+
+       /* Close the old fd so we can re-use it. */
        close(fd);
 
        /* Pack the FDT and place the data after it */
@@ -588,8 +631,8 @@ static int fit_import_data(struct image_tool_params *params, const char *fname)
        if (fd < 0) {
                fprintf(stderr, "%s: Can't open %s: %s\n",
                        params->cmdname, fname, strerror(errno));
-               free(fdt);
-               return -EIO;
+               ret = -EIO;
+               goto err;
        }
        if (write(fd, fdt, new_size) != new_size) {
                debug("%s: Failed to write external data to file %s\n",
@@ -598,14 +641,74 @@ static int fit_import_data(struct image_tool_params *params, const char *fname)
                goto err;
        }
 
-       ret = 0;
+       free(fdt);
+       close(fd);
+       return 0;
 
+err_munmap:
+       munmap(old_fdt, sbuf.st_size);
 err:
        free(fdt);
        close(fd);
        return ret;
 }
 
+static int copyfile(const char *src, const char *dst)
+{
+       int fd_src = -1, fd_dst = -1;
+       void *buf = NULL;
+       ssize_t size;
+       size_t count;
+       int ret = -1;
+
+       fd_src = open(src, O_RDONLY);
+       if (fd_src < 0) {
+               printf("Can't open file %s (%s)\n", src, strerror(errno));
+               goto out;
+       }
+
+       fd_dst = open(dst, O_WRONLY | O_CREAT, 0666);
+       if (fd_dst < 0) {
+               printf("Can't open file %s (%s)\n", dst, strerror(errno));
+               goto out;
+       }
+
+       buf = malloc(512);
+       if (!buf) {
+               printf("Can't allocate buffer to copy file\n");
+               goto out;
+       }
+
+       while (1) {
+               size = read(fd_src, buf, 512);
+               if (size < 0) {
+                       printf("Can't read file %s\n", src);
+                       goto out;
+               }
+               if (!size)
+                       break;
+
+               count = size;
+               size = write(fd_dst, buf, count);
+               if (size < 0) {
+                       printf("Can't write file %s\n", dst);
+                       goto out;
+               }
+       }
+
+       ret = 0;
+
+ out:
+       if (fd_src >= 0)
+               close(fd_src);
+       if (fd_dst >= 0)
+               close(fd_dst);
+       if (buf)
+               free(buf);
+
+       return ret;
+}
+
 /**
  * fit_handle_file - main FIT file processing function
  *
@@ -621,6 +724,7 @@ err:
 static int fit_handle_file(struct image_tool_params *params)
 {
        char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
+       char bakfile[MKIMAGE_MAX_TMPFILE_LEN + 4] = {0};
        char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
        size_t size_inc;
        int ret;
@@ -647,14 +751,18 @@ static int fit_handle_file(struct image_tool_params *params)
                }
                *cmd = '\0';
        } else if (params->datafile) {
-               /* dtc -I dts -O dtb -p 500 datafile > tmpfile */
-               snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
-                        MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
+               /* dtc -I dts -O dtb -p 500 -o tmpfile datafile */
+               snprintf(cmd, sizeof(cmd), "%s %s -o \"%s\" \"%s\"",
+                        MKIMAGE_DTC, params->dtc, tmpfile, params->datafile);
                debug("Trying to execute \"%s\"\n", cmd);
        } else {
-               snprintf(cmd, sizeof(cmd), "cp %s %s",
+               snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"",
                         params->imagefile, tmpfile);
        }
+       if (strlen(cmd) >= MKIMAGE_MAX_DTC_CMDLINE_LEN - 1) {
+               fprintf(stderr, "WARNING: command-line for FIT creation might be truncated and will probably fail.\n");
+       }
+
        if (*cmd && system(cmd) == -1) {
                fprintf (stderr, "%s: system(%s) failed: %s\n",
                                params->cmdname, cmd, strerror(errno));
@@ -666,6 +774,14 @@ static int fit_handle_file(struct image_tool_params *params)
        if (ret)
                goto err_system;
 
+       /*
+        * Copy the tmpfile to bakfile, then in the following loop
+        * we copy bakfile to tmpfile. So we always start from the
+        * beginning.
+        */
+       sprintf(bakfile, "%s%s", tmpfile, ".bak");
+       rename(tmpfile, bakfile);
+
        /*
         * Set hashes for images in the blob. Unfortunately we may need more
         * space in either FDT, so keep trying until we succeed.
@@ -677,6 +793,11 @@ static int fit_handle_file(struct image_tool_params *params)
         * steps of this loop is enough to sign with several keys.
         */
        for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) {
+               if (copyfile(bakfile, tmpfile) < 0) {
+                       printf("Can't copy %s to %s\n", bakfile, tmpfile);
+                       ret = -EIO;
+                       break;
+               }
                ret = fit_add_file_data(params, size_inc, tmpfile);
                if (!ret || ret != -ENOSPC)
                        break;
@@ -700,13 +821,16 @@ static int fit_handle_file(struct image_tool_params *params)
                                params->cmdname, tmpfile, params->imagefile,
                                strerror (errno));
                unlink (tmpfile);
+               unlink(bakfile);
                unlink (params->imagefile);
                return EXIT_FAILURE;
        }
+       unlink(bakfile);
        return EXIT_SUCCESS;
 
 err_system:
        unlink(tmpfile);
+       unlink(bakfile);
        return -1;
 }
 
@@ -726,9 +850,14 @@ static int fit_image_extract(
 {
        const void *file_data;
        size_t file_size = 0;
+       int ret;
 
-       /* get the "data" property of component at offset "image_noffset" */
-       fit_image_get_data(fit, image_noffset, &file_data, &file_size);
+       /* get the data address and size of component at offset "image_noffset" */
+       ret = fit_image_get_data_and_size(fit, image_noffset, &file_data, &file_size);
+       if (ret) {
+               fprintf(stderr, "Could not get component information\n");
+               return ret;
+       }
 
        /* save the "file_data" into the file specified by "file_name" */
        return imagetool_save_subimage(file_name, (ulong) file_data, file_size);
@@ -805,9 +934,9 @@ static int fit_check_params(struct image_tool_params *params)
 {
        if (params->auto_its)
                return 0;
-       return  ((params->dflag && (params->fflag || params->lflag)) ||
-               (params->fflag && (params->dflag || params->lflag)) ||
-               (params->lflag && (params->dflag || params->fflag)));
+       return  ((params->dflag && params->fflag) ||
+                (params->fflag && params->lflag) ||
+                (params->lflag && params->dflag));
 }
 
 U_BOOT_IMAGE_TYPE(