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