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 <stdarg.h> 22 #include <version.h> 23 #include <u-boot/crc.h> 24 25 static image_header_t header; 26 27 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) 28 29 /* Resize the fdt to its actual size + a bit of padding */ 30 static int fdt_shrink_to_minimum(void *blob, uint extrasize) 31 { 32 uint64_t addr, size; 33 uint actualsize; 34 int total, ret; 35 int i; 36 37 if (!blob) 38 return 0; 39 40 total = fdt_num_mem_rsv(blob); 41 for (i = 0; i < total; i++) { 42 fdt_get_mem_rsv(blob, i, &addr, &size); 43 if (addr == (uintptr_t)blob) { 44 fdt_del_mem_rsv(blob, i); 45 break; 46 } 47 } 48 49 /* 50 * Calculate the actual size of the fdt 51 * plus the size needed for 5 fdt_add_mem_rsv, one 52 * for the fdt itself and 4 for a possible initrd 53 * ((initrd-start + initrd-end) * 2 (name & value)) 54 */ 55 actualsize = fdt_off_dt_strings(blob) + 56 fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry); 57 58 actualsize += extrasize; 59 actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x200); 60 actualsize = actualsize - ((uintptr_t)blob & 0xfff); 61 62 /* Change the fdt header to reflect the correct size */ 63 fdt_set_totalsize(blob, actualsize); 64 65 /* Add the new reservation */ 66 ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize); 67 if (ret < 0) 68 return ret; 69 70 return actualsize; 71 } 72 73 static int fit_add_file_data(struct image_tool_params *params, size_t size_inc, 74 const char *tmpfile) 75 { 76 int tfd, destfd = 0; 77 void *dest_blob = NULL; 78 off_t destfd_size = 0; 79 struct stat sbuf; 80 void *ptr; 81 int ret = 0; 82 83 tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true); 84 if (tfd < 0) 85 return -EIO; 86 87 if (params->keydest) { 88 struct stat dest_sbuf; 89 90 destfd = mmap_fdt(params->cmdname, params->keydest, size_inc, 91 &dest_blob, &dest_sbuf, false); 92 if (destfd < 0) { 93 ret = -EIO; 94 goto err_keydest; 95 } 96 destfd_size = dest_sbuf.st_size; 97 } 98 99 /* for first image creation, add a timestamp at offset 0 i.e., root */ 100 if (params->datafile) { 101 time_t time = imagetool_get_source_date(params, sbuf.st_mtime); 102 ret = fit_set_timestamp(ptr, 0, time); 103 ret |= fit_set_totalsize(ptr, 0, sbuf.st_size); 104 if (params->vflag > 0) 105 ret |= fit_set_version(ptr, 0, params->vflag); 106 else 107 ret |= fit_set_version(ptr, 0, 0); 108 } 109 110 if (!ret) { 111 ret = fit_add_verification_data(params->keydir, dest_blob, ptr, 112 params->comment, 113 params->require_keys, 114 params->engine_id); 115 } 116 117 /* Remove external data size from fdt totalsize */ 118 if (params->external_offset) { 119 fdt_shrink_to_minimum(ptr, 0); 120 if (params->external_offset < fdt_totalsize(ptr)) { 121 ret = -EINVAL; 122 printf("Failed: external offset 0x%x overlaps FIT length 0x%x\n", 123 params->external_offset, fdt_totalsize(ptr)); 124 } 125 } 126 127 if (dest_blob) { 128 munmap(dest_blob, destfd_size); 129 close(destfd); 130 } 131 132 err_keydest: 133 munmap(ptr, sbuf.st_size); 134 close(tfd); 135 136 return ret; 137 } 138 139 /** 140 * fit_calc_size() - Calculate the approximate size of the FIT we will generate 141 */ 142 static int fit_calc_size(struct image_tool_params *params) 143 { 144 struct content_info *cont; 145 int size, total_size; 146 147 size = imagetool_get_filesize(params, params->datafile); 148 if (size < 0) 149 return -1; 150 total_size = size; 151 152 if (params->fit_ramdisk) { 153 size = imagetool_get_filesize(params, params->fit_ramdisk); 154 if (size < 0) 155 return -1; 156 total_size += size; 157 } 158 159 for (cont = params->content_head; cont; cont = cont->next) { 160 size = imagetool_get_filesize(params, cont->fname); 161 if (size < 0) 162 return -1; 163 164 /* Add space for properties */ 165 total_size += size + 300; 166 } 167 168 /* Add plenty of space for headers, properties, nodes, etc. */ 169 total_size += 4096; 170 171 return total_size; 172 } 173 174 static int fdt_property_file(struct image_tool_params *params, 175 void *fdt, const char *name, const char *fname) 176 { 177 struct stat sbuf; 178 void *ptr; 179 int ret; 180 int fd; 181 182 fd = open(fname, O_RDWR | O_BINARY); 183 if (fd < 0) { 184 fprintf(stderr, "%s: Can't open %s: %s\n", 185 params->cmdname, fname, strerror(errno)); 186 return -1; 187 } 188 189 if (fstat(fd, &sbuf) < 0) { 190 fprintf(stderr, "%s: Can't stat %s: %s\n", 191 params->cmdname, fname, strerror(errno)); 192 goto err; 193 } 194 195 ret = fdt_property_placeholder(fdt, "data", sbuf.st_size, &ptr); 196 if (ret) 197 goto err; 198 ret = read(fd, ptr, sbuf.st_size); 199 if (ret != sbuf.st_size) { 200 fprintf(stderr, "%s: Can't read %s: %s\n", 201 params->cmdname, fname, strerror(errno)); 202 goto err; 203 } 204 close(fd); 205 206 return 0; 207 err: 208 close(fd); 209 return -1; 210 } 211 212 static int fdt_property_strf(void *fdt, const char *name, const char *fmt, ...) 213 { 214 char str[100]; 215 va_list ptr; 216 217 va_start(ptr, fmt); 218 vsnprintf(str, sizeof(str), fmt, ptr); 219 va_end(ptr); 220 return fdt_property_string(fdt, name, str); 221 } 222 223 static void get_basename(char *str, int size, const char *fname) 224 { 225 const char *p, *start, *end; 226 int len; 227 228 /* 229 * Use the base name as the 'name' field. So for example: 230 * 231 * "arch/arm/dts/sun7i-a20-bananapro.dtb" 232 * becomes "sun7i-a20-bananapro" 233 */ 234 p = strrchr(fname, '/'); 235 start = p ? p + 1 : fname; 236 p = strrchr(fname, '.'); 237 end = p ? p : fname + strlen(fname); 238 len = end - start; 239 if (len >= size) 240 len = size - 1; 241 memcpy(str, start, len); 242 str[len] = '\0'; 243 } 244 245 /** 246 * fit_write_images() - Write out a list of images to the FIT 247 * 248 * We always include the main image (params->datafile). If there are device 249 * tree files, we include an fdt@ node for each of those too. 250 */ 251 static int fit_write_images(struct image_tool_params *params, char *fdt) 252 { 253 struct content_info *cont; 254 const char *typename; 255 char str[100]; 256 int upto; 257 int ret; 258 259 fdt_begin_node(fdt, "images"); 260 261 /* First the main image */ 262 typename = genimg_get_type_short_name(params->fit_image_type); 263 snprintf(str, sizeof(str), "%s@1", typename); 264 fdt_begin_node(fdt, str); 265 fdt_property_string(fdt, "description", params->imagename); 266 fdt_property_string(fdt, "type", typename); 267 fdt_property_string(fdt, "arch", 268 genimg_get_arch_short_name(params->arch)); 269 fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os)); 270 fdt_property_string(fdt, "compression", 271 genimg_get_comp_short_name(params->comp)); 272 fdt_property_u32(fdt, "load", params->addr); 273 fdt_property_u32(fdt, "entry", params->ep); 274 275 /* 276 * Put data last since it is large. SPL may only load the first part 277 * of the DT, so this way it can access all the above fields. 278 */ 279 ret = fdt_property_file(params, fdt, "data", params->datafile); 280 if (ret) 281 return ret; 282 fdt_end_node(fdt); 283 284 /* Now the device tree files if available */ 285 upto = 0; 286 for (cont = params->content_head; cont; cont = cont->next) { 287 if (cont->type != IH_TYPE_FLATDT) 288 continue; 289 snprintf(str, sizeof(str), "%s@%d", FIT_FDT_PROP, ++upto); 290 fdt_begin_node(fdt, str); 291 292 get_basename(str, sizeof(str), cont->fname); 293 fdt_property_string(fdt, "description", str); 294 ret = fdt_property_file(params, fdt, "data", cont->fname); 295 if (ret) 296 return ret; 297 fdt_property_string(fdt, "type", typename); 298 fdt_property_string(fdt, "arch", 299 genimg_get_arch_short_name(params->arch)); 300 fdt_property_string(fdt, "compression", 301 genimg_get_comp_short_name(IH_COMP_NONE)); 302 fdt_end_node(fdt); 303 } 304 305 /* And a ramdisk file if available */ 306 if (params->fit_ramdisk) { 307 fdt_begin_node(fdt, FIT_RAMDISK_PROP "@1"); 308 309 fdt_property_string(fdt, "type", FIT_RAMDISK_PROP); 310 fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os)); 311 312 ret = fdt_property_file(params, fdt, "data", params->fit_ramdisk); 313 if (ret) 314 return ret; 315 316 fdt_end_node(fdt); 317 } 318 319 fdt_end_node(fdt); 320 321 return 0; 322 } 323 324 /** 325 * fit_write_configs() - Write out a list of configurations to the FIT 326 * 327 * If there are device tree files, we include a configuration for each, which 328 * selects the main image (params->datafile) and its corresponding device 329 * tree file. 330 * 331 * Otherwise we just create a configuration with the main image in it. 332 */ 333 static void fit_write_configs(struct image_tool_params *params, char *fdt) 334 { 335 struct content_info *cont; 336 const char *typename; 337 char str[100]; 338 int upto; 339 340 fdt_begin_node(fdt, "configurations"); 341 fdt_property_string(fdt, "default", "conf@1"); 342 343 upto = 0; 344 for (cont = params->content_head; cont; cont = cont->next) { 345 if (cont->type != IH_TYPE_FLATDT) 346 continue; 347 typename = genimg_get_type_short_name(cont->type); 348 snprintf(str, sizeof(str), "conf@%d", ++upto); 349 fdt_begin_node(fdt, str); 350 351 get_basename(str, sizeof(str), cont->fname); 352 fdt_property_string(fdt, "description", str); 353 354 typename = genimg_get_type_short_name(params->fit_image_type); 355 snprintf(str, sizeof(str), "%s@1", typename); 356 fdt_property_string(fdt, typename, str); 357 358 if (params->fit_ramdisk) 359 fdt_property_string(fdt, FIT_RAMDISK_PROP, 360 FIT_RAMDISK_PROP "@1"); 361 362 snprintf(str, sizeof(str), FIT_FDT_PROP "@%d", upto); 363 fdt_property_string(fdt, FIT_FDT_PROP, str); 364 fdt_end_node(fdt); 365 } 366 367 if (!upto) { 368 fdt_begin_node(fdt, "conf@1"); 369 typename = genimg_get_type_short_name(params->fit_image_type); 370 snprintf(str, sizeof(str), "%s@1", typename); 371 fdt_property_string(fdt, typename, str); 372 373 if (params->fit_ramdisk) 374 fdt_property_string(fdt, FIT_RAMDISK_PROP, 375 FIT_RAMDISK_PROP "@1"); 376 377 fdt_end_node(fdt); 378 } 379 380 fdt_end_node(fdt); 381 } 382 383 static int fit_build_fdt(struct image_tool_params *params, char *fdt, int size) 384 { 385 int ret; 386 387 ret = fdt_create(fdt, size); 388 if (ret) 389 return ret; 390 fdt_finish_reservemap(fdt); 391 fdt_begin_node(fdt, ""); 392 fdt_property_strf(fdt, "description", 393 "%s image with one or more FDT blobs", 394 genimg_get_type_name(params->fit_image_type)); 395 fdt_property_strf(fdt, "creator", "U-Boot mkimage %s", PLAIN_VERSION); 396 fdt_property_u32(fdt, "#address-cells", 1); 397 ret = fit_write_images(params, fdt); 398 if (ret) 399 return ret; 400 fit_write_configs(params, fdt); 401 fdt_end_node(fdt); 402 ret = fdt_finish(fdt); 403 if (ret) 404 return ret; 405 406 return fdt_totalsize(fdt); 407 } 408 409 static int fit_build(struct image_tool_params *params, const char *fname) 410 { 411 char *buf; 412 int size; 413 int ret; 414 int fd; 415 416 size = fit_calc_size(params); 417 if (size < 0) 418 return -1; 419 buf = malloc(size); 420 if (!buf) { 421 fprintf(stderr, "%s: Out of memory (%d bytes)\n", 422 params->cmdname, size); 423 return -1; 424 } 425 ret = fit_build_fdt(params, buf, size); 426 if (ret < 0) { 427 fprintf(stderr, "%s: Failed to build FIT image\n", 428 params->cmdname); 429 goto err_buf; 430 } 431 size = ret; 432 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666); 433 if (fd < 0) { 434 fprintf(stderr, "%s: Can't open %s: %s\n", 435 params->cmdname, fname, strerror(errno)); 436 goto err_buf; 437 } 438 ret = write(fd, buf, size); 439 if (ret != size) { 440 fprintf(stderr, "%s: Can't write %s: %s\n", 441 params->cmdname, fname, strerror(errno)); 442 goto err; 443 } 444 close(fd); 445 free(buf); 446 447 return 0; 448 err: 449 close(fd); 450 err_buf: 451 free(buf); 452 return -1; 453 } 454 455 /** 456 * fit_extract_data() - Move all data outside the FIT 457 * 458 * This takes a normal FIT file and removes all the 'data' properties from it. 459 * The data is placed in an area after the FIT so that it can be accessed 460 * using an offset into that area. The 'data' properties turn into 461 * 'data-offset' properties. 462 * 463 * This function cannot cope with FITs with 'data-offset' properties. All 464 * data must be in 'data' properties on entry. 465 */ 466 static int fit_extract_data(struct image_tool_params *params, const char *fname) 467 { 468 void *buf; 469 int buf_ptr; 470 int fit_size, new_size; 471 int fd; 472 struct stat sbuf; 473 void *fdt; 474 int ret; 475 int images; 476 int node; 477 478 fd = mmap_fdt(params->cmdname, fname, 0x400, &fdt, &sbuf, false); 479 if (fd < 0) 480 return -EIO; 481 fit_size = fdt_totalsize(fdt); 482 483 /* Allocate space to hold the image data we will extract */ 484 buf = malloc(fit_size); 485 if (!buf) { 486 ret = -ENOMEM; 487 goto err_munmap; 488 } 489 buf_ptr = 0; 490 491 images = fdt_path_offset(fdt, FIT_IMAGES_PATH); 492 if (images < 0) { 493 debug("%s: Cannot find /images node: %d\n", __func__, images); 494 ret = -EINVAL; 495 goto err_munmap; 496 } 497 498 for (node = fdt_first_subnode(fdt, images); 499 node >= 0; 500 node = fdt_next_subnode(fdt, node)) { 501 const char *data; 502 int len; 503 504 data = fdt_getprop(fdt, node, "data", &len); 505 if (!data) 506 continue; 507 memcpy(buf + buf_ptr, data, len); 508 debug("Extracting data size %x\n", len); 509 510 ret = fdt_delprop(fdt, node, "data"); 511 if (ret) { 512 ret = -EPERM; 513 goto err_munmap; 514 } 515 if (params->external_offset > 0) { 516 /* An external offset positions the data absolutely. */ 517 fdt_setprop_u32(fdt, node, "data-position", 518 params->external_offset + buf_ptr); 519 } else { 520 fdt_setprop_u32(fdt, node, "data-offset", buf_ptr); 521 } 522 fdt_setprop_u32(fdt, node, "data-size", len); 523 524 buf_ptr += FIT_ALIGN(len); 525 } 526 527 /* Pack the FDT and place the data after it */ 528 fdt_pack(fdt); 529 530 debug("Size reduced from %x to %x\n", fit_size, fdt_totalsize(fdt)); 531 debug("External data size %x\n", buf_ptr); 532 new_size = fdt_totalsize(fdt); 533 new_size = FIT_ALIGN(new_size); 534 munmap(fdt, sbuf.st_size); 535 536 if (ftruncate(fd, new_size)) { 537 debug("%s: Failed to truncate file: %s\n", __func__, 538 strerror(errno)); 539 ret = -EIO; 540 goto err; 541 } 542 543 /* Check if an offset for the external data was set. */ 544 if (params->external_offset > 0) { 545 if (params->external_offset < new_size) { 546 printf("Failed: external offset 0x%x overlaps FIT length 0x%x\n", 547 params->external_offset, new_size); 548 ret = -EINVAL; 549 goto err; 550 } 551 new_size = params->external_offset; 552 } 553 if (lseek(fd, new_size, SEEK_SET) < 0) { 554 debug("%s: Failed to seek to end of file: %s\n", __func__, 555 strerror(errno)); 556 ret = -EIO; 557 goto err; 558 } 559 if (write(fd, buf, buf_ptr) != buf_ptr) { 560 debug("%s: Failed to write external data to file %s\n", 561 __func__, strerror(errno)); 562 ret = -EIO; 563 goto err; 564 } 565 free(buf); 566 close(fd); 567 return 0; 568 569 err_munmap: 570 munmap(fdt, sbuf.st_size); 571 err: 572 if (buf) 573 free(buf); 574 close(fd); 575 return ret; 576 } 577 578 static int fit_import_data(struct image_tool_params *params, const char *fname) 579 { 580 void *fdt, *old_fdt; 581 int fit_size, new_size, size, data_base; 582 int fd; 583 struct stat sbuf; 584 int ret; 585 int images; 586 int node; 587 588 fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false); 589 if (fd < 0) 590 return -EIO; 591 fit_size = fdt_totalsize(old_fdt); 592 data_base = FIT_ALIGN(fit_size); 593 594 /* Allocate space to hold the new FIT */ 595 size = sbuf.st_size + 16384; 596 fdt = malloc(size); 597 if (!fdt) { 598 fprintf(stderr, "%s: Failed to allocate memory (%d bytes)\n", 599 __func__, size); 600 ret = -ENOMEM; 601 goto err_has_fd; 602 } 603 ret = fdt_open_into(old_fdt, fdt, size); 604 if (ret) { 605 debug("%s: Failed to expand FIT: %s\n", __func__, 606 fdt_strerror(errno)); 607 ret = -EINVAL; 608 goto err_has_fd; 609 } 610 611 images = fdt_path_offset(fdt, FIT_IMAGES_PATH); 612 if (images < 0) { 613 debug("%s: Cannot find /images node: %d\n", __func__, images); 614 ret = -EINVAL; 615 goto err_has_fd; 616 } 617 618 for (node = fdt_first_subnode(fdt, images); 619 node >= 0; 620 node = fdt_next_subnode(fdt, node)) { 621 int buf_ptr; 622 int len; 623 624 buf_ptr = fdtdec_get_int(fdt, node, "data-offset", -1); 625 len = fdtdec_get_int(fdt, node, "data-size", -1); 626 if (buf_ptr == -1 || len == -1) 627 continue; 628 debug("Importing data size %x\n", len); 629 630 ret = fdt_setprop(fdt, node, "data", fdt + data_base + buf_ptr, 631 len); 632 if (ret) { 633 debug("%s: Failed to write property: %s\n", __func__, 634 fdt_strerror(ret)); 635 ret = -EINVAL; 636 goto err_has_fd; 637 } 638 } 639 640 /* Close the old fd so we can re-use it. */ 641 close(fd); 642 643 /* Pack the FDT and place the data after it */ 644 fdt_pack(fdt); 645 646 new_size = fdt_totalsize(fdt); 647 debug("Size expanded from %x to %x\n", fit_size, new_size); 648 649 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666); 650 if (fd < 0) { 651 fprintf(stderr, "%s: Can't open %s: %s\n", 652 params->cmdname, fname, strerror(errno)); 653 ret = -EIO; 654 goto err_no_fd; 655 } 656 if (write(fd, fdt, new_size) != new_size) { 657 debug("%s: Failed to write external data to file %s\n", 658 __func__, strerror(errno)); 659 ret = -EIO; 660 goto err_has_fd; 661 } 662 663 ret = 0; 664 665 err_has_fd: 666 close(fd); 667 err_no_fd: 668 munmap(old_fdt, sbuf.st_size); 669 free(fdt); 670 return ret; 671 } 672 673 /** 674 * fit_handle_file - main FIT file processing function 675 * 676 * fit_handle_file() runs dtc to convert .its to .itb, includes 677 * binary data, updates timestamp property and calculates hashes. 678 * 679 * datafile - .its file 680 * imagefile - .itb file 681 * 682 * returns: 683 * only on success, otherwise calls exit (EXIT_FAILURE); 684 */ 685 static int fit_handle_file(struct image_tool_params *params) 686 { 687 char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; 688 char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; 689 size_t size_inc; 690 int ret; 691 692 /* Flattened Image Tree (FIT) format handling */ 693 debug ("FIT format handling\n"); 694 695 /* call dtc to include binary properties into the tmp file */ 696 if (strlen (params->imagefile) + 697 strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) { 698 fprintf (stderr, "%s: Image file name (%s) too long, " 699 "can't create tmpfile", 700 params->imagefile, params->cmdname); 701 return (EXIT_FAILURE); 702 } 703 sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); 704 705 /* We either compile the source file, or use the existing FIT image */ 706 if (params->auto_its) { 707 if (fit_build(params, tmpfile)) { 708 fprintf(stderr, "%s: failed to build FIT\n", 709 params->cmdname); 710 return EXIT_FAILURE; 711 } 712 *cmd = '\0'; 713 } else if (params->datafile) { 714 /* dtc -I dts -O dtb -p 500 datafile > tmpfile */ 715 snprintf(cmd, sizeof(cmd), "%s %s \"%s\" > \"%s\"", 716 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); 717 debug("Trying to execute \"%s\"\n", cmd); 718 } else { 719 snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"", 720 params->imagefile, tmpfile); 721 } 722 if (*cmd && system(cmd) == -1) { 723 fprintf (stderr, "%s: system(%s) failed: %s\n", 724 params->cmdname, cmd, strerror(errno)); 725 goto err_system; 726 } 727 728 /* Move the data so it is internal to the FIT, if needed */ 729 ret = fit_import_data(params, tmpfile); 730 if (ret) 731 goto err_system; 732 733 /* Args "-E -p": move the data so it is external to the FIT, if requested */ 734 if (params->external_data && params->external_offset) { 735 ret = fit_extract_data(params, tmpfile); 736 if (ret) 737 goto err_system; 738 } 739 740 /* 741 * Set hashes for images in the blob. Unfortunately we may need more 742 * space in either FDT, so keep trying until we succeed. 743 * 744 * Note: this is pretty inefficient for signing, since we must 745 * calculate the signature every time. It would be better to calculate 746 * all the data and then store it in a separate step. However, this 747 * would be considerably more complex to implement. Generally a few 748 * steps of this loop is enough to sign with several keys. 749 */ 750 for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) { 751 ret = fit_add_file_data(params, size_inc, tmpfile); 752 if (!ret || ret != -ENOSPC) 753 break; 754 } 755 756 if (ret) { 757 fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n", 758 params->cmdname, ret); 759 goto err_system; 760 } 761 762 /* Args "-E": move the data so it is external to the FIT, if requested */ 763 if (params->external_data && !params->external_offset) { 764 ret = fit_extract_data(params, tmpfile); 765 if (ret) 766 goto err_system; 767 } 768 769 if (rename (tmpfile, params->imagefile) == -1) { 770 fprintf (stderr, "%s: Can't rename %s to %s: %s\n", 771 params->cmdname, tmpfile, params->imagefile, 772 strerror (errno)); 773 unlink (tmpfile); 774 unlink (params->imagefile); 775 return EXIT_FAILURE; 776 } 777 return EXIT_SUCCESS; 778 779 err_system: 780 unlink(tmpfile); 781 return -1; 782 } 783 784 /** 785 * fit_image_extract - extract a FIT component image 786 * @fit: pointer to the FIT format image header 787 * @image_noffset: offset of the component image node 788 * @file_name: name of the file to store the FIT sub-image 789 * 790 * returns: 791 * zero in case of success or a negative value if fail. 792 */ 793 static int fit_image_extract( 794 const void *fit, 795 int image_noffset, 796 const char *file_name) 797 { 798 const void *file_data; 799 size_t file_size = 0; 800 801 /* get the "data" property of component at offset "image_noffset" */ 802 fit_image_get_data(fit, image_noffset, &file_data, &file_size); 803 804 /* save the "file_data" into the file specified by "file_name" */ 805 return imagetool_save_subimage(file_name, (ulong) file_data, file_size); 806 } 807 808 /** 809 * fit_extract_contents - retrieve a sub-image component from the FIT image 810 * @ptr: pointer to the FIT format image header 811 * @params: command line parameters 812 * 813 * returns: 814 * zero in case of success or a negative value if fail. 815 */ 816 static int fit_extract_contents(void *ptr, struct image_tool_params *params) 817 { 818 int images_noffset; 819 int noffset; 820 int ndepth; 821 const void *fit = ptr; 822 int count = 0; 823 const char *p; 824 825 /* Indent string is defined in header image.h */ 826 p = IMAGE_INDENT_STRING; 827 828 if (!fit_check_format(fit)) { 829 printf("Bad FIT image format\n"); 830 return -1; 831 } 832 833 /* Find images parent node offset */ 834 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 835 if (images_noffset < 0) { 836 printf("Can't find images parent node '%s' (%s)\n", 837 FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 838 return -1; 839 } 840 841 /* Avoid any overrun */ 842 count = fit_get_subimage_count(fit, images_noffset); 843 if ((params->pflag < 0) || (count <= params->pflag)) { 844 printf("No such component at '%d'\n", params->pflag); 845 return -1; 846 } 847 848 /* Process its subnodes, extract the desired component from image */ 849 for (ndepth = 0, count = 0, 850 noffset = fdt_next_node(fit, images_noffset, &ndepth); 851 (noffset >= 0) && (ndepth > 0); 852 noffset = fdt_next_node(fit, noffset, &ndepth)) { 853 if (ndepth == 1) { 854 /* 855 * Direct child node of the images parent node, 856 * i.e. component image node. 857 */ 858 if (params->pflag == count) { 859 printf("Extracted:\n%s Image %u (%s)\n", p, 860 count, fit_get_name(fit, noffset, NULL)); 861 862 fit_image_print(fit, noffset, p); 863 864 return fit_image_extract(fit, noffset, 865 params->outfile); 866 } 867 868 count++; 869 } 870 } 871 872 return 0; 873 } 874 875 static int fit_check_params(struct image_tool_params *params) 876 { 877 if (params->auto_its) 878 return 0; 879 return ((params->dflag && (params->fflag || params->lflag)) || 880 (params->fflag && (params->dflag || params->lflag)) || 881 (params->lflag && (params->dflag || params->fflag))); 882 } 883 884 U_BOOT_IMAGE_TYPE( 885 fitimage, 886 "FIT Image support", 887 sizeof(image_header_t), 888 (void *)&header, 889 fit_check_params, 890 fit_verify_header, 891 fit_print_contents, 892 NULL, 893 fit_extract_contents, 894 fit_check_image_types, 895 fit_handle_file, 896 NULL /* FIT images use DTB header */ 897 ); 898