1 /* 2 * (C) Copyright 2008 Semihalf 3 * 4 * (C) Copyright 2000-2004 5 * DENX Software Engineering 6 * Wolfgang Denk, wd@denx.de 7 * 8 * Updated-by: Prafulla Wadaskar <prafulla@marvell.com> 9 * FIT image specific code abstracted from mkimage.c 10 * some functions added to address abstraction 11 * 12 * All rights reserved. 13 * 14 * SPDX-License-Identifier: GPL-2.0+ 15 */ 16 17 #include "imagetool.h" 18 #include "fit_common.h" 19 #include "mkimage.h" 20 #include <image.h> 21 #include <u-boot/crc.h> 22 23 static image_header_t header; 24 25 static int fit_add_file_data(struct image_tool_params *params, size_t size_inc, 26 const char *tmpfile) 27 { 28 int tfd, destfd = 0; 29 void *dest_blob = NULL; 30 off_t destfd_size = 0; 31 struct stat sbuf; 32 void *ptr; 33 int ret = 0; 34 35 tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true); 36 if (tfd < 0) 37 return -EIO; 38 39 if (params->keydest) { 40 struct stat dest_sbuf; 41 42 destfd = mmap_fdt(params->cmdname, params->keydest, size_inc, 43 &dest_blob, &dest_sbuf, false); 44 if (destfd < 0) { 45 ret = -EIO; 46 goto err_keydest; 47 } 48 destfd_size = dest_sbuf.st_size; 49 } 50 51 /* for first image creation, add a timestamp at offset 0 i.e., root */ 52 if (params->datafile) 53 ret = fit_set_timestamp(ptr, 0, sbuf.st_mtime); 54 55 if (!ret) { 56 ret = fit_add_verification_data(params->keydir, dest_blob, ptr, 57 params->comment, 58 params->require_keys); 59 } 60 61 if (dest_blob) { 62 munmap(dest_blob, destfd_size); 63 close(destfd); 64 } 65 66 err_keydest: 67 munmap(ptr, sbuf.st_size); 68 close(tfd); 69 70 return ret; 71 } 72 73 /** 74 * fit_handle_file - main FIT file processing function 75 * 76 * fit_handle_file() runs dtc to convert .its to .itb, includes 77 * binary data, updates timestamp property and calculates hashes. 78 * 79 * datafile - .its file 80 * imagefile - .itb file 81 * 82 * returns: 83 * only on success, otherwise calls exit (EXIT_FAILURE); 84 */ 85 static int fit_handle_file(struct image_tool_params *params) 86 { 87 char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; 88 char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; 89 size_t size_inc; 90 int ret; 91 92 /* Flattened Image Tree (FIT) format handling */ 93 debug ("FIT format handling\n"); 94 95 /* call dtc to include binary properties into the tmp file */ 96 if (strlen (params->imagefile) + 97 strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) { 98 fprintf (stderr, "%s: Image file name (%s) too long, " 99 "can't create tmpfile", 100 params->imagefile, params->cmdname); 101 return (EXIT_FAILURE); 102 } 103 sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); 104 105 /* We either compile the source file, or use the existing FIT image */ 106 if (params->datafile) { 107 /* dtc -I dts -O dtb -p 500 datafile > tmpfile */ 108 snprintf(cmd, sizeof(cmd), "%s %s %s > %s", 109 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); 110 debug("Trying to execute \"%s\"\n", cmd); 111 } else { 112 snprintf(cmd, sizeof(cmd), "cp %s %s", 113 params->imagefile, tmpfile); 114 } 115 if (system (cmd) == -1) { 116 fprintf (stderr, "%s: system(%s) failed: %s\n", 117 params->cmdname, cmd, strerror(errno)); 118 goto err_system; 119 } 120 121 /* 122 * Set hashes for images in the blob. Unfortunately we may need more 123 * space in either FDT, so keep trying until we succeed. 124 * 125 * Note: this is pretty inefficient for signing, since we must 126 * calculate the signature every time. It would be better to calculate 127 * all the data and then store it in a separate step. However, this 128 * would be considerably more complex to implement. Generally a few 129 * steps of this loop is enough to sign with several keys. 130 */ 131 for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) { 132 ret = fit_add_file_data(params, size_inc, tmpfile); 133 if (!ret || ret != -ENOSPC) 134 break; 135 } 136 137 if (ret) { 138 fprintf(stderr, "%s Can't add hashes to FIT blob\n", 139 params->cmdname); 140 goto err_system; 141 } 142 143 if (rename (tmpfile, params->imagefile) == -1) { 144 fprintf (stderr, "%s: Can't rename %s to %s: %s\n", 145 params->cmdname, tmpfile, params->imagefile, 146 strerror (errno)); 147 unlink (tmpfile); 148 unlink (params->imagefile); 149 return EXIT_FAILURE; 150 } 151 return EXIT_SUCCESS; 152 153 err_system: 154 unlink(tmpfile); 155 return -1; 156 } 157 158 /** 159 * fit_image_extract - extract a FIT component image 160 * @fit: pointer to the FIT format image header 161 * @image_noffset: offset of the component image node 162 * @file_name: name of the file to store the FIT sub-image 163 * 164 * returns: 165 * zero in case of success or a negative value if fail. 166 */ 167 static int fit_image_extract( 168 const void *fit, 169 int image_noffset, 170 const char *file_name) 171 { 172 const void *file_data; 173 size_t file_size = 0; 174 175 /* get the "data" property of component at offset "image_noffset" */ 176 fit_image_get_data(fit, image_noffset, &file_data, &file_size); 177 178 /* save the "file_data" into the file specified by "file_name" */ 179 return imagetool_save_subimage(file_name, (ulong) file_data, file_size); 180 } 181 182 /** 183 * fit_extract_contents - retrieve a sub-image component from the FIT image 184 * @ptr: pointer to the FIT format image header 185 * @params: command line parameters 186 * 187 * returns: 188 * zero in case of success or a negative value if fail. 189 */ 190 static int fit_extract_contents(void *ptr, struct image_tool_params *params) 191 { 192 int images_noffset; 193 int noffset; 194 int ndepth; 195 const void *fit = ptr; 196 int count = 0; 197 const char *p; 198 199 /* Indent string is defined in header image.h */ 200 p = IMAGE_INDENT_STRING; 201 202 if (!fit_check_format(fit)) { 203 printf("Bad FIT image format\n"); 204 return -1; 205 } 206 207 /* Find images parent node offset */ 208 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 209 if (images_noffset < 0) { 210 printf("Can't find images parent node '%s' (%s)\n", 211 FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 212 return -1; 213 } 214 215 /* Avoid any overrun */ 216 count = fit_get_subimage_count(fit, images_noffset); 217 if ((params->pflag < 0) || (count <= params->pflag)) { 218 printf("No such component at '%d'\n", params->pflag); 219 return -1; 220 } 221 222 /* Process its subnodes, extract the desired component from image */ 223 for (ndepth = 0, count = 0, 224 noffset = fdt_next_node(fit, images_noffset, &ndepth); 225 (noffset >= 0) && (ndepth > 0); 226 noffset = fdt_next_node(fit, noffset, &ndepth)) { 227 if (ndepth == 1) { 228 /* 229 * Direct child node of the images parent node, 230 * i.e. component image node. 231 */ 232 if (params->pflag == count) { 233 printf("Extracted:\n%s Image %u (%s)\n", p, 234 count, fit_get_name(fit, noffset, NULL)); 235 236 fit_image_print(fit, noffset, p); 237 238 return fit_image_extract(fit, noffset, 239 params->outfile); 240 } 241 242 count++; 243 } 244 } 245 246 return 0; 247 } 248 249 static int fit_check_params(struct image_tool_params *params) 250 { 251 return ((params->dflag && (params->fflag || params->lflag)) || 252 (params->fflag && (params->dflag || params->lflag)) || 253 (params->lflag && (params->dflag || params->fflag))); 254 } 255 256 U_BOOT_IMAGE_TYPE( 257 fitimage, 258 "FIT Image support", 259 sizeof(image_header_t), 260 (void *)&header, 261 fit_check_params, 262 fit_verify_header, 263 fit_print_contents, 264 NULL, 265 fit_extract_contents, 266 fit_check_image_types, 267 fit_handle_file, 268 NULL /* FIT images use DTB header */ 269 ); 270