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