mkimage: Support automatic creating of a FIT without a .its
authorSimon Glass <sjg@chromium.org>
Tue, 23 Feb 2016 05:55:51 +0000 (22:55 -0700)
committerTom Rini <trini@konsulko.com>
Mon, 14 Mar 2016 23:18:28 +0000 (19:18 -0400)
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>
doc/mkimage.1
tools/fit_image.c
tools/imagetool.h
tools/mkimage.c

index 1b9d18cbc9f4ab8951ac6409769b18938eb8401a..146c114d9d6a3a7aaf37cbf13fb5076d8928ff86 100644 (file)
@@ -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
index eb2a25eeac6aebcd7ae764ff8a593d18cc482528..ed101f1d31dac9154a0db61887b09f7eb998d968 100644 (file)
@@ -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;
@@ -70,6 +72,207 @@ err_keydest:
        return ret;
 }
 
+/**
+ * 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@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@1");
+
+       fdt_begin_node(fdt, "conf@1");
+       typename = genimg_get_type_short_name(params->fit_image_type);
+       snprintf(str, sizeof(str), "%s@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
  *
@@ -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)));
index 3cf42ac96ab1d84c89385d461b8ef1b464cf69f6..4f426e40a04043581d8acb2b09cdfac4bb6c79a4 100644 (file)
@@ -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 */
 };
 
index 4526da20b572899b5f0c95658acb47cb18efd0e6..7add86c13d09074cb6bcb09f446c71fa0b290b4b 100644 (file)
@@ -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;
        }