From 8e35bb07eb68e524804f2ef53dd18c7cec0b06fc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 22 Feb 2016 22:55:51 -0700 Subject: [PATCH] mkimage: Support automatic creating of a FIT without a .its 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 --- 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 1b9d18cbc9..146c114d9d 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 eb2a25eeac..ed101f1d31 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -18,6 +18,8 @@ #include "fit_common.h" #include "mkimage.h" #include +#include +#include #include 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))); diff --git a/tools/imagetool.h b/tools/imagetool.h index 3cf42ac96a..4f426e40a0 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 4526da20b5..7add86c13d 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.39.5