1 /* 2 * (C) Copyright 2008 Semihalf 3 * 4 * (C) Copyright 2000-2004 5 * DENX Software Engineering 6 * Wolfgang Denk, wd@denx.de 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include "mkimage.h" 25 #include <image.h> 26 #include <u-boot/crc.h> 27 28 static void copy_file (int, const char *, int); 29 static void usage (void); 30 static int image_verify_header (char *, int); 31 static void fit_handle_file (void); 32 33 char *datafile; 34 char *imagefile; 35 char *cmdname; 36 37 int dflag = 0; 38 int eflag = 0; 39 int fflag = 0; 40 int lflag = 0; 41 int vflag = 0; 42 int xflag = 0; 43 int opt_os = IH_OS_LINUX; 44 int opt_arch = IH_ARCH_PPC; 45 int opt_type = IH_TYPE_KERNEL; 46 int opt_comp = IH_COMP_GZIP; 47 char *opt_dtc = MKIMAGE_DEFAULT_DTC_OPTIONS; 48 49 image_header_t header; 50 image_header_t *hdr = &header; 51 52 int 53 main (int argc, char **argv) 54 { 55 int ifd = -1; 56 uint32_t checksum; 57 uint32_t addr; 58 uint32_t ep; 59 struct stat sbuf; 60 unsigned char *ptr; 61 char *name = ""; 62 int retval = 0; 63 64 cmdname = *argv; 65 66 addr = ep = 0; 67 68 while (--argc > 0 && **++argv == '-') { 69 while (*++*argv) { 70 switch (**argv) { 71 case 'l': 72 lflag = 1; 73 break; 74 case 'A': 75 if ((--argc <= 0) || 76 (opt_arch = genimg_get_arch_id (*++argv)) < 0) 77 usage (); 78 goto NXTARG; 79 case 'C': 80 if ((--argc <= 0) || 81 (opt_comp = genimg_get_comp_id (*++argv)) < 0) 82 usage (); 83 goto NXTARG; 84 case 'D': 85 if (--argc <= 0) 86 usage (); 87 opt_dtc = *++argv; 88 goto NXTARG; 89 90 case 'O': 91 if ((--argc <= 0) || 92 (opt_os = genimg_get_os_id (*++argv)) < 0) 93 usage (); 94 goto NXTARG; 95 case 'T': 96 if ((--argc <= 0) || 97 (opt_type = genimg_get_type_id (*++argv)) < 0) 98 usage (); 99 goto NXTARG; 100 101 case 'a': 102 if (--argc <= 0) 103 usage (); 104 addr = strtoul (*++argv, (char **)&ptr, 16); 105 if (*ptr) { 106 fprintf (stderr, 107 "%s: invalid load address %s\n", 108 cmdname, *argv); 109 exit (EXIT_FAILURE); 110 } 111 goto NXTARG; 112 case 'd': 113 if (--argc <= 0) 114 usage (); 115 datafile = *++argv; 116 dflag = 1; 117 goto NXTARG; 118 case 'e': 119 if (--argc <= 0) 120 usage (); 121 ep = strtoul (*++argv, (char **)&ptr, 16); 122 if (*ptr) { 123 fprintf (stderr, 124 "%s: invalid entry point %s\n", 125 cmdname, *argv); 126 exit (EXIT_FAILURE); 127 } 128 eflag = 1; 129 goto NXTARG; 130 case 'f': 131 if (--argc <= 0) 132 usage (); 133 datafile = *++argv; 134 fflag = 1; 135 goto NXTARG; 136 case 'n': 137 if (--argc <= 0) 138 usage (); 139 name = *++argv; 140 goto NXTARG; 141 case 'v': 142 vflag++; 143 break; 144 case 'x': 145 xflag++; 146 break; 147 default: 148 usage (); 149 } 150 } 151 NXTARG: ; 152 } 153 154 if ((argc != 1) || 155 (dflag && (fflag || lflag)) || 156 (fflag && (dflag || lflag)) || 157 (lflag && (dflag || fflag))) 158 usage(); 159 160 if (!eflag) { 161 ep = addr; 162 /* If XIP, entry point must be after the U-Boot header */ 163 if (xflag) 164 ep += image_get_header_size (); 165 } 166 167 /* 168 * If XIP, ensure the entry point is equal to the load address plus 169 * the size of the U-Boot header. 170 */ 171 if (xflag) { 172 if (ep != addr + image_get_header_size ()) { 173 fprintf (stderr, 174 "%s: For XIP, the entry point must be the load addr + %lu\n", 175 cmdname, 176 (unsigned long)image_get_header_size ()); 177 exit (EXIT_FAILURE); 178 } 179 } 180 181 imagefile = *argv; 182 183 if (!fflag){ 184 if (lflag) { 185 ifd = open (imagefile, O_RDONLY|O_BINARY); 186 } else { 187 ifd = open (imagefile, 188 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 189 } 190 191 if (ifd < 0) { 192 fprintf (stderr, "%s: Can't open %s: %s\n", 193 cmdname, imagefile, strerror(errno)); 194 exit (EXIT_FAILURE); 195 } 196 } 197 198 if (lflag) { 199 /* 200 * list header information of existing image 201 */ 202 if (fstat(ifd, &sbuf) < 0) { 203 fprintf (stderr, "%s: Can't stat %s: %s\n", 204 cmdname, imagefile, strerror(errno)); 205 exit (EXIT_FAILURE); 206 } 207 208 if ((unsigned)sbuf.st_size < image_get_header_size ()) { 209 fprintf (stderr, 210 "%s: Bad size: \"%s\" is no valid image\n", 211 cmdname, imagefile); 212 exit (EXIT_FAILURE); 213 } 214 215 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); 216 if (ptr == MAP_FAILED) { 217 fprintf (stderr, "%s: Can't read %s: %s\n", 218 cmdname, imagefile, strerror(errno)); 219 exit (EXIT_FAILURE); 220 } 221 222 if (!(retval = fdt_check_header (ptr))) { 223 /* FIT image */ 224 fit_print_contents (ptr); 225 } else if (!(retval = image_verify_header ((char *)ptr, 226 sbuf.st_size))) { 227 /* old-style image */ 228 image_print_contents ((image_header_t *)ptr); 229 } 230 231 (void) munmap((void *)ptr, sbuf.st_size); 232 (void) close (ifd); 233 234 exit (retval); 235 } else if (fflag) { 236 /* Flattened Image Tree (FIT) format handling */ 237 debug ("FIT format handling\n"); 238 fit_handle_file (); 239 exit (retval); 240 } 241 242 /* 243 * Must be -w then: 244 * 245 * write dummy header, to be fixed later 246 */ 247 memset (hdr, 0, image_get_header_size ()); 248 249 if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) { 250 fprintf (stderr, "%s: Write error on %s: %s\n", 251 cmdname, imagefile, strerror(errno)); 252 exit (EXIT_FAILURE); 253 } 254 255 if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) { 256 char *file = datafile; 257 uint32_t size; 258 259 for (;;) { 260 char *sep = NULL; 261 262 if (file) { 263 if ((sep = strchr(file, ':')) != NULL) { 264 *sep = '\0'; 265 } 266 267 if (stat (file, &sbuf) < 0) { 268 fprintf (stderr, "%s: Can't stat %s: %s\n", 269 cmdname, file, strerror(errno)); 270 exit (EXIT_FAILURE); 271 } 272 size = cpu_to_uimage (sbuf.st_size); 273 } else { 274 size = 0; 275 } 276 277 if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 278 fprintf (stderr, "%s: Write error on %s: %s\n", 279 cmdname, imagefile, strerror(errno)); 280 exit (EXIT_FAILURE); 281 } 282 283 if (!file) { 284 break; 285 } 286 287 if (sep) { 288 *sep = ':'; 289 file = sep + 1; 290 } else { 291 file = NULL; 292 } 293 } 294 295 file = datafile; 296 297 for (;;) { 298 char *sep = strchr(file, ':'); 299 if (sep) { 300 *sep = '\0'; 301 copy_file (ifd, file, 1); 302 *sep++ = ':'; 303 file = sep; 304 } else { 305 copy_file (ifd, file, 0); 306 break; 307 } 308 } 309 } else { 310 copy_file (ifd, datafile, 0); 311 } 312 313 /* We're a bit of paranoid */ 314 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__) 315 (void) fdatasync (ifd); 316 #else 317 (void) fsync (ifd); 318 #endif 319 320 if (fstat(ifd, &sbuf) < 0) { 321 fprintf (stderr, "%s: Can't stat %s: %s\n", 322 cmdname, imagefile, strerror(errno)); 323 exit (EXIT_FAILURE); 324 } 325 326 ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 327 if (ptr == MAP_FAILED) { 328 fprintf (stderr, "%s: Can't map %s: %s\n", 329 cmdname, imagefile, strerror(errno)); 330 exit (EXIT_FAILURE); 331 } 332 333 hdr = (image_header_t *)ptr; 334 335 checksum = crc32 (0, 336 (const unsigned char *)(ptr + 337 image_get_header_size ()), 338 sbuf.st_size - image_get_header_size () 339 ); 340 341 /* Build new header */ 342 image_set_magic (hdr, IH_MAGIC); 343 image_set_time (hdr, sbuf.st_mtime); 344 image_set_size (hdr, sbuf.st_size - image_get_header_size ()); 345 image_set_load (hdr, addr); 346 image_set_ep (hdr, ep); 347 image_set_dcrc (hdr, checksum); 348 image_set_os (hdr, opt_os); 349 image_set_arch (hdr, opt_arch); 350 image_set_type (hdr, opt_type); 351 image_set_comp (hdr, opt_comp); 352 353 image_set_name (hdr, name); 354 355 checksum = crc32 (0, (const unsigned char *)hdr, 356 image_get_header_size ()); 357 358 image_set_hcrc (hdr, checksum); 359 360 image_print_contents (hdr); 361 362 (void) munmap((void *)ptr, sbuf.st_size); 363 364 /* We're a bit of paranoid */ 365 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__) 366 (void) fdatasync (ifd); 367 #else 368 (void) fsync (ifd); 369 #endif 370 371 if (close(ifd)) { 372 fprintf (stderr, "%s: Write error on %s: %s\n", 373 cmdname, imagefile, strerror(errno)); 374 exit (EXIT_FAILURE); 375 } 376 377 exit (EXIT_SUCCESS); 378 } 379 380 static void 381 copy_file (int ifd, const char *datafile, int pad) 382 { 383 int dfd; 384 struct stat sbuf; 385 unsigned char *ptr; 386 int tail; 387 int zero = 0; 388 int offset = 0; 389 int size; 390 391 if (vflag) { 392 fprintf (stderr, "Adding Image %s\n", datafile); 393 } 394 395 if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 396 fprintf (stderr, "%s: Can't open %s: %s\n", 397 cmdname, datafile, strerror(errno)); 398 exit (EXIT_FAILURE); 399 } 400 401 if (fstat(dfd, &sbuf) < 0) { 402 fprintf (stderr, "%s: Can't stat %s: %s\n", 403 cmdname, datafile, strerror(errno)); 404 exit (EXIT_FAILURE); 405 } 406 407 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); 408 if (ptr == MAP_FAILED) { 409 fprintf (stderr, "%s: Can't read %s: %s\n", 410 cmdname, datafile, strerror(errno)); 411 exit (EXIT_FAILURE); 412 } 413 414 if (xflag) { 415 unsigned char *p = NULL; 416 /* 417 * XIP: do not append the image_header_t at the 418 * beginning of the file, but consume the space 419 * reserved for it. 420 */ 421 422 if ((unsigned)sbuf.st_size < image_get_header_size ()) { 423 fprintf (stderr, 424 "%s: Bad size: \"%s\" is too small for XIP\n", 425 cmdname, datafile); 426 exit (EXIT_FAILURE); 427 } 428 429 for (p = ptr; p < ptr + image_get_header_size (); p++) { 430 if ( *p != 0xff ) { 431 fprintf (stderr, 432 "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 433 cmdname, datafile); 434 exit (EXIT_FAILURE); 435 } 436 } 437 438 offset = image_get_header_size (); 439 } 440 441 size = sbuf.st_size - offset; 442 if (write(ifd, ptr + offset, size) != size) { 443 fprintf (stderr, "%s: Write error on %s: %s\n", 444 cmdname, imagefile, strerror(errno)); 445 exit (EXIT_FAILURE); 446 } 447 448 if (pad && ((tail = size % 4) != 0)) { 449 450 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 451 fprintf (stderr, "%s: Write error on %s: %s\n", 452 cmdname, imagefile, strerror(errno)); 453 exit (EXIT_FAILURE); 454 } 455 } 456 457 (void) munmap((void *)ptr, sbuf.st_size); 458 (void) close (dfd); 459 } 460 461 void 462 usage () 463 { 464 fprintf (stderr, "Usage: %s -l image\n" 465 " -l ==> list image header information\n", 466 cmdname); 467 fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp " 468 "-a addr -e ep -n name -d data_file[:data_file...] image\n" 469 " -A ==> set architecture to 'arch'\n" 470 " -O ==> set operating system to 'os'\n" 471 " -T ==> set image type to 'type'\n" 472 " -C ==> set compression type 'comp'\n" 473 " -a ==> set load address to 'addr' (hex)\n" 474 " -e ==> set entry point to 'ep' (hex)\n" 475 " -n ==> set image name to 'name'\n" 476 " -d ==> use image data from 'datafile'\n" 477 " -x ==> set XIP (execute in place)\n", 478 cmdname); 479 fprintf (stderr, " %s [-D dtc_options] -f fit-image.its fit-image\n", 480 cmdname); 481 482 exit (EXIT_FAILURE); 483 } 484 485 static int 486 image_verify_header (char *ptr, int image_size) 487 { 488 int len; 489 const unsigned char *data; 490 uint32_t checksum; 491 image_header_t header; 492 image_header_t *hdr = &header; 493 494 /* 495 * create copy of header so that we can blank out the 496 * checksum field for checking - this can't be done 497 * on the PROT_READ mapped data. 498 */ 499 memcpy (hdr, ptr, sizeof(image_header_t)); 500 501 if (be32_to_cpu(hdr->ih_magic) != IH_MAGIC) { 502 fprintf (stderr, 503 "%s: Bad Magic Number: \"%s\" is no valid image\n", 504 cmdname, imagefile); 505 return -FDT_ERR_BADMAGIC; 506 } 507 508 data = (const unsigned char *)hdr; 509 len = sizeof(image_header_t); 510 511 checksum = be32_to_cpu(hdr->ih_hcrc); 512 hdr->ih_hcrc = cpu_to_be32(0); /* clear for re-calculation */ 513 514 if (crc32 (0, data, len) != checksum) { 515 fprintf (stderr, 516 "%s: ERROR: \"%s\" has bad header checksum!\n", 517 cmdname, imagefile); 518 return -FDT_ERR_BADSTATE; 519 } 520 521 data = (const unsigned char *)ptr + sizeof(image_header_t); 522 len = image_size - sizeof(image_header_t) ; 523 524 if (crc32 (0, data, len) != be32_to_cpu(hdr->ih_dcrc)) { 525 fprintf (stderr, 526 "%s: ERROR: \"%s\" has corrupted data!\n", 527 cmdname, imagefile); 528 return -FDT_ERR_BADSTRUCTURE; 529 } 530 return 0; 531 } 532 533 /** 534 * fit_handle_file - main FIT file processing function 535 * 536 * fit_handle_file() runs dtc to convert .its to .itb, includes 537 * binary data, updates timestamp property and calculates hashes. 538 * 539 * datafile - .its file 540 * imagefile - .itb file 541 * 542 * returns: 543 * only on success, otherwise calls exit (EXIT_FAILURE); 544 */ 545 static void fit_handle_file (void) 546 { 547 char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; 548 char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; 549 int tfd; 550 struct stat sbuf; 551 unsigned char *ptr; 552 553 /* call dtc to include binary properties into the tmp file */ 554 if (strlen (imagefile) + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > 555 sizeof (tmpfile)) { 556 fprintf (stderr, "%s: Image file name (%s) too long, " 557 "can't create tmpfile", 558 imagefile, cmdname); 559 exit (EXIT_FAILURE); 560 } 561 sprintf (tmpfile, "%s%s", imagefile, MKIMAGE_TMPFILE_SUFFIX); 562 563 /* dtc -I dts -O -p 200 datafile > tmpfile */ 564 sprintf (cmd, "%s %s %s > %s", 565 MKIMAGE_DTC, opt_dtc, datafile, tmpfile); 566 debug ("Trying to execute \"%s\"\n", cmd); 567 if (system (cmd) == -1) { 568 fprintf (stderr, "%s: system(%s) failed: %s\n", 569 cmdname, cmd, strerror(errno)); 570 unlink (tmpfile); 571 exit (EXIT_FAILURE); 572 } 573 574 /* load FIT blob into memory */ 575 tfd = open (tmpfile, O_RDWR|O_BINARY); 576 577 if (tfd < 0) { 578 fprintf (stderr, "%s: Can't open %s: %s\n", 579 cmdname, tmpfile, strerror(errno)); 580 unlink (tmpfile); 581 exit (EXIT_FAILURE); 582 } 583 584 if (fstat (tfd, &sbuf) < 0) { 585 fprintf (stderr, "%s: Can't stat %s: %s\n", 586 cmdname, tmpfile, strerror(errno)); 587 unlink (tmpfile); 588 exit (EXIT_FAILURE); 589 } 590 591 ptr = mmap (0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, tfd, 0); 592 if (ptr == MAP_FAILED) { 593 fprintf (stderr, "%s: Can't read %s: %s\n", 594 cmdname, tmpfile, strerror(errno)); 595 unlink (tmpfile); 596 exit (EXIT_FAILURE); 597 } 598 599 /* check if ptr has a valid blob */ 600 if (fdt_check_header (ptr)) { 601 fprintf (stderr, "%s: Invalid FIT blob\n", cmdname); 602 unlink (tmpfile); 603 exit (EXIT_FAILURE); 604 } 605 606 /* set hashes for images in the blob */ 607 if (fit_set_hashes (ptr)) { 608 fprintf (stderr, "%s Can't add hashes to FIT blob", cmdname); 609 unlink (tmpfile); 610 exit (EXIT_FAILURE); 611 } 612 613 /* add a timestamp at offset 0 i.e., root */ 614 if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) { 615 fprintf (stderr, "%s: Can't add image timestamp\n", cmdname); 616 unlink (tmpfile); 617 exit (EXIT_FAILURE); 618 } 619 debug ("Added timestamp successfully\n"); 620 621 munmap ((void *)ptr, sbuf.st_size); 622 close (tfd); 623 624 if (rename (tmpfile, imagefile) == -1) { 625 fprintf (stderr, "%s: Can't rename %s to %s: %s\n", 626 cmdname, tmpfile, imagefile, strerror (errno)); 627 unlink (tmpfile); 628 unlink (imagefile); 629 exit (EXIT_FAILURE); 630 } 631 } 632