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