diff --git a/doc/mkimage.1 b/doc/mkimage.1 index 146c114d9d..036b095c1b 100644 --- a/doc/mkimage.1 +++ b/doc/mkimage.1 @@ -96,6 +96,10 @@ Set XIP (execute in place) flag. .P .B Create FIT image: +.TP +.BI "\-b +Specifies that the following arguments are device tree binary files (.dtb). + .TP .BI "\-c [" "comment" "]" Specifies a comment to be added when signing. This is typically a useful @@ -191,6 +195,15 @@ is required. .br .B -c """Kernel 4.4 image for production devices""" -d vmlinuz kernel.itb .fi +.P +Create a FIT image containing a kernel and some device tree files, 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 \\\\ +.B -b /path/to/rk3288-firefly.dtb /path/to/rk3288-jerry.dtb kernel.itb +.fi .SH HOMEPAGE http://www.denx.de/wiki/U-Boot/WebHome diff --git a/tools/fit_image.c b/tools/fit_image.c index ed101f1d31..765ff31e67 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -77,6 +77,7 @@ err_keydest: */ static int fit_calc_size(struct image_tool_params *params) { + struct content_info *cont; int size, total_size; size = imagetool_get_filesize(params, params->datafile); @@ -84,8 +85,14 @@ static int fit_calc_size(struct image_tool_params *params) return -1; total_size = size; + for (cont = params->content_head; cont; cont = cont->next) { + size = imagetool_get_filesize(params, cont->fname); + if (size < 0) + return -1; - /* TODO(sjg@chromium.org): Add in the size of any other files */ + /* Add space for properties */ + total_size += size + 300; + } /* Add plenty of space for headers, properties, nodes, etc. */ total_size += 4096; @@ -141,15 +148,40 @@ static int fdt_property_strf(void *fdt, const char *name, const char *fmt, ...) return fdt_property_string(fdt, name, str); } +static void get_basename(char *str, int size, const char *fname) +{ + const char *p, *start, *end; + int len; + + /* + * Use the base name as the 'name' field. So for example: + * + * "arch/arm/dts/sun7i-a20-bananapro.dtb" + * becomes "sun7i-a20-bananapro" + */ + p = strrchr(fname, '/'); + start = p ? p + 1 : fname; + p = strrchr(fname, '.'); + end = p ? p : fname + strlen(fname); + len = end - start; + if (len >= size) + len = size - 1; + memcpy(str, start, len); + str[len] = '\0'; +} + /** * fit_write_images() - Write out a list of images to the FIT * - * Include the main image (params->datafile). + * We always include the main image (params->datafile). If there are device + * tree files, we include an fdt@ node for each of those too. */ static int fit_write_images(struct image_tool_params *params, char *fdt) { + struct content_info *cont; const char *typename; char str[100]; + int upto; int ret; fdt_begin_node(fdt, "images"); @@ -176,6 +208,27 @@ static int fit_write_images(struct image_tool_params *params, char *fdt) return ret; fdt_end_node(fdt); + /* Now the device tree files if available */ + upto = 0; + for (cont = params->content_head; cont; cont = cont->next) { + if (cont->type != IH_TYPE_FLATDT) + continue; + snprintf(str, sizeof(str), "%s@%d", FIT_FDT_PROP, ++upto); + fdt_begin_node(fdt, str); + + get_basename(str, sizeof(str), cont->fname); + fdt_property_string(fdt, "description", str); + ret = fdt_property_file(params, fdt, "data", cont->fname); + if (ret) + return ret; + fdt_property_string(fdt, "type", typename); + fdt_property_string(fdt, "arch", + genimg_get_arch_short_name(params->arch)); + fdt_property_string(fdt, "compression", + genimg_get_comp_short_name(IH_COMP_NONE)); + fdt_end_node(fdt); + } + fdt_end_node(fdt); return 0; @@ -184,21 +237,48 @@ static int fit_write_images(struct image_tool_params *params, char *fdt) /** * fit_write_configs() - Write out a list of configurations to the FIT * - * Create a configuration with the main image in it. + * If there are device tree files, we include a configuration for each, which + * selects the main image (params->datafile) and its corresponding device + * tree file. + * + * Otherwise we just create a configuration with the main image in it. */ static void fit_write_configs(struct image_tool_params *params, char *fdt) { + struct content_info *cont; const char *typename; char str[100]; + int upto; 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); + upto = 0; + for (cont = params->content_head; cont; cont = cont->next) { + if (cont->type != IH_TYPE_FLATDT) + continue; + typename = genimg_get_type_short_name(cont->type); + snprintf(str, sizeof(str), "conf@%d", ++upto); + fdt_begin_node(fdt, str); + + get_basename(str, sizeof(str), cont->fname); + fdt_property_string(fdt, "description", str); + + typename = genimg_get_type_short_name(params->fit_image_type); + snprintf(str, sizeof(str), "%s@1", typename); + fdt_property_string(fdt, typename, str); + + snprintf(str, sizeof(str), FIT_FDT_PROP "@%d", upto); + fdt_property_string(fdt, FIT_FDT_PROP, str); + fdt_end_node(fdt); + } + if (!upto) { + 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); } diff --git a/tools/imagetool.h b/tools/imagetool.h index 4f426e40a0..3d30fbec5c 100644 --- a/tools/imagetool.h +++ b/tools/imagetool.h @@ -27,6 +27,13 @@ #define IH_ARCH_DEFAULT IH_ARCH_INVALID +/* Information about a file that needs to be placed into the FIT */ +struct content_info { + struct content_info *next; + int type; /* File type (IH_TYPE_...) */ + const char *fname; +}; + /* * This structure defines all such variables those are initialized by * mkimage and dumpimage main core and need to be referred by image @@ -63,6 +70,8 @@ struct image_tool_params { 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 */ + struct content_info *content_head; /* List of files to include */ + struct content_info *content_tail; }; /* diff --git a/tools/mkimage.c b/tools/mkimage.c index 7add86c13d..22fab1d535 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -85,7 +85,8 @@ 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 auto|-F] fit-image\n", + " %s [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b ] fit-image\n" + " is used with -f auto, and is a space-separated list of .dtb files\n", params.cmdname); fprintf(stderr, " -D => set all options for device tree compiler\n" @@ -109,6 +110,24 @@ static void usage(const char *msg) exit(EXIT_FAILURE); } +static int add_content(int type, const char *fname) +{ + struct content_info *cont; + + cont = calloc(1, sizeof(*cont)); + if (!cont) + return -1; + cont->type = type; + cont->fname = fname; + if (params.content_tail) + params.content_tail->next = cont; + else + params.content_head = cont; + params.content_tail = cont; + + return 0; +} + static void process_args(int argc, char **argv) { char *ptr; @@ -119,7 +138,7 @@ static void process_args(int argc, char **argv) expecting = IH_TYPE_COUNT; /* Unknown */ while ((opt = getopt(argc, argv, - "-a:A:cC:d:D:e:f:Fk:K:ln:O:rR:sT:vVx")) != -1) { + "-a:A:bcC:d:D:e:f:Fk:K:ln:O:rR:sT:vVx")) != -1) { switch (opt) { case 'a': params.addr = strtoull(optarg, &ptr, 16); @@ -134,6 +153,9 @@ static void process_args(int argc, char **argv) if (params.arch < 0) usage("Invalid architecture"); break; + case 'b': + expecting = IH_TYPE_FLATDT; + break; case 'c': params.comment = optarg; break; @@ -222,6 +244,18 @@ static void process_args(int argc, char **argv) if (expecting == type || optind == argc) { params.imagefile = optarg; expecting = IH_TYPE_INVALID; + } else if (expecting == IH_TYPE_INVALID) { + fprintf(stderr, + "%s: Unknown content type: use -b before device tree files", + params.cmdname); + exit(EXIT_FAILURE); + } else { + if (add_content(expecting, optarg)) { + fprintf(stderr, + "%s: Out of memory adding content '%s'", + params.cmdname, optarg); + exit(EXIT_FAILURE); + } } break; default: