1 /* 2 * (C) Copyright 2008 Semihalf 3 * 4 * (C) Copyright 2000-2009 5 * DENX Software Engineering 6 * Wolfgang Denk, wd@denx.de 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include "mkimage.h" 12 #include <image.h> 13 #include <version.h> 14 15 static void copy_file(int, const char *, int); 16 17 /* parameters initialized by core will be used by the image type code */ 18 static struct image_tool_params params = { 19 .os = IH_OS_LINUX, 20 .arch = IH_ARCH_PPC, 21 .type = IH_TYPE_KERNEL, 22 .comp = IH_COMP_GZIP, 23 .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS, 24 .imagename = "", 25 .imagename2 = "", 26 }; 27 28 static int h_compare_image_name(const void *vtype1, const void *vtype2) 29 { 30 const int *type1 = vtype1; 31 const int *type2 = vtype2; 32 const char *name1 = genimg_get_type_short_name(*type1); 33 const char *name2 = genimg_get_type_short_name(*type2); 34 35 return strcmp(name1, name2); 36 } 37 38 /* Show all image types supported by mkimage */ 39 static void show_image_types(void) 40 { 41 struct image_type_params *tparams; 42 int order[IH_TYPE_COUNT]; 43 int count; 44 int type; 45 int i; 46 47 /* Sort the names in order of short name for easier reading */ 48 memset(order, '\0', sizeof(order)); 49 for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) { 50 tparams = imagetool_get_type(type); 51 if (tparams) 52 order[count++] = type; 53 } 54 qsort(order, count, sizeof(int), h_compare_image_name); 55 56 fprintf(stderr, "\nInvalid image type. Supported image types:\n"); 57 for (i = 0; i < count; i++) { 58 type = order[i]; 59 tparams = imagetool_get_type(type); 60 if (tparams) { 61 fprintf(stderr, "\t%-15s %s\n", 62 genimg_get_type_short_name(type), 63 genimg_get_type_name(type)); 64 } 65 } 66 fprintf(stderr, "\n"); 67 } 68 69 static void usage(const char *msg) 70 { 71 fprintf(stderr, "Error: %s\n", msg); 72 fprintf(stderr, "Usage: %s -l image\n" 73 " -l ==> list image header information\n", 74 params.cmdname); 75 fprintf(stderr, 76 " %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n" 77 " -A ==> set architecture to 'arch'\n" 78 " -O ==> set operating system to 'os'\n" 79 " -T ==> set image type to 'type'\n" 80 " -C ==> set compression type 'comp'\n" 81 " -a ==> set load address to 'addr' (hex)\n" 82 " -e ==> set entry point to 'ep' (hex)\n" 83 " -n ==> set image name to 'name'\n" 84 " -d ==> use image data from 'datafile'\n" 85 " -x ==> set XIP (execute in place)\n", 86 params.cmdname); 87 fprintf(stderr, 88 " %s [-D dtc_options] [-f fit-image.its|-f auto|-F] fit-image\n", 89 params.cmdname); 90 fprintf(stderr, 91 " -D => set all options for device tree compiler\n" 92 " -f => input filename for FIT source\n"); 93 #ifdef CONFIG_FIT_SIGNATURE 94 fprintf(stderr, 95 "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n" 96 " -k => set directory containing private keys\n" 97 " -K => write public keys to this .dtb file\n" 98 " -c => add comment in signature node\n" 99 " -F => re-sign existing FIT image\n" 100 " -r => mark keys used as 'required' in dtb\n"); 101 #else 102 fprintf(stderr, 103 "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n"); 104 #endif 105 fprintf(stderr, " %s -V ==> print version information and exit\n", 106 params.cmdname); 107 fprintf(stderr, "Use -T to see a list of available image types\n"); 108 109 exit(EXIT_FAILURE); 110 } 111 112 static void process_args(int argc, char **argv) 113 { 114 char *ptr; 115 int type = IH_TYPE_INVALID; 116 char *datafile = NULL; 117 int expecting; 118 int opt; 119 120 expecting = IH_TYPE_COUNT; /* Unknown */ 121 while ((opt = getopt(argc, argv, 122 "-a:A:cC:d:D:e:f:Fk:K:ln:O:rR:sT:vVx")) != -1) { 123 switch (opt) { 124 case 'a': 125 params.addr = strtoull(optarg, &ptr, 16); 126 if (*ptr) { 127 fprintf(stderr, "%s: invalid load address %s\n", 128 params.cmdname, optarg); 129 exit(EXIT_FAILURE); 130 } 131 break; 132 case 'A': 133 params.arch = genimg_get_arch_id(optarg); 134 if (params.arch < 0) 135 usage("Invalid architecture"); 136 break; 137 case 'c': 138 params.comment = optarg; 139 break; 140 case 'C': 141 params.comp = genimg_get_comp_id(optarg); 142 if (params.comp < 0) 143 usage("Invalid compression type"); 144 break; 145 case 'd': 146 params.datafile = optarg; 147 params.dflag = 1; 148 break; 149 case 'D': 150 params.dtc = optarg; 151 break; 152 case 'e': 153 params.ep = strtoull(optarg, &ptr, 16); 154 if (*ptr) { 155 fprintf(stderr, "%s: invalid entry point %s\n", 156 params.cmdname, optarg); 157 exit(EXIT_FAILURE); 158 } 159 params.eflag = 1; 160 break; 161 case 'f': 162 datafile = optarg; 163 params.auto_its = !strcmp(datafile, "auto"); 164 /* no break */ 165 case 'F': 166 /* 167 * The flattened image tree (FIT) format 168 * requires a flattened device tree image type 169 */ 170 params.fit_image_type = params.type; 171 params.type = IH_TYPE_FLATDT; 172 params.fflag = 1; 173 break; 174 case 'k': 175 params.keydir = optarg; 176 break; 177 case 'K': 178 params.keydest = optarg; 179 break; 180 case 'l': 181 params.lflag = 1; 182 break; 183 case 'n': 184 params.imagename = optarg; 185 break; 186 case 'O': 187 params.os = genimg_get_os_id(optarg); 188 if (params.os < 0) 189 usage("Invalid operating system"); 190 break; 191 case 'r': 192 params.require_keys = 1; 193 break; 194 case 'R': 195 /* 196 * This entry is for the second configuration 197 * file, if only one is not enough. 198 */ 199 params.imagename2 = optarg; 200 break; 201 case 's': 202 params.skipcpy = 1; 203 break; 204 case 'T': 205 type = genimg_get_type_id(optarg); 206 if (type < 0) { 207 show_image_types(); 208 usage("Invalid image type"); 209 } 210 expecting = type; 211 break; 212 case 'v': 213 params.vflag++; 214 break; 215 case 'V': 216 printf("mkimage version %s\n", PLAIN_VERSION); 217 exit(EXIT_SUCCESS); 218 case 'x': 219 params.xflag++; 220 break; 221 case 1: 222 if (expecting == type || optind == argc) { 223 params.imagefile = optarg; 224 expecting = IH_TYPE_INVALID; 225 } 226 break; 227 default: 228 usage("Invalid option"); 229 } 230 } 231 232 /* 233 * For auto-generated FIT images we need to know the image type to put 234 * in the FIT, which is separate from the file's image type (which 235 * will always be IH_TYPE_FLATDT in this case). 236 */ 237 if (params.type == IH_TYPE_FLATDT) { 238 params.fit_image_type = type; 239 if (!params.auto_its) 240 params.datafile = datafile; 241 } else if (type != IH_TYPE_INVALID) { 242 params.type = type; 243 } 244 245 if (!params.imagefile) 246 usage("Missing output filename"); 247 } 248 249 250 int main(int argc, char **argv) 251 { 252 int ifd = -1; 253 struct stat sbuf; 254 char *ptr; 255 int retval = 0; 256 struct image_type_params *tparams = NULL; 257 int pad_len = 0; 258 int dfd; 259 260 params.cmdname = *argv; 261 params.addr = 0; 262 params.ep = 0; 263 264 process_args(argc, argv); 265 266 /* set tparams as per input type_id */ 267 tparams = imagetool_get_type(params.type); 268 if (tparams == NULL) { 269 fprintf (stderr, "%s: unsupported type %s\n", 270 params.cmdname, genimg_get_type_name(params.type)); 271 exit (EXIT_FAILURE); 272 } 273 274 /* 275 * check the passed arguments parameters meets the requirements 276 * as per image type to be generated/listed 277 */ 278 if (tparams->check_params) 279 if (tparams->check_params (¶ms)) 280 usage("Bad parameters for image type"); 281 282 if (!params.eflag) { 283 params.ep = params.addr; 284 /* If XIP, entry point must be after the U-Boot header */ 285 if (params.xflag) 286 params.ep += tparams->header_size; 287 } 288 289 if (params.fflag){ 290 if (tparams->fflag_handle) 291 /* 292 * in some cases, some additional processing needs 293 * to be done if fflag is defined 294 * 295 * For ex. fit_handle_file for Fit file support 296 */ 297 retval = tparams->fflag_handle(¶ms); 298 299 if (retval != EXIT_SUCCESS) 300 exit (retval); 301 } 302 303 if (params.lflag || params.fflag) { 304 ifd = open (params.imagefile, O_RDONLY|O_BINARY); 305 } else { 306 ifd = open (params.imagefile, 307 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 308 } 309 310 if (ifd < 0) { 311 fprintf (stderr, "%s: Can't open %s: %s\n", 312 params.cmdname, params.imagefile, 313 strerror(errno)); 314 exit (EXIT_FAILURE); 315 } 316 317 if (params.lflag || params.fflag) { 318 /* 319 * list header information of existing image 320 */ 321 if (fstat(ifd, &sbuf) < 0) { 322 fprintf (stderr, "%s: Can't stat %s: %s\n", 323 params.cmdname, params.imagefile, 324 strerror(errno)); 325 exit (EXIT_FAILURE); 326 } 327 328 if ((unsigned)sbuf.st_size < tparams->header_size) { 329 fprintf (stderr, 330 "%s: Bad size: \"%s\" is not valid image\n", 331 params.cmdname, params.imagefile); 332 exit (EXIT_FAILURE); 333 } 334 335 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); 336 if (ptr == MAP_FAILED) { 337 fprintf (stderr, "%s: Can't read %s: %s\n", 338 params.cmdname, params.imagefile, 339 strerror(errno)); 340 exit (EXIT_FAILURE); 341 } 342 343 /* 344 * scan through mkimage registry for all supported image types 345 * and verify the input image file header for match 346 * Print the image information for matched image type 347 * Returns the error code if not matched 348 */ 349 retval = imagetool_verify_print_header(ptr, &sbuf, 350 tparams, ¶ms); 351 352 (void) munmap((void *)ptr, sbuf.st_size); 353 (void) close (ifd); 354 355 exit (retval); 356 } 357 358 if ((params.type != IH_TYPE_MULTI) && (params.type != IH_TYPE_SCRIPT)) { 359 dfd = open(params.datafile, O_RDONLY | O_BINARY); 360 if (dfd < 0) { 361 fprintf(stderr, "%s: Can't open %s: %s\n", 362 params.cmdname, params.datafile, 363 strerror(errno)); 364 exit(EXIT_FAILURE); 365 } 366 367 if (fstat(dfd, &sbuf) < 0) { 368 fprintf(stderr, "%s: Can't stat %s: %s\n", 369 params.cmdname, params.datafile, 370 strerror(errno)); 371 exit(EXIT_FAILURE); 372 } 373 374 params.file_size = sbuf.st_size + tparams->header_size; 375 close(dfd); 376 } 377 378 /* 379 * In case there an header with a variable 380 * length will be added, the corresponding 381 * function is called. This is responsible to 382 * allocate memory for the header itself. 383 */ 384 if (tparams->vrec_header) 385 pad_len = tparams->vrec_header(¶ms, tparams); 386 else 387 memset(tparams->hdr, 0, tparams->header_size); 388 389 if (write(ifd, tparams->hdr, tparams->header_size) 390 != tparams->header_size) { 391 fprintf (stderr, "%s: Write error on %s: %s\n", 392 params.cmdname, params.imagefile, strerror(errno)); 393 exit (EXIT_FAILURE); 394 } 395 396 if (!params.skipcpy) { 397 if (params.type == IH_TYPE_MULTI || 398 params.type == IH_TYPE_SCRIPT) { 399 char *file = params.datafile; 400 uint32_t size; 401 402 for (;;) { 403 char *sep = NULL; 404 405 if (file) { 406 if ((sep = strchr(file, ':')) != NULL) { 407 *sep = '\0'; 408 } 409 410 if (stat (file, &sbuf) < 0) { 411 fprintf (stderr, "%s: Can't stat %s: %s\n", 412 params.cmdname, file, strerror(errno)); 413 exit (EXIT_FAILURE); 414 } 415 size = cpu_to_uimage (sbuf.st_size); 416 } else { 417 size = 0; 418 } 419 420 if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 421 fprintf (stderr, "%s: Write error on %s: %s\n", 422 params.cmdname, params.imagefile, 423 strerror(errno)); 424 exit (EXIT_FAILURE); 425 } 426 427 if (!file) { 428 break; 429 } 430 431 if (sep) { 432 *sep = ':'; 433 file = sep + 1; 434 } else { 435 file = NULL; 436 } 437 } 438 439 file = params.datafile; 440 441 for (;;) { 442 char *sep = strchr(file, ':'); 443 if (sep) { 444 *sep = '\0'; 445 copy_file (ifd, file, 1); 446 *sep++ = ':'; 447 file = sep; 448 } else { 449 copy_file (ifd, file, 0); 450 break; 451 } 452 } 453 } else if (params.type == IH_TYPE_PBLIMAGE) { 454 /* PBL has special Image format, implements its' own */ 455 pbl_load_uboot(ifd, ¶ms); 456 } else { 457 copy_file(ifd, params.datafile, pad_len); 458 } 459 } 460 461 /* We're a bit of paranoid */ 462 #if defined(_POSIX_SYNCHRONIZED_IO) && \ 463 !defined(__sun__) && \ 464 !defined(__FreeBSD__) && \ 465 !defined(__OpenBSD__) && \ 466 !defined(__APPLE__) 467 (void) fdatasync (ifd); 468 #else 469 (void) fsync (ifd); 470 #endif 471 472 if (fstat(ifd, &sbuf) < 0) { 473 fprintf (stderr, "%s: Can't stat %s: %s\n", 474 params.cmdname, params.imagefile, strerror(errno)); 475 exit (EXIT_FAILURE); 476 } 477 params.file_size = sbuf.st_size; 478 479 ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 480 if (ptr == MAP_FAILED) { 481 fprintf (stderr, "%s: Can't map %s: %s\n", 482 params.cmdname, params.imagefile, strerror(errno)); 483 exit (EXIT_FAILURE); 484 } 485 486 /* Setup the image header as per input image type*/ 487 if (tparams->set_header) 488 tparams->set_header (ptr, &sbuf, ifd, ¶ms); 489 else { 490 fprintf (stderr, "%s: Can't set header for %s: %s\n", 491 params.cmdname, tparams->name, strerror(errno)); 492 exit (EXIT_FAILURE); 493 } 494 495 /* Print the image information by processing image header */ 496 if (tparams->print_header) 497 tparams->print_header (ptr); 498 else { 499 fprintf (stderr, "%s: Can't print header for %s: %s\n", 500 params.cmdname, tparams->name, strerror(errno)); 501 exit (EXIT_FAILURE); 502 } 503 504 (void) munmap((void *)ptr, sbuf.st_size); 505 506 /* We're a bit of paranoid */ 507 #if defined(_POSIX_SYNCHRONIZED_IO) && \ 508 !defined(__sun__) && \ 509 !defined(__FreeBSD__) && \ 510 !defined(__OpenBSD__) && \ 511 !defined(__APPLE__) 512 (void) fdatasync (ifd); 513 #else 514 (void) fsync (ifd); 515 #endif 516 517 if (close(ifd)) { 518 fprintf (stderr, "%s: Write error on %s: %s\n", 519 params.cmdname, params.imagefile, strerror(errno)); 520 exit (EXIT_FAILURE); 521 } 522 523 exit (EXIT_SUCCESS); 524 } 525 526 static void 527 copy_file (int ifd, const char *datafile, int pad) 528 { 529 int dfd; 530 struct stat sbuf; 531 unsigned char *ptr; 532 int tail; 533 int zero = 0; 534 uint8_t zeros[4096]; 535 int offset = 0; 536 int size; 537 struct image_type_params *tparams = imagetool_get_type(params.type); 538 539 memset(zeros, 0, sizeof(zeros)); 540 541 if (params.vflag) { 542 fprintf (stderr, "Adding Image %s\n", datafile); 543 } 544 545 if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 546 fprintf (stderr, "%s: Can't open %s: %s\n", 547 params.cmdname, datafile, strerror(errno)); 548 exit (EXIT_FAILURE); 549 } 550 551 if (fstat(dfd, &sbuf) < 0) { 552 fprintf (stderr, "%s: Can't stat %s: %s\n", 553 params.cmdname, datafile, strerror(errno)); 554 exit (EXIT_FAILURE); 555 } 556 557 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); 558 if (ptr == MAP_FAILED) { 559 fprintf (stderr, "%s: Can't read %s: %s\n", 560 params.cmdname, datafile, strerror(errno)); 561 exit (EXIT_FAILURE); 562 } 563 564 if (params.xflag) { 565 unsigned char *p = NULL; 566 /* 567 * XIP: do not append the image_header_t at the 568 * beginning of the file, but consume the space 569 * reserved for it. 570 */ 571 572 if ((unsigned)sbuf.st_size < tparams->header_size) { 573 fprintf (stderr, 574 "%s: Bad size: \"%s\" is too small for XIP\n", 575 params.cmdname, datafile); 576 exit (EXIT_FAILURE); 577 } 578 579 for (p = ptr; p < ptr + tparams->header_size; p++) { 580 if ( *p != 0xff ) { 581 fprintf (stderr, 582 "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 583 params.cmdname, datafile); 584 exit (EXIT_FAILURE); 585 } 586 } 587 588 offset = tparams->header_size; 589 } 590 591 size = sbuf.st_size - offset; 592 if (write(ifd, ptr + offset, size) != size) { 593 fprintf (stderr, "%s: Write error on %s: %s\n", 594 params.cmdname, params.imagefile, strerror(errno)); 595 exit (EXIT_FAILURE); 596 } 597 598 tail = size % 4; 599 if ((pad == 1) && (tail != 0)) { 600 601 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 602 fprintf (stderr, "%s: Write error on %s: %s\n", 603 params.cmdname, params.imagefile, 604 strerror(errno)); 605 exit (EXIT_FAILURE); 606 } 607 } else if (pad > 1) { 608 while (pad > 0) { 609 int todo = sizeof(zeros); 610 611 if (todo > pad) 612 todo = pad; 613 if (write(ifd, (char *)&zeros, todo) != todo) { 614 fprintf(stderr, "%s: Write error on %s: %s\n", 615 params.cmdname, params.imagefile, 616 strerror(errno)); 617 exit(EXIT_FAILURE); 618 } 619 pad -= todo; 620 } 621 } 622 623 (void) munmap((void *)ptr, sbuf.st_size); 624 (void) close (dfd); 625 } 626