diff mbox

[U-Boot,v2,07/11] mkimage: Automatically make space in FDT when full

Message ID 1397659304-13952-8-git-send-email-sjg@chromium.org
State Superseded
Delegated to: Tom Rini
Headers show

Commit Message

Simon Glass April 16, 2014, 2:41 p.m. UTC
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>
---

Changes in v2: None

 tools/fit_image.c  | 165 ++++++++++++++++++++++++++++++++++++-----------------
 tools/image-host.c |  26 ++++++---
 2 files changed, 129 insertions(+), 62 deletions(-)
diff mbox

Patch

diff --git a/tools/fit_image.c b/tools/fit_image.c
index 1466164..fc70d51 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -35,10 +35,23 @@  static int fit_check_image_types (uint8_t type)
 		return EXIT_FAILURE;
 }
 
-int mmap_fdt(struct image_tool_params *params, const char *fname, void **blobp,
-		struct stat *sbuf)
+/**
+ * Map an FDT into memory, optionally increasing its size
+ *
+ * @params:	Image parameters
+ * @fname:	Filename containing FDT
+ * @size_inc:	Amount to increase size by (0 = leave it alone)
+ * @delete_on_error:	true to delete the file if we get an error
+ * @blobp:	Returns pointer to FDT blob
+ * @sbuf:	File status information is stored here
+ * @return 0 if OK, -1 on error.
+ */
+static int mmap_fdt(struct image_tool_params *params, const char *fname,
+		    size_t size_inc, bool delete_on_error, void **blobp,
+		    struct stat *sbuf)
 {
 	void *ptr;
+	int ret;
 	int fd;
 
 	/* Load FIT blob into memory (we need to write hashes/signatures) */
@@ -47,34 +60,103 @@  int mmap_fdt(struct image_tool_params *params, const char *fname, void **blobp,
 	if (fd < 0) {
 		fprintf(stderr, "%s: Can't open %s: %s\n",
 			params->cmdname, fname, strerror(errno));
-		unlink(fname);
-		return -1;
+		goto err;
 	}
 
 	if (fstat(fd, sbuf) < 0) {
 		fprintf(stderr, "%s: Can't stat %s: %s\n",
 			params->cmdname, fname, strerror(errno));
-		unlink(fname);
-		return -1;
+		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",
+				params->cmdname, fname, strerror(errno));
+		goto err;
+		}
 	}
 
 	ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 	if (ptr == MAP_FAILED) {
 		fprintf(stderr, "%s: Can't read %s: %s\n",
 			params->cmdname, fname, strerror(errno));
-		unlink(fname);
-		return -1;
+		goto err;
 	}
 
 	/* check if ptr has a valid blob */
 	if (fdt_check_header(ptr)) {
 		fprintf(stderr, "%s: Invalid FIT blob\n", params->cmdname);
-		unlink(fname);
-		return -1;
+		goto err;
+	}
+
+	/* expand if needed */
+	if (size_inc) {
+		ret = fdt_open_into(ptr, ptr, sbuf->st_size);
+		if (ret) {
+			fprintf(stderr, "%s: Cannot expand FDT: %s\n",
+				params->cmdname, fdt_strerror(ret));
+			goto err;
+		}
 	}
 
 	*blobp = ptr;
 	return fd;
+
+err:
+	close(fd);
+	if (delete_on_error)
+		unlink(fname);
+	return -1;
+}
+
+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, tmpfile, size_inc, true, &ptr, &sbuf);
+	if (tfd < 0)
+		return -EIO;
+
+	if (params->keydest) {
+		struct stat dest_sbuf;
+
+		destfd = mmap_fdt(params, params->keydest, size_inc, false,
+				  &dest_blob, &dest_sbuf);
+		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;
 }
 
 /**
@@ -93,11 +175,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");
@@ -128,39 +207,26 @@  static int fit_handle_file(struct image_tool_params *params)
 		goto err_system;
 	}
 
-	if (params->keydest) {
-		destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf);
-		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, tmpfile, &ptr, &sbuf);
-	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) {
@@ -169,17 +235,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;
diff --git a/tools/image-host.c b/tools/image-host.c
index 0d5c88c..cb36477 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -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;