[U-Boot] [PATCH v2 19/27] mkimage: Support automatic creating of a FIT without a .its

Simon Glass
2016-02-23T05:55:51Z

At present, when generating a FIT, mkimage requires a .its file containing
the structure of the FIT and referring to the images to be included.

Creating the .its file is a separate step that makes it harder to use FIT.
This is not required for creating legacy images.

Often the FIT is pretty standard, consisting of an OS image, some device
tree files and a single configuration. We can handle this case automatically
and avoid needing a .its file at all.

To start with, support automatically generate the FIT using a new '-f auto'
option. Initially this only supports adding a single image (e.g. a linux
kernel) and a single configuration.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Rename the function to fdt_property_placeholder()

doc/mkimage.1 | 16 +++-
tools/fit_image.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
tools/imagetool.h | 1 +
tools/mkimage.c | 8 +-
4 files changed, 235 insertions(+), 6 deletions(-)

diff --git a/doc/mkimage.1 b/doc/mkimage.1
index 1b9d18c..146c114 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -108,10 +108,15 @@ Provide special options to the device tree compiler that is used to
create the image.

.TP
-.BI "\-f [" "image tree source file" "]"
+.BI "\-f [" "image tree source file" " | " "auto" "]"
Image tree source file that describes the structure and contents of the
FIT image.

+This can be automatically generated for some simple cases.
+Use "-f auto" for this. In that case the arguments -d, -A, -O, -T, -C, -a
+and -e are used to specify the image to include in the FIT and its attributes.
+No .its file is required.
+
.TP
.BI "\-F"
Indicates that an existing FIT image should be modified. No dtc
@@ -178,6 +183,15 @@ with unavailable keys are skipped.
.B -c """Kernel 3.8 image for production devices""" kernel.itb
.fi

+.P
+Create a FIT image containing a kernel, using automatic mode. No .its file
+is required.
+.nf
+.B mkimage -f auto -A arm -O linux -T kernel -C none -a 43e00000 -e 0 \\\\
+.br
+.B -c """Kernel 4.4 image for production devices""" -d vmlinuz kernel.itb
+.fi
+
.SH HOMEPAGE
http://www.denx.de/wiki/U-Boot/WebHome
.PP
diff --git a/tools/fit_image.c b/tools/fit_image.c
index eb2a25e..ed101f1 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -18,6 +18,8 @@
#include "fit_common.h"
#include "mkimage.h"
#include <image.h>
+#include <stdarg.h>
+#include <version.h>
#include <u-boot/crc.h>

static image_header_t header;
@@ -71,6 +73,207 @@ err_keydest:
}

