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