mkimage: Automatically make space in FDT when full
authorSimon Glass <sjg@chromium.org>
Tue, 3 Jun 2014 04:04:53 +0000 (22:04 -0600)
committerTom Rini <trini@ti.com>
Wed, 11 Jun 2014 20:25:46 +0000 (16:25 -0400)
When adding hashes or signatures, the target FDT may be full. Detect this
and automatically try again after making 1KB of space.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/fit_check_sign.c
tools/fit_common.c
tools/fit_common.h
tools/fit_image.c
tools/fit_info.c
tools/image-host.c

index 357650d526e77e6290bc1a422bf6cd6b110cf70f..af257cc8a2a2bf0bce3b51efc78f9aa58d1db4a0 100644 (file)
@@ -62,10 +62,10 @@ int main(int argc, char **argv)
                        break;
        }
 
-       ffd = mmap_fdt(cmdname, fdtfile, &fit_blob, &fsbuf, false);
+       ffd = mmap_fdt(cmdname, fdtfile, 0, &fit_blob, &fsbuf, false);
        if (ffd < 0)
                return EXIT_FAILURE;
-       kfd = mmap_fdt(cmdname, keyfile, &key_blob, &ksbuf, false);
+       kfd = mmap_fdt(cmdname, keyfile, 0, &key_blob, &ksbuf, false);
        if (ffd < 0)
                return EXIT_FAILURE;
 
index 286f357ab1769af8c507e6c94719558800ce7a92..81ba698abd2594727522559c0ca8560268bdae20 100644 (file)
@@ -38,8 +38,8 @@ int fit_check_image_types(uint8_t type)
                return EXIT_FAILURE;
 }
 
-int mmap_fdt(const char *cmdname, const char *fname, void **blobp,
-            struct stat *sbuf, bool delete_on_error)
+int mmap_fdt(const char *cmdname, const char *fname, size_t size_inc,
+            void **blobp, struct stat *sbuf, bool delete_on_error)
 {
        void *ptr;
        int fd;
@@ -59,6 +59,15 @@ int mmap_fdt(const char *cmdname, const char *fname, void **blobp,
                goto err;
        }
 
+       if (size_inc) {
+               sbuf->st_size += size_inc;
+               if (ftruncate(fd, sbuf->st_size)) {
+                       fprintf(stderr, "%s: Can't expand %s: %s\n",
+                               cmdname, fname, strerror(errno));
+               goto err;
+               }
+       }
+
        errno = 0;
        ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if ((ptr == MAP_FAILED) || (errno != 0)) {
@@ -73,6 +82,18 @@ int mmap_fdt(const char *cmdname, const char *fname, void **blobp,
                goto err;
        }
 
+       /* expand if needed */
+       if (size_inc) {
+               int ret;
+
+               ret = fdt_open_into(ptr, ptr, sbuf->st_size);
+               if (ret) {
+                       fprintf(stderr, "%s: Cannot expand FDT: %s\n",
+                               cmdname, fdt_strerror(ret));
+                       goto err;
+               }
+       }
+
        *blobp = ptr;
        return fd;
 
index adcee6df64580cfa6f0af91b7804258ff449232a..b8d8438717fc06992530af7e77c6cae30a12643a 100644 (file)
@@ -21,12 +21,13 @@ int fit_check_image_types(uint8_t type);
  *
  * @cmdname:   Tool name (for displaying with error messages)
  * @fname:     Filename containing FDT
+ * @size_inc:  Amount to increase size by (0 = leave it alone)
  * @blobp:     Returns pointer to FDT blob
  * @sbuf:      File status information is stored here
  * @delete_on_error:   true to delete the file if we get an error
  * @return 0 if OK, -1 on error.
  */
-int mmap_fdt(const char *cmdname, const char *fname, void **blobp,
-            struct stat *sbuf, bool delete_on_error);
+int mmap_fdt(const char *cmdname, const char *fname, size_t size_inc,
+            void **blobp, struct stat *sbuf, bool delete_on_error);
 
 #endif /* _FIT_COMMON_H_ */
index eeee484cdec096eecda45ad9942fc8354f38f4f3..3ececf913ff4c4fe2c1c2457f3f5b5ccbfa195fb 100644 (file)
 
 static image_header_t header;
 
+static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
+                            const char *tmpfile)
+{
+       int tfd, destfd = 0;
+       void *dest_blob = NULL;
+       off_t destfd_size = 0;
+       struct stat sbuf;
+       void *ptr;
+       int ret = 0;
+
+       tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true);
+       if (tfd < 0)
+               return -EIO;
+
+       if (params->keydest) {
+               struct stat dest_sbuf;
+
+               destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
+                                 &dest_blob, &dest_sbuf, false);
+               if (destfd < 0) {
+                       ret = -EIO;
+                       goto err_keydest;
+               }
+               destfd_size = dest_sbuf.st_size;
+       }
+
+       /* for first image creation, add a timestamp at offset 0 i.e., root  */
+       if (params->datafile)
+               ret = fit_set_timestamp(ptr, 0, sbuf.st_mtime);
+
+       if (!ret) {
+               ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
+                                               params->comment,
+                                               params->require_keys);
+       }
+
+       if (dest_blob) {
+               munmap(dest_blob, destfd_size);
+               close(destfd);
+       }
+
+err_keydest:
+       munmap(ptr, sbuf.st_size);
+       close(tfd);
+
+       return ret;
+}
+
 /**
  * fit_handle_file - main FIT file processing function
  *
@@ -38,11 +86,8 @@ static int fit_handle_file(struct image_tool_params *params)
 {
        char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
        char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
-       int tfd, destfd = 0;
-       void *dest_blob = NULL;
-       struct stat sbuf;
-       void *ptr;
-       off_t destfd_size = 0;
+       size_t size_inc;
+       int ret;
 
        /* Flattened Image Tree (FIT) format  handling */
        debug ("FIT format handling\n");
