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