/**
+ * fit_calc_size() - Calculate the approximate size of the FIT we will generate
+ */
+static int fit_calc_size(struct image_tool_params *params)
+{
+ int size, total_size;
+
+ size = imagetool_get_filesize(params, params->datafile);
+ if (size < 0)
+ return -1;
+
+ total_size = size;
+
+ /* TODO(sjg@chromium.org): Add in the size of any other files */
+
+ /* Add plenty of space for headers, properties, nodes, etc. */
+ total_size += 4096;
+
+ return total_size;
+}
+
+static int fdt_property_file(struct image_tool_params *params,
+ void *fdt, const char *name, const char *fname)
+{
+ struct stat sbuf;
+ void *ptr;
+ int ret;
+ int fd;
+
+ fd = open(fname, O_RDWR | O_BINARY);
+ if (fd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ return -1;
+ }
+
+ if (fstat(fd, &sbuf) < 0) {
+ fprintf(stderr, "%s: Can't stat %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ goto err;
+ }
+
+ ret = fdt_property_placeholder(fdt, "data", sbuf.st_size, &ptr);
+ if (ret)
+ return ret;
+ ret = read(fd, ptr, sbuf.st_size);
+ if (ret != sbuf.st_size) {
+ fprintf(stderr, "%s: Can't read %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ goto err;
+ }
+
+ return 0;
+err:
+ close(fd);
+ return -1;
+}
+
+static int fdt_property_strf(void *fdt, const char *name, const char *fmt, ...)
+{
+ char str[100];
+ va_list ptr;
+
+ va_start(ptr, fmt);
+ vsnprintf(str, sizeof(str), fmt, ptr);
+ va_end(ptr);
+ return fdt_property_string(fdt, name, str);
+}
+
+/**
+ * fit_write_images() - Write out a list of images to the FIT
+ *
+ * Include the main image (params->datafile).
+ */
+static int fit_write_images(struct image_tool_params *params, char *fdt)
+{
+ const char *typename;
+ char str[100];
+ int ret;
+
+ fdt_begin_node(fdt, "images");
+
+ /* First the main image */
+ typename = genimg_get_type_short_name(params->fit_image_type);
+ snprintf(str, sizeof(str), "%s at 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", genimg_get_arch_name(params->arch));
+ fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
+ fdt_property_string(fdt, "compression",
+ genimg_get_comp_short_name(params->comp));
+ fdt_property_u32(fdt, "load", params->addr);
+ fdt_property_u32(fdt, "entry", 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);
+ if (ret)
+ return ret;
+ fdt_end_node(fdt);
+
+ fdt_end_node(fdt);
+
+ return 0;
+}
+
+/**
+ * fit_write_configs() - Write out a list of configurations to the FIT
+ *
+ * Create a configuration with the main image in it.
+ */
+static void fit_write_configs(struct image_tool_params *params, char *fdt)
+{
+ const char *typename;
+ char str[100];
+
+ fdt_begin_node(fdt, "configurations");
+ fdt_property_string(fdt, "default", "conf at 1");
+
+ fdt_begin_node(fdt, "conf at 1");
+ typename = genimg_get_type_short_name(params->fit_image_type);
+ snprintf(str, sizeof(str), "%s at 1", typename);
+ fdt_property_string(fdt, typename, str);
+ fdt_end_node(fdt);
+
+ fdt_end_node(fdt);
+}
+
+static int fit_build_fdt(struct image_tool_params *params, char *fdt, int size)
+{
+ int ret;
+
+ ret = fdt_create(fdt, size);
+ if (ret)
+ return ret;
+ fdt_finish_reservemap(fdt);
+ fdt_begin_node(fdt, "");
+ fdt_property_strf(fdt, "description",
+ "%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);
+ fdt_property_u32(fdt, "#address-cells", 1);
+ ret = fit_write_images(params, fdt);
+ if (ret)
+ return ret;
+ fit_write_configs(params, fdt);
+ fdt_end_node(fdt);
+ ret = fdt_finish(fdt);
+ if (ret)
+ return ret;
+
+ return fdt_totalsize(fdt);
+}
+
+static int fit_build(struct image_tool_params *params, const char *fname)
+{
+ char *buf;
+ int size;
+ int ret;
+ int fd;
+
+ size = fit_calc_size(params);
+ if (size < 0)
+ return -1;
+ buf = malloc(size);
+ if (!buf) {
+ fprintf(stderr, "%s: Out of memory (%d bytes)\n",
+ params->cmdname, size);
+ return -1;
+ }
+ ret = fit_build_fdt(params, buf, size);
+ if (ret < 0) {
+ fprintf(stderr, "%s: Failed to build FIT image\n",
+ params->cmdname);
+ goto err;
+ }
+ size = ret;
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (fd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ goto err;
+ }
+ ret = write(fd, buf, size);
+ if (ret != size) {
+ fprintf(stderr, "%s: Can't write %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ close(fd);
+ goto err;
+ }
+ close(fd);
+
+ return 0;
+err:
+ free(buf);
+ return -1;
+}
+
+/**
* fit_handle_file - main FIT file processing function
*
* fit_handle_file() runs dtc to convert .its to .itb, includes
@@ -103,7 +306,14 @@ static int fit_handle_file(struct image_tool_params *params)
sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);

/* We either compile the source file, or use the existing FIT image */
- if (params->datafile) {
+ if (params->auto_its) {
+ if (fit_build(params, tmpfile)) {
+ fprintf(stderr, "%s: failed to build FIT\n",
+ params->cmdname);
+ return EXIT_FAILURE;
+ }
+ *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);
@@ -112,7 +322,7 @@ static int fit_handle_file(struct image_tool_params *params)
snprintf(cmd, sizeof(cmd), "cp %s %s",
params->imagefile, tmpfile);
}
- if (system (cmd) == -1) {
+ if (*cmd && system(cmd) == -1) {
fprintf (stderr, "%s: system(%s) failed: %s\n",
params->cmdname, cmd, strerror(errno));
goto err_system;
@@ -248,6 +458,8 @@ static int fit_extract_contents(void *ptr, struct image_tool_params *params)

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)));
diff --git a/tools/imagetool.h b/tools/imagetool.h
index 3cf42ac..4f426e4 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -61,6 +61,7 @@ struct image_tool_params {
int require_keys; /* 1 to mark signing keys as 'required' */
int file_size; /* Total size of output file */
int orig_file_size; /* Original size for file before padding */
+ bool auto_its; /* Automatically create the .its file */
int fit_image_type; /* Image type to put into the FIT */
};

diff --git a/tools/mkimage.c b/tools/mkimage.c
index 2fd1f0b..93a625f 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -85,7 +85,7 @@ static void usage(const char *msg)
" -x ==> set XIP (execute in place)\n",
params.cmdname);
fprintf(stderr,
- " %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
+ " %s [-D dtc_options] [-f fit-image.its|-f auto|-F] fit-image\n",
params.cmdname);
fprintf(stderr,
" -D => set all options for device tree compiler\n"
@@ -159,7 +159,8 @@ static void process_args(int argc, char **argv)
params.eflag = 1;
break;
case 'f':
- params.datafile = optarg;
+ datafile = optarg;
+ params.auto_its = !strcmp(datafile, "auto");
/* no break */
case 'F':
/*
@@ -235,7 +236,8 @@ static void process_args(int argc, char **argv)
*/
if (params.type == IH_TYPE_FLATDT) {
params.fit_image_type = type;
- params.datafile = datafile;
+ if (!params.auto_its)
+ params.datafile = datafile;
} else if (type != IH_TYPE_INVALID) {
params.type = type;
}
--
2.7.0.rc3.207.g0ac5344