@@ -73,40 +118,26 @@ static int fit_handle_file(struct image_tool_params *params)
                goto err_system;
        }
 
-       if (params->keydest) {
-               destfd = mmap_fdt(params->cmdname, params->keydest,
-                                 &dest_blob, &sbuf, 1);
-               if (destfd < 0)
-                       goto err_keydest;
-               destfd_size = sbuf.st_size;
+       /*
+        * Set hashes for images in the blob. Unfortunately we may need more
+        * space in either FDT, so keep trying until we succeed.
+        *
+        * Note: this is pretty inefficient for signing, since we must
+        * calculate the signature every time. It would be better to calculate
+        * all the data and then store it in a separate step. However, this
+        * would be considerably more complex to implement. Generally a few
+        * steps of this loop is enough to sign with several keys.
+        */
+       for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) {
+               ret = fit_add_file_data(params, size_inc, tmpfile);
+               if (!ret || ret != -ENOSPC)
+                       break;
        }
 
-       tfd = mmap_fdt(params->cmdname, tmpfile, &ptr, &sbuf, 1);
-       if (tfd < 0)
-               goto err_mmap;
-
-       /* set hashes for images in the blob */
-       if (fit_add_verification_data(params->keydir,
-                                     dest_blob, ptr, params->comment,
-                                     params->require_keys)) {
+       if (ret) {
                fprintf(stderr, "%s Can't add hashes to FIT blob\n",
                        params->cmdname);
-               goto err_add_hashes;
-       }
-
-       /* for first image creation, add a timestamp at offset 0 i.e., root  */
-       if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {
-               fprintf (stderr, "%s: Can't add image timestamp\n",
-                               params->cmdname);
-               goto err_add_timestamp;
-       }
-       debug ("Added timestamp successfully\n");
-
-       munmap ((void *)ptr, sbuf.st_size);
-       close (tfd);
-       if (dest_blob) {
-               munmap(dest_blob, destfd_size);
-               close(destfd);
+               goto err_system;
        }
 
        if (rename (tmpfile, params->imagefile) == -1) {
@@ -115,17 +146,10 @@ static int fit_handle_file(struct image_tool_params *params)
                                strerror (errno));
                unlink (tmpfile);
                unlink (params->imagefile);
-               return (EXIT_FAILURE);
+               return EXIT_FAILURE;
        }
-       return (EXIT_SUCCESS);
+       return EXIT_SUCCESS;
 
-err_add_timestamp:
-err_add_hashes:
-       munmap(ptr, sbuf.st_size);
-err_mmap:
-       if (dest_blob)
-               munmap(dest_blob, destfd_size);
-err_keydest:
 err_system:
        unlink(tmpfile);
        return -1;
index 9442ff107249859ab9ab0afa78357057428ad6d9..afbed7b5995a69a261bae2a4d055963c9fc9b543 100644 (file)
@@ -68,7 +68,7 @@ int main(int argc, char **argv)
                        break;
                }
 
-       ffd = mmap_fdt(cmdname, fdtfile, &fit_blob, &fsbuf, false);
+       ffd = mmap_fdt(cmdname, fdtfile, 0, &fit_blob, &fsbuf, false);
 
        if (ffd < 0) {
                printf("Could not open %s\n", fdtfile);
index 651f1c2f8b46727eb6aa9dffc470452b3e641026..2be5e8043c1dd9cefa7b0380dd51533bee473fea 100644 (file)
@@ -224,7 +224,9 @@ static int fit_image_process_sig(const char *keydir, void *keydest,
        ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
                        NULL, 0);
        if (ret) {
-               printf("Can't write signature for '%s' signature node in '%s' image node: %s\n",
+               if (ret == -FDT_ERR_NOSPACE)
+                       return -ENOSPC;
+               printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n",
                       node_name, image_name, fdt_strerror(ret));
                return -1;
        }
@@ -589,10 +591,13 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
                return -1;
        }
 
-       if (fit_image_write_sig(fit, noffset, value, value_len, comment,
-                               region_prop, region_proplen)) {
-               printf("Can't write signature for '%s' signature node in '%s' conf node\n",
-                      node_name, conf_name);
+       ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
+                               region_prop, region_proplen);
+       if (ret) {
+               if (ret == -FDT_ERR_NOSPACE)
+                       return -ENOSPC;
+               printf("Can't write signature for '%s' signature node in '%s' conf node: %s\n",
+                      node_name, conf_name, fdt_strerror(ret));
                return -1;
        }
        free(value);
@@ -602,10 +607,13 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
        info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
 
        /* Write the public key into the supplied FDT file */
-       if (keydest && info.algo->add_verify_data(&info, keydest)) {
-               printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
-                      node_name, conf_name);
-               return -1;
+       if (keydest) {
+               ret = info.algo->add_verify_data(&info, keydest);
+               if (ret) {
+                       printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+                              node_name, conf_name);
+                       return ret == FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
+               }
        }
 
        return 0;