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] 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 params.datafile = optarg; 163 /* no break */ 164 case 'F': 165 /* 166 * The flattened image tree (FIT) format 167 * requires a flattened device tree image type 168 */ 169 params.fit_image_type = params.type; 170 params.type = IH_TYPE_FLATDT; 171 params.fflag = 1; 172 break; 173 case 'k': 174 params.keydir = optarg; 175 break; 176 case 'K': 177 params.keydest = optarg; 178 break; 179 case 'l': 180 params.lflag = 1; 181 break; 182 case 'n': 183 params.imagename = optarg; 184 break; 185 case 'O': 186 params.os = genimg_get_os_id(optarg); 187 if (params.os < 0) 188 usage("Invalid operating system"); 189 break; 190 case 'r': 191 params.require_keys = 1; 192 break; 193 case 'R': 194 /* 195 * This entry is for the second configuration 196 * file, if only one is not enough. 197 */ 198 params.imagename2 = optarg; 199 break; 200 case 's': 201 params.skipcpy = 1; 202 break; 203 case 'T': 204 type = genimg_get_type_id(optarg); 205 if (type < 0) { 206 show_image_types(); 207 usage("Invalid image type"); 208 } 209 expecting = type; 210 break; 211 case 'v': 212 params.vflag++; 213 break; 214 case 'V': 215 printf("mkimage version %s\n", PLAIN_VERSION); 216 exit(EXIT_SUCCESS); 217 case 'x': 218 params.xflag++; 219 break; 220 case 1: 221 if (expecting == type || optind == argc) { 222 params.imagefile = optarg; 223 expecting = IH_TYPE_INVALID; 224 } 225 break; 226 default: 227 usage("Invalid option"); 228 } 229 } 230 231 /* 232 * For auto-generated FIT images we need to know the image type to put 233 * in the FIT, which is separate from the file's image type (which 234 * will always be IH_TYPE_FLATDT in this case). 235 */ 236 if (params.type == IH_TYPE_FLATDT) { 237 params.fit_image_type = type; 238 params.datafile = datafile; 239 } else if (type != IH_TYPE_INVALID) { 240 params.type = type; 241 } 242 243 if (!params.imagefile) 244 usage("Missing output filename"); 245 } 246 247 248 int main(int argc, char **argv) 249 { 250 int ifd = -1; 251 struct stat sbuf; 252 char *ptr; 253 int retval = 0; 254 struct image_type_params *tparams = NULL; 255 int pad_len = 0; 256 int dfd; 257 258 params.cmdname = *argv; 259 params.addr = 0; 260 params.ep = 0; 261 262 process_args(argc, argv); 263 264 /* set tparams as per input type_id */ 265 tparams = imagetool_get_type(params.type); 266 if (tparams == NULL) { 267 fprintf (stderr, "%s: unsupported type %s\n", 268 params.cmdname, genimg_get_type_name(params.type)); 269 exit (EXIT_FAILURE); 270 } 271 272 /* 273 * check the passed arguments parameters meets the requirements 274 * as per image type to be generated/listed 275 */ 276 if (tparams->check_params) 277 if (tparams->check_params (¶ms)) 278 usage("Bad parameters for image type"); 279 280 if (!params.eflag) { 281 params.ep = params.addr; 282 /* If XIP, entry point must be after the U-Boot header */ 283 if (params.xflag) 284 params.ep += tparams->header_size; 285 } 286 287 if (params.fflag){ 288 if (tparams->fflag_handle) 289 /* 290 * in some cases, some additional processing needs 291 * to be done if fflag is defined 292 * 293 * For ex. fit_handle_file for Fit file support 294 */ 295 retval = tparams->fflag_handle(¶ms); 296 297 if (retval != EXIT_SUCCESS) 298 exit (retval); 299 } 300 301 if (params.lflag || params.fflag) { 302 ifd = open (params.imagefile, O_RDONLY|O_BINARY); 303 } else { 304 ifd = open (params.imagefile, 305 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 306 } 307 308 if (ifd < 0) { 309 fprintf (stderr, "%s: Can't open %s: %s\n", 310 params.cmdname, params.imagefile, 311 strerror(errno)); 312 exit (EXIT_FAILURE); 313 } 314 315 if (params.lflag || params.fflag) { 316 /* 317 * list header information of existing image 318 */ 319 if (fstat(ifd, &sbuf) < 0) { 320 fprintf (stderr, "%s: Can't stat %s: %s\n", 321 params.cmdname, params.imagefile, 322 strerror(errno)); 323 exit (EXIT_FAILURE); 324 } 325 326 if ((unsigned)sbuf.st_size < tparams->header_size) { 327 fprintf (stderr, 328 "%s: Bad size: \"%s\" is not valid image\n", 329 params.cmdname, params.imagefile); 330 exit (EXIT_FAILURE); 331 } 332 333 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); 334 if (ptr == MAP_FAILED) { 335 fprintf (stderr, "%s: Can't read %s: %s\n", 336 params.cmdname, params.imagefile, 337 strerror(errno)); 338 exit (EXIT_FAILURE); 339 } 340 341 /* 342 * scan through mkimage registry for all supported image types 343 * and verify the input image file header for match 344 * Print the image information for matched image type 345 * Returns the error code if not matched 346 */ 347 retval = imagetool_verify_print_header(ptr, &sbuf, 348 tparams, ¶ms); 349 350 (void) munmap((void *)ptr, sbuf.st_size); 351 (void) close (ifd); 352 353 exit (retval); 354 } 355 356 if ((params.type != IH_TYPE_MULTI) && (params.type != IH_TYPE_SCRIPT)) { 357 dfd = open(params.datafile, O_RDONLY | O_BINARY); 358 if (dfd < 0) { 359 fprintf(stderr, "%s: Can't open %s: %s\n", 360 params.cmdname, params.datafile, 361 strerror(errno)); 362 exit(EXIT_FAILURE); 363 } 364 365 if (fstat(dfd, &sbuf) < 0) { 366 fprintf(stderr, "%s: Can't stat %s: %s\n", 367 params.cmdname, params.datafile, 368 strerror(errno)); 369 exit(EXIT_FAILURE); 370 } 371 372 params.file_size = sbuf.st_size + tparams->header_size; 373 close(dfd); 374 } 375 376 /* 377 * In case there an header with a variable 378 * length will be added, the corresponding 379 * function is called. This is responsible to 380 * allocate memory for the header itself. 381 */ 382 if (tparams->vrec_header) 383 pad_len = tparams->vrec_header(¶ms, tparams); 384 else 385 memset(tparams->hdr, 0, tparams->header_size); 386 387 if (write(ifd, tparams->hdr, tparams->header_size) 388 != tparams->header_size) { 389 fprintf (stderr, "%s: Write error on %s: %s\n", 390 params.cmdname, params.imagefile, strerror(errno)); 391 exit (EXIT_FAILURE); 392 } 393 394 if (!params.skipcpy) { 395 if (params.type == IH_TYPE_MULTI || 396 params.type == IH_TYPE_SCRIPT) { 397 char *file = params.datafile; 398 uint32_t size; 399 400 for (;;) { 401 char *sep = NULL; 402 403 if (file) { 404 if ((sep = strchr(file, ':')) != NULL) { 405 *sep = '\0'; 406 } 407 408 if (stat (file, &sbuf) < 0) { 409 fprintf (stderr, "%s: Can't stat %s: %s\n", 410 params.cmdname, file, strerror(errno)); 411 exit (EXIT_FAILURE); 412 } 413 size = cpu_to_uimage (sbuf.st_size); 414 } else { 415 size = 0; 416 } 417 418 if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 419 fprintf (stderr, "%s: Write error on %s: %s\n", 420 params.cmdname, params.imagefile, 421 strerror(errno)); 422 exit (EXIT_FAILURE); 423 } 424 425 if (!file) { 426 break; 427 } 428 429 if (sep) { 430 *sep = ':'; 431 file = sep + 1; 432 } else { 433 file = NULL; 434 } 435 } 436 437 file = params.datafile; 438 439 for (;;) { 440 char *sep = strchr(file, ':'); 441 if (sep) { 442 *sep = '\0'; 443 copy_file (ifd, file, 1); 444 *sep++ = ':'; 445 file = sep; 446 } else { 447 copy_file (ifd, file, 0); 448 break; 449 } 450 } 451 } else if (params.type == IH_TYPE_PBLIMAGE) { 452 /* PBL has special Image format, implements its' own */ 453 pbl_load_uboot(ifd, ¶ms); 454 } else { 455 copy_file(ifd, params.datafile, pad_len); 456 } 457 } 458 459 /* We're a bit of paranoid */ 460 #if defined(_POSIX_SYNCHRONIZED_IO) && \ 461 !defined(__sun__) && \ 462 !defined(__FreeBSD__) && \ 463 !defined(__OpenBSD__) && \ 464 !defined(__APPLE__) 465 (void) fdatasync (ifd); 466 #else 467 (void) fsync (ifd); 468 #endif 469 470 if (fstat(ifd, &sbuf) < 0) { 471 fprintf (stderr, "%s: Can't stat %s: %s\n", 472 params.cmdname, params.imagefile, strerror(errno)); 473 exit (EXIT_FAILURE); 474 } 475 params.file_size = sbuf.st_size; 476 477 ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 478 if (ptr == MAP_FAILED) { 479 fprintf (stderr, "%s: Can't map %s: %s\n", 480 params.cmdname, params.imagefile, strerror(errno)); 481 exit (EXIT_FAILURE); 482 } 483 484 /* Setup the image header as per input image type*/ 485 if (tparams->set_header) 486 tparams->set_header (ptr, &sbuf, ifd, ¶ms); 487 else { 488 fprintf (stderr, "%s: Can't set header for %s: %s\n", 489 params.cmdname, tparams->name, strerror(errno)); 490 exit (EXIT_FAILURE); 491 } 492 493 /* Print the image information by processing image header */ 494 if (tparams->print_header) 495 tparams->print_header (ptr); 496 else { 497 fprintf (stderr, "%s: Can't print header for %s: %s\n", 498 params.cmdname, tparams->name, strerror(errno)); 499 exit (EXIT_FAILURE); 500 } 501 502 (void) munmap((void *)ptr, sbuf.st_size); 503 504 /* We're a bit of paranoid */ 505 #if defined(_POSIX_SYNCHRONIZED_IO) && \ 506 !defined(__sun__) && \ 507 !defined(__FreeBSD__) && \ 508 !defined(__OpenBSD__) && \ 509 !defined(__APPLE__) 510 (void) fdatasync (ifd); 511 #else 512 (void) fsync (ifd); 513 #endif 514 515 if (close(ifd)) { 516 fprintf (stderr, "%s: Write error on %s: %s\n", 517 params.cmdname, params.imagefile, strerror(errno)); 518 exit (EXIT_FAILURE); 519 } 520 521 exit (EXIT_SUCCESS); 522 } 523 524 static void 525 copy_file (int ifd, const char *datafile, int pad) 526 { 527 int dfd; 528 struct stat sbuf; 529 unsigned char *ptr; 530 int tail; 531 int zero = 0; 532 uint8_t zeros[4096]; 533 int offset = 0; 534 int size; 535 struct image_type_params *tparams = imagetool_get_type(params.type); 536 537 memset(zeros, 0, sizeof(zeros)); 538 539 if (params.vflag) { 540 fprintf (stderr, "Adding Image %s\n", datafile); 541 } 542 543 if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 544 fprintf (stderr, "%s: Can't open %s: %s\n", 545 params.cmdname, datafile, strerror(errno)); 546 exit (EXIT_FAILURE); 547 } 548 549 if (fstat(dfd, &sbuf) < 0) { 550 fprintf (stderr, "%s: Can't stat %s: %s\n", 551 params.cmdname, datafile, strerror(errno)); 552 exit (EXIT_FAILURE); 553 } 554 555 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); 556 if (ptr == MAP_FAILED) { 557 fprintf (stderr, "%s: Can't read %s: %s\n", 558 params.cmdname, datafile, strerror(errno)); 559 exit (EXIT_FAILURE); 560 } 561 562 if (params.xflag) { 563 unsigned char *p = NULL; 564 /* 565 * XIP: do not append the image_header_t at the 566 * beginning of the file, but consume the space 567 * reserved for it. 568 */ 569 570 if ((unsigned)sbuf.st_size < tparams->header_size) { 571 fprintf (stderr, 572 "%s: Bad size: \"%s\" is too small for XIP\n", 573 params.cmdname, datafile); 574 exit (EXIT_FAILURE); 575 } 576 577 for (p = ptr; p < ptr + tparams->header_size; p++) { 578 if ( *p != 0xff ) { 579 fprintf (stderr, 580 "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 581 params.cmdname, datafile); 582 exit (EXIT_FAILURE); 583 } 584 } 585 586 offset = tparams->header_size; 587 } 588 589 size = sbuf.st_size - offset; 590 if (write(ifd, ptr + offset, size) != size) { 591 fprintf (stderr, "%s: Write error on %s: %s\n", 592 params.cmdname, params.imagefile, strerror(errno)); 593 exit (EXIT_FAILURE); 594 } 595 596 tail = size % 4; 597 if ((pad == 1) && (tail != 0)) { 598 599 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 600 fprintf (stderr, "%s: Write error on %s: %s\n", 601 params.cmdname, params.imagefile, 602 strerror(errno)); 603 exit (EXIT_FAILURE); 604 } 605 } else if (pad > 1) { 606 while (pad > 0) { 607 int todo = sizeof(zeros); 608 609 if (todo > pad) 610 todo = pad; 611 if (write(ifd, (char *)&zeros, todo) != todo) { 612 fprintf(stderr, "%s: Write error on %s: %s\n", 613 params.cmdname, params.imagefile, 614 strerror(errno)); 615 exit(EXIT_FAILURE); 616 } 617 pad -= todo; 618 } 619 } 620 621 (void) munmap((void *)ptr, sbuf.st_size); 622 (void) close (dfd); 623 } 624