1 /* 2 * (C) Copyright 2008 Semihalf 3 * 4 * (C) Copyright 2000-2009 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 static void copy_file(int, const char *, int); 28 static void usage(void); 29 30 /* image_type_params link list to maintain registered image type supports */ 31 struct image_type_params *mkimage_tparams = NULL; 32 33 /* parameters initialized by core will be used by the image type code */ 34 struct mkimage_params params = { 35 .os = IH_OS_LINUX, 36 .arch = IH_ARCH_PPC, 37 .type = IH_TYPE_KERNEL, 38 .comp = IH_COMP_GZIP, 39 .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS, 40 }; 41 42 /* 43 * mkimage_register - 44 * 45 * It is used to register respective image generation/list support to the 46 * mkimage core 47 * 48 * the input struct image_type_params is checked and appended to the link 49 * list, if the input structure is already registered, error 50 */ 51 void mkimage_register (struct image_type_params *tparams) 52 { 53 struct image_type_params **tp; 54 55 if (!tparams) { 56 fprintf (stderr, "%s: %s: Null input\n", 57 params.cmdname, __FUNCTION__); 58 exit (EXIT_FAILURE); 59 } 60 61 /* scan the linked list, check for registry and point the last one */ 62 for (tp = &mkimage_tparams; *tp != NULL; tp = &(*tp)->next) { 63 if (!strcmp((*tp)->name, tparams->name)) { 64 fprintf (stderr, "%s: %s already registered\n", 65 params.cmdname, tparams->name); 66 return; 67 } 68 } 69 70 /* add input struct entry at the end of link list */ 71 *tp = tparams; 72 /* mark input entry as last entry in the link list */ 73 tparams->next = NULL; 74 75 debug ("Registered %s\n", tparams->name); 76 } 77 78 /* 79 * mkimage_get_type - 80 * 81 * It scans all registers image type supports 82 * checks the input type_id for each supported image type 83 * 84 * if successful, 85 * returns respective image_type_params pointer if success 86 * if input type_id is not supported by any of image_type_support 87 * returns NULL 88 */ 89 struct image_type_params *mkimage_get_type(int type) 90 { 91 struct image_type_params *curr; 92 93 for (curr = mkimage_tparams; curr != NULL; curr = curr->next) { 94 if (curr->check_image_type) { 95 if (!curr->check_image_type (type)) 96 return curr; 97 } 98 } 99 return NULL; 100 } 101 102 /* 103 * mkimage_verify_print_header - 104 * 105 * It scans mkimage_tparams link list, 106 * verifies image_header for each supported image type 107 * if verification is successful, prints respective header 108 * 109 * returns negative if input image format does not match with any of 110 * supported image types 111 */ 112 int mkimage_verify_print_header (void *ptr, struct stat *sbuf) 113 { 114 int retval = -1; 115 struct image_type_params *curr; 116 117 for (curr = mkimage_tparams; curr != NULL; curr = curr->next ) { 118 if (curr->verify_header) { 119 retval = curr->verify_header ( 120 (unsigned char *)ptr, sbuf->st_size, 121 ¶ms); 122 123 if (retval == 0) { 124 /* 125 * Print the image information 126 * if verify is successful 127 */ 128 if (curr->print_header) 129 curr->print_header (ptr); 130 else { 131 fprintf (stderr, 132 "%s: print_header undefined for %s\n", 133 params.cmdname, curr->name); 134 } 135 break; 136 } 137 } 138 } 139 return retval; 140 } 141 142 int 143 main (int argc, char **argv) 144 { 145 int ifd = -1; 146 struct stat sbuf; 147 unsigned char *ptr; 148 int retval = 0; 149 struct image_type_params *tparams = NULL; 150 151 /* Init FIT image generation/list support */ 152 init_fit_image_type (); 153 /* Init Default image generation/list support */ 154 init_default_image_type (); 155 156 params.cmdname = *argv; 157 params.addr = params.ep = 0; 158 159 while (--argc > 0 && **++argv == '-') { 160 while (*++*argv) { 161 switch (**argv) { 162 case 'l': 163 params.lflag = 1; 164 break; 165 case 'A': 166 if ((--argc <= 0) || 167 (params.arch = 168 genimg_get_arch_id (*++argv)) < 0) 169 usage (); 170 goto NXTARG; 171 case 'C': 172 if ((--argc <= 0) || 173 (params.comp = 174 genimg_get_comp_id (*++argv)) < 0) 175 usage (); 176 goto NXTARG; 177 case 'D': 178 if (--argc <= 0) 179 usage (); 180 params.dtc = *++argv; 181 goto NXTARG; 182 183 case 'O': 184 if ((--argc <= 0) || 185 (params.os = 186 genimg_get_os_id (*++argv)) < 0) 187 usage (); 188 goto NXTARG; 189 case 'T': 190 if ((--argc <= 0) || 191 (params.type = 192 genimg_get_type_id (*++argv)) < 0) 193 usage (); 194 goto NXTARG; 195 196 case 'a': 197 if (--argc <= 0) 198 usage (); 199 params.addr = strtoul (*++argv, 200 (char **)&ptr, 16); 201 if (*ptr) { 202 fprintf (stderr, 203 "%s: invalid load address %s\n", 204 params.cmdname, *argv); 205 exit (EXIT_FAILURE); 206 } 207 goto NXTARG; 208 case 'd': 209 if (--argc <= 0) 210 usage (); 211 params.datafile = *++argv; 212 params.dflag = 1; 213 goto NXTARG; 214 case 'e': 215 if (--argc <= 0) 216 usage (); 217 params.ep = strtoul (*++argv, 218 (char **)&ptr, 16); 219 if (*ptr) { 220 fprintf (stderr, 221 "%s: invalid entry point %s\n", 222 params.cmdname, *argv); 223 exit (EXIT_FAILURE); 224 } 225 params.eflag = 1; 226 goto NXTARG; 227 case 'f': 228 if (--argc <= 0) 229 usage (); 230 params.datafile = *++argv; 231 params.fflag = 1; 232 goto NXTARG; 233 case 'n': 234 if (--argc <= 0) 235 usage (); 236 params.imagename = *++argv; 237 goto NXTARG; 238 case 'v': 239 params.vflag++; 240 break; 241 case 'x': 242 params.xflag++; 243 break; 244 default: 245 usage (); 246 } 247 } 248 NXTARG: ; 249 } 250 251 if (argc != 1) 252 usage (); 253 254 /* set tparams as per input type_id */ 255 tparams = mkimage_get_type(params.type); 256 if (tparams == NULL) { 257 fprintf (stderr, "%s: unsupported type %s\n", 258 params.cmdname, genimg_get_type_name(params.type)); 259 exit (EXIT_FAILURE); 260 } 261 262 /* 263 * check the passed arguments parameters meets the requirements 264 * as per image type to be generated/listed 265 */ 266 if (tparams->check_params) 267 if (tparams->check_params (¶ms)) 268 usage (); 269 270 if (!params.eflag) { 271 params.ep = params.addr; 272 /* If XIP, entry point must be after the U-Boot header */ 273 if (params.xflag) 274 params.ep += tparams->header_size; 275 } 276 277 /* 278 * If XIP, ensure the entry point is equal to the load address plus 279 * the size of the U-Boot header. 280 */ 281 if (params.xflag) { 282 if (params.ep != params.addr + tparams->header_size) { 283 fprintf (stderr, 284 "%s: For XIP, the entry point must be the load addr + %lu\n", 285 params.cmdname, 286 (unsigned long)tparams->header_size); 287 exit (EXIT_FAILURE); 288 } 289 } 290 291 params.imagefile = *argv; 292 293 if (!params.fflag){ 294 if (params.lflag) { 295 ifd = open (params.imagefile, O_RDONLY|O_BINARY); 296 } else { 297 ifd = open (params.imagefile, 298 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 299 } 300 301 if (ifd < 0) { 302 fprintf (stderr, "%s: Can't open %s: %s\n", 303 params.cmdname, params.imagefile, 304 strerror(errno)); 305 exit (EXIT_FAILURE); 306 } 307 } 308 309 if (params.lflag) { 310 /* 311 * list header information of existing image 312 */ 313 if (fstat(ifd, &sbuf) < 0) { 314 fprintf (stderr, "%s: Can't stat %s: %s\n", 315 params.cmdname, params.imagefile, 316 strerror(errno)); 317 exit (EXIT_FAILURE); 318 } 319 320 if ((unsigned)sbuf.st_size < tparams->header_size) { 321 fprintf (stderr, 322 "%s: Bad size: \"%s\" is not valid image\n", 323 params.cmdname, params.imagefile); 324 exit (EXIT_FAILURE); 325 } 326 327 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); 328 if (ptr == MAP_FAILED) { 329 fprintf (stderr, "%s: Can't read %s: %s\n", 330 params.cmdname, params.imagefile, 331 strerror(errno)); 332 exit (EXIT_FAILURE); 333 } 334 335 /* 336 * scan through mkimage registry for all supported image types 337 * and verify the input image file header for match 338 * Print the image information for matched image type 339 * Returns the error code if not matched 340 */ 341 retval = mkimage_verify_print_header (ptr, &sbuf); 342 343 (void) munmap((void *)ptr, sbuf.st_size); 344 (void) close (ifd); 345 346 exit (retval); 347 } else if (params.fflag) { 348 if (tparams->fflag_handle) 349 /* 350 * in some cases, some additional processing needs 351 * to be done if fflag is defined 352 * 353 * For ex. fit_handle_file for Fit file support 354 */ 355 retval = tparams->fflag_handle(¶ms); 356 357 exit (retval); 358 } 359 360 /* 361 * Must be -w then: 362 * 363 * write dummy header, to be fixed later 364 */ 365 memset (tparams->hdr, 0, tparams->header_size); 366 367 if (write(ifd, tparams->hdr, tparams->header_size) 368 != tparams->header_size) { 369 fprintf (stderr, "%s: Write error on %s: %s\n", 370 params.cmdname, params.imagefile, strerror(errno)); 371 exit (EXIT_FAILURE); 372 } 373 374 if (params.type == IH_TYPE_MULTI || params.type == IH_TYPE_SCRIPT) { 375 char *file = params.datafile; 376 uint32_t size; 377 378 for (;;) { 379 char *sep = NULL; 380 381 if (file) { 382 if ((sep = strchr(file, ':')) != NULL) { 383 *sep = '\0'; 384 } 385 386 if (stat (file, &sbuf) < 0) { 387 fprintf (stderr, "%s: Can't stat %s: %s\n", 388 params.cmdname, file, strerror(errno)); 389 exit (EXIT_FAILURE); 390 } 391 size = cpu_to_uimage (sbuf.st_size); 392 } else { 393 size = 0; 394 } 395 396 if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 397 fprintf (stderr, "%s: Write error on %s: %s\n", 398 params.cmdname, params.imagefile, 399 strerror(errno)); 400 exit (EXIT_FAILURE); 401 } 402 403 if (!file) { 404 break; 405 } 406 407 if (sep) { 408 *sep = ':'; 409 file = sep + 1; 410 } else { 411 file = NULL; 412 } 413 } 414 415 file = params.datafile; 416 417 for (;;) { 418 char *sep = strchr(file, ':'); 419 if (sep) { 420 *sep = '\0'; 421 copy_file (ifd, file, 1); 422 *sep++ = ':'; 423 file = sep; 424 } else { 425 copy_file (ifd, file, 0); 426 break; 427 } 428 } 429 } else { 430 copy_file (ifd, params.datafile, 0); 431 } 432 433 /* We're a bit of paranoid */ 434 #if defined(_POSIX_SYNCHRONIZED_IO) && \ 435 !defined(__sun__) && \ 436 !defined(__FreeBSD__) && \ 437 !defined(__APPLE__) 438 (void) fdatasync (ifd); 439 #else 440 (void) fsync (ifd); 441 #endif 442 443 if (fstat(ifd, &sbuf) < 0) { 444 fprintf (stderr, "%s: Can't stat %s: %s\n", 445 params.cmdname, params.imagefile, strerror(errno)); 446 exit (EXIT_FAILURE); 447 } 448 449 ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 450 if (ptr == MAP_FAILED) { 451 fprintf (stderr, "%s: Can't map %s: %s\n", 452 params.cmdname, params.imagefile, strerror(errno)); 453 exit (EXIT_FAILURE); 454 } 455 456 /* Setup the image header as per input image type*/ 457 if (tparams->set_header) 458 tparams->set_header (ptr, &sbuf, ifd, ¶ms); 459 else { 460 fprintf (stderr, "%s: Can't set header for %s: %s\n", 461 params.cmdname, tparams->name, strerror(errno)); 462 exit (EXIT_FAILURE); 463 } 464 465 /* Print the image information by processing image header */ 466 if (tparams->print_header) 467 tparams->print_header (ptr); 468 else { 469 fprintf (stderr, "%s: Can't print header for %s: %s\n", 470 params.cmdname, tparams->name, strerror(errno)); 471 exit (EXIT_FAILURE); 472 } 473 474 (void) munmap((void *)ptr, sbuf.st_size); 475 476 /* We're a bit of paranoid */ 477 #if defined(_POSIX_SYNCHRONIZED_IO) && \ 478 !defined(__sun__) && \ 479 !defined(__FreeBSD__) && \ 480 !defined(__APPLE__) 481 (void) fdatasync (ifd); 482 #else 483 (void) fsync (ifd); 484 #endif 485 486 if (close(ifd)) { 487 fprintf (stderr, "%s: Write error on %s: %s\n", 488 params.cmdname, params.imagefile, strerror(errno)); 489 exit (EXIT_FAILURE); 490 } 491 492 exit (EXIT_SUCCESS); 493 } 494 495 static void 496 copy_file (int ifd, const char *datafile, int pad) 497 { 498 int dfd; 499 struct stat sbuf; 500 unsigned char *ptr; 501 int tail; 502 int zero = 0; 503 int offset = 0; 504 int size; 505 struct image_type_params *tparams = mkimage_get_type (params.type); 506 507 if (params.vflag) { 508 fprintf (stderr, "Adding Image %s\n", datafile); 509 } 510 511 if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 512 fprintf (stderr, "%s: Can't open %s: %s\n", 513 params.cmdname, datafile, strerror(errno)); 514 exit (EXIT_FAILURE); 515 } 516 517 if (fstat(dfd, &sbuf) < 0) { 518 fprintf (stderr, "%s: Can't stat %s: %s\n", 519 params.cmdname, datafile, strerror(errno)); 520 exit (EXIT_FAILURE); 521 } 522 523 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); 524 if (ptr == MAP_FAILED) { 525 fprintf (stderr, "%s: Can't read %s: %s\n", 526 params.cmdname, datafile, strerror(errno)); 527 exit (EXIT_FAILURE); 528 } 529 530 if (params.xflag) { 531 unsigned char *p = NULL; 532 /* 533 * XIP: do not append the image_header_t at the 534 * beginning of the file, but consume the space 535 * reserved for it. 536 */ 537 538 if ((unsigned)sbuf.st_size < tparams->header_size) { 539 fprintf (stderr, 540 "%s: Bad size: \"%s\" is too small for XIP\n", 541 params.cmdname, datafile); 542 exit (EXIT_FAILURE); 543 } 544 545 for (p = ptr; p < ptr + tparams->header_size; p++) { 546 if ( *p != 0xff ) { 547 fprintf (stderr, 548 "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 549 params.cmdname, datafile); 550 exit (EXIT_FAILURE); 551 } 552 } 553 554 offset = tparams->header_size; 555 } 556 557 size = sbuf.st_size - offset; 558 if (write(ifd, ptr + offset, size) != size) { 559 fprintf (stderr, "%s: Write error on %s: %s\n", 560 params.cmdname, params.imagefile, strerror(errno)); 561 exit (EXIT_FAILURE); 562 } 563 564 if (pad && ((tail = size % 4) != 0)) { 565 566 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 567 fprintf (stderr, "%s: Write error on %s: %s\n", 568 params.cmdname, params.imagefile, 569 strerror(errno)); 570 exit (EXIT_FAILURE); 571 } 572 } 573 574 (void) munmap((void *)ptr, sbuf.st_size); 575 (void) close (dfd); 576 } 577 578 void 579 usage () 580 { 581 fprintf (stderr, "Usage: %s -l image\n" 582 " -l ==> list image header information\n", 583 params.cmdname); 584 fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp " 585 "-a addr -e ep -n name -d data_file[:data_file...] image\n" 586 " -A ==> set architecture to 'arch'\n" 587 " -O ==> set operating system to 'os'\n" 588 " -T ==> set image type to 'type'\n" 589 " -C ==> set compression type 'comp'\n" 590 " -a ==> set load address to 'addr' (hex)\n" 591 " -e ==> set entry point to 'ep' (hex)\n" 592 " -n ==> set image name to 'name'\n" 593 " -d ==> use image data from 'datafile'\n" 594 " -x ==> set XIP (execute in place)\n", 595 params.cmdname); 596 fprintf (stderr, " %s [-D dtc_options] -f fit-image.its fit-image\n", 597 params.cmdname); 598 599 exit (EXIT_FAILURE); 600 } 601