mkimage.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  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. #include "mkimage.h"
  11. #include <image.h>
  12. #include <version.h>
  13. static void copy_file(int, const char *, int);
  14. static void usage(void);
  15. /* parameters initialized by core will be used by the image type code */
  16. struct image_tool_params params = {
  17. .os = IH_OS_LINUX,
  18. .arch = IH_ARCH_PPC,
  19. .type = IH_TYPE_KERNEL,
  20. .comp = IH_COMP_GZIP,
  21. .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
  22. .imagename = "",
  23. .imagename2 = "",
  24. };
  25. int
  26. main (int argc, char **argv)
  27. {
  28. int ifd = -1;
  29. struct stat sbuf;
  30. char *ptr;
  31. int retval = 0;
  32. struct image_type_params *tparams = NULL;
  33. int pad_len = 0;
  34. params.cmdname = *argv;
  35. params.addr = params.ep = 0;
  36. while (--argc > 0 && **++argv == '-') {
  37. while (*++*argv) {
  38. switch (**argv) {
  39. case 'l':
  40. params.lflag = 1;
  41. break;
  42. case 'A':
  43. if ((--argc <= 0) ||
  44. (params.arch =
  45. genimg_get_arch_id (*++argv)) < 0)
  46. usage ();
  47. goto NXTARG;
  48. case 'c':
  49. if (--argc <= 0)
  50. usage();
  51. params.comment = *++argv;
  52. goto NXTARG;
  53. case 'C':
  54. if ((--argc <= 0) ||
  55. (params.comp =
  56. genimg_get_comp_id (*++argv)) < 0)
  57. usage ();
  58. goto NXTARG;
  59. case 'D':
  60. if (--argc <= 0)
  61. usage ();
  62. params.dtc = *++argv;
  63. goto NXTARG;
  64. case 'O':
  65. if ((--argc <= 0) ||
  66. (params.os =
  67. genimg_get_os_id (*++argv)) < 0)
  68. usage ();
  69. goto NXTARG;
  70. case 'T':
  71. if ((--argc <= 0) ||
  72. (params.type =
  73. genimg_get_type_id (*++argv)) < 0)
  74. usage ();
  75. goto NXTARG;
  76. case 'a':
  77. if (--argc <= 0)
  78. usage ();
  79. params.addr = strtoul (*++argv, &ptr, 16);
  80. if (*ptr) {
  81. fprintf (stderr,
  82. "%s: invalid load address %s\n",
  83. params.cmdname, *argv);
  84. exit (EXIT_FAILURE);
  85. }
  86. goto NXTARG;
  87. case 'd':
  88. if (--argc <= 0)
  89. usage ();
  90. params.datafile = *++argv;
  91. params.dflag = 1;
  92. goto NXTARG;
  93. case 'e':
  94. if (--argc <= 0)
  95. usage ();
  96. params.ep = strtoul (*++argv, &ptr, 16);
  97. if (*ptr) {
  98. fprintf (stderr,
  99. "%s: invalid entry point %s\n",
  100. params.cmdname, *argv);
  101. exit (EXIT_FAILURE);
  102. }
  103. params.eflag = 1;
  104. goto NXTARG;
  105. case 'f':
  106. if (--argc <= 0)
  107. usage ();
  108. params.datafile = *++argv;
  109. /* no break */
  110. case 'F':
  111. /*
  112. * The flattened image tree (FIT) format
  113. * requires a flattened device tree image type
  114. */
  115. params.type = IH_TYPE_FLATDT;
  116. params.fflag = 1;
  117. goto NXTARG;
  118. case 'k':
  119. if (--argc <= 0)
  120. usage();
  121. params.keydir = *++argv;
  122. goto NXTARG;
  123. case 'K':
  124. if (--argc <= 0)
  125. usage();
  126. params.keydest = *++argv;
  127. goto NXTARG;
  128. case 'n':
  129. if (--argc <= 0)
  130. usage ();
  131. params.imagename = *++argv;
  132. goto NXTARG;
  133. case 'r':
  134. params.require_keys = 1;
  135. break;
  136. case 'R':
  137. if (--argc <= 0)
  138. usage();
  139. /*
  140. * This entry is for the second configuration
  141. * file, if only one is not enough.
  142. */
  143. params.imagename2 = *++argv;
  144. goto NXTARG;
  145. case 's':
  146. params.skipcpy = 1;
  147. break;
  148. case 'v':
  149. params.vflag++;
  150. break;
  151. case 'V':
  152. printf("mkimage version %s\n", PLAIN_VERSION);
  153. exit(EXIT_SUCCESS);
  154. case 'x':
  155. params.xflag++;
  156. break;
  157. default:
  158. usage ();
  159. }
  160. }
  161. NXTARG: ;
  162. }
  163. if (argc != 1)
  164. usage ();
  165. /* set tparams as per input type_id */
  166. tparams = imagetool_get_type(params.type);
  167. if (tparams == NULL) {
  168. fprintf (stderr, "%s: unsupported type %s\n",
  169. params.cmdname, genimg_get_type_name(params.type));
  170. exit (EXIT_FAILURE);
  171. }
  172. /*
  173. * check the passed arguments parameters meets the requirements
  174. * as per image type to be generated/listed
  175. */
  176. if (tparams->check_params)
  177. if (tparams->check_params (&params))
  178. usage ();
  179. if (!params.eflag) {
  180. params.ep = params.addr;
  181. /* If XIP, entry point must be after the U-Boot header */
  182. if (params.xflag)
  183. params.ep += tparams->header_size;
  184. }
  185. params.imagefile = *argv;
  186. if (params.fflag){
  187. if (tparams->fflag_handle)
  188. /*
  189. * in some cases, some additional processing needs
  190. * to be done if fflag is defined
  191. *
  192. * For ex. fit_handle_file for Fit file support
  193. */
  194. retval = tparams->fflag_handle(&params);
  195. if (retval != EXIT_SUCCESS)
  196. exit (retval);
  197. }
  198. if (params.lflag || params.fflag) {
  199. ifd = open (params.imagefile, O_RDONLY|O_BINARY);
  200. } else {
  201. ifd = open (params.imagefile,
  202. O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
  203. }
  204. if (ifd < 0) {
  205. fprintf (stderr, "%s: Can't open %s: %s\n",
  206. params.cmdname, params.imagefile,
  207. strerror(errno));
  208. exit (EXIT_FAILURE);
  209. }
  210. if (params.lflag || params.fflag) {
  211. /*
  212. * list header information of existing image
  213. */
  214. if (fstat(ifd, &sbuf) < 0) {
  215. fprintf (stderr, "%s: Can't stat %s: %s\n",
  216. params.cmdname, params.imagefile,
  217. strerror(errno));
  218. exit (EXIT_FAILURE);
  219. }
  220. if ((unsigned)sbuf.st_size < tparams->header_size) {
  221. fprintf (stderr,
  222. "%s: Bad size: \"%s\" is not valid image\n",
  223. params.cmdname, params.imagefile);
  224. exit (EXIT_FAILURE);
  225. }
  226. ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
  227. if (ptr == MAP_FAILED) {
  228. fprintf (stderr, "%s: Can't read %s: %s\n",
  229. params.cmdname, params.imagefile,
  230. strerror(errno));
  231. exit (EXIT_FAILURE);
  232. }
  233. /*
  234. * scan through mkimage registry for all supported image types
  235. * and verify the input image file header for match
  236. * Print the image information for matched image type
  237. * Returns the error code if not matched
  238. */
  239. retval = imagetool_verify_print_header(ptr, &sbuf,
  240. tparams, &params);
  241. (void) munmap((void *)ptr, sbuf.st_size);
  242. (void) close (ifd);
  243. exit (retval);
  244. }
  245. /*
  246. * In case there an header with a variable
  247. * length will be added, the corresponding
  248. * function is called. This is responsible to
  249. * allocate memory for the header itself.
  250. */
  251. if (tparams->vrec_header)
  252. pad_len = tparams->vrec_header(&params, tparams);
  253. else
  254. memset(tparams->hdr, 0, tparams->header_size);
  255. if (write(ifd, tparams->hdr, tparams->header_size)
  256. != tparams->header_size) {
  257. fprintf (stderr, "%s: Write error on %s: %s\n",
  258. params.cmdname, params.imagefile, strerror(errno));
  259. exit (EXIT_FAILURE);
  260. }
  261. if (!params.skipcpy) {
  262. if (params.type == IH_TYPE_MULTI ||
  263. params.type == IH_TYPE_SCRIPT) {
  264. char *file = params.datafile;
  265. uint32_t size;
  266. for (;;) {
  267. char *sep = NULL;
  268. if (file) {
  269. if ((sep = strchr(file, ':')) != NULL) {
  270. *sep = '\0';
  271. }
  272. if (stat (file, &sbuf) < 0) {
  273. fprintf (stderr, "%s: Can't stat %s: %s\n",
  274. params.cmdname, file, strerror(errno));
  275. exit (EXIT_FAILURE);
  276. }
  277. size = cpu_to_uimage (sbuf.st_size);
  278. } else {
  279. size = 0;
  280. }
  281. if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
  282. fprintf (stderr, "%s: Write error on %s: %s\n",
  283. params.cmdname, params.imagefile,
  284. strerror(errno));
  285. exit (EXIT_FAILURE);
  286. }
  287. if (!file) {
  288. break;
  289. }
  290. if (sep) {
  291. *sep = ':';
  292. file = sep + 1;
  293. } else {
  294. file = NULL;
  295. }
  296. }
  297. file = params.datafile;
  298. for (;;) {
  299. char *sep = strchr(file, ':');
  300. if (sep) {
  301. *sep = '\0';
  302. copy_file (ifd, file, 1);
  303. *sep++ = ':';
  304. file = sep;
  305. } else {
  306. copy_file (ifd, file, 0);
  307. break;
  308. }
  309. }
  310. } else if (params.type == IH_TYPE_PBLIMAGE) {
  311. /* PBL has special Image format, implements its' own */
  312. pbl_load_uboot(ifd, &params);
  313. } else {
  314. copy_file(ifd, params.datafile, pad_len);
  315. }
  316. }
  317. /* We're a bit of paranoid */
  318. #if defined(_POSIX_SYNCHRONIZED_IO) && \
  319. !defined(__sun__) && \
  320. !defined(__FreeBSD__) && \
  321. !defined(__OpenBSD__) && \
  322. !defined(__APPLE__)
  323. (void) fdatasync (ifd);
  324. #else
  325. (void) fsync (ifd);
  326. #endif
  327. if (fstat(ifd, &sbuf) < 0) {
  328. fprintf (stderr, "%s: Can't stat %s: %s\n",
  329. params.cmdname, params.imagefile, strerror(errno));
  330. exit (EXIT_FAILURE);
  331. }
  332. ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
  333. if (ptr == MAP_FAILED) {
  334. fprintf (stderr, "%s: Can't map %s: %s\n",
  335. params.cmdname, params.imagefile, strerror(errno));
  336. exit (EXIT_FAILURE);
  337. }
  338. /* Setup the image header as per input image type*/
  339. if (tparams->set_header)
  340. tparams->set_header (ptr, &sbuf, ifd, &params);
  341. else {
  342. fprintf (stderr, "%s: Can't set header for %s: %s\n",
  343. params.cmdname, tparams->name, strerror(errno));
  344. exit (EXIT_FAILURE);
  345. }
  346. /* Print the image information by processing image header */
  347. if (tparams->print_header)
  348. tparams->print_header (ptr);
  349. else {
  350. fprintf (stderr, "%s: Can't print header for %s: %s\n",
  351. params.cmdname, tparams->name, strerror(errno));
  352. exit (EXIT_FAILURE);
  353. }
  354. (void) munmap((void *)ptr, sbuf.st_size);
  355. /* We're a bit of paranoid */
  356. #if defined(_POSIX_SYNCHRONIZED_IO) && \
  357. !defined(__sun__) && \
  358. !defined(__FreeBSD__) && \
  359. !defined(__OpenBSD__) && \
  360. !defined(__APPLE__)
  361. (void) fdatasync (ifd);
  362. #else
  363. (void) fsync (ifd);
  364. #endif
  365. if (close(ifd)) {
  366. fprintf (stderr, "%s: Write error on %s: %s\n",
  367. params.cmdname, params.imagefile, strerror(errno));
  368. exit (EXIT_FAILURE);
  369. }
  370. exit (EXIT_SUCCESS);
  371. }
  372. static void
  373. copy_file (int ifd, const char *datafile, int pad)
  374. {
  375. int dfd;
  376. struct stat sbuf;
  377. unsigned char *ptr;
  378. int tail;
  379. int zero = 0;
  380. uint8_t zeros[4096];
  381. int offset = 0;
  382. int size;
  383. struct image_type_params *tparams = imagetool_get_type(params.type);
  384. if (pad >= sizeof(zeros)) {
  385. fprintf(stderr, "%s: Can't pad to %d\n",
  386. params.cmdname, pad);
  387. exit(EXIT_FAILURE);
  388. }
  389. memset(zeros, 0, sizeof(zeros));
  390. if (params.vflag) {
  391. fprintf (stderr, "Adding Image %s\n", datafile);
  392. }
  393. if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
  394. fprintf (stderr, "%s: Can't open %s: %s\n",
  395. params.cmdname, datafile, strerror(errno));
  396. exit (EXIT_FAILURE);
  397. }
  398. if (fstat(dfd, &sbuf) < 0) {
  399. fprintf (stderr, "%s: Can't stat %s: %s\n",
  400. params.cmdname, datafile, strerror(errno));
  401. exit (EXIT_FAILURE);
  402. }
  403. ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
  404. if (ptr == MAP_FAILED) {
  405. fprintf (stderr, "%s: Can't read %s: %s\n",
  406. params.cmdname, datafile, strerror(errno));
  407. exit (EXIT_FAILURE);
  408. }
  409. if (params.xflag) {
  410. unsigned char *p = NULL;
  411. /*
  412. * XIP: do not append the image_header_t at the
  413. * beginning of the file, but consume the space
  414. * reserved for it.
  415. */
  416. if ((unsigned)sbuf.st_size < tparams->header_size) {
  417. fprintf (stderr,
  418. "%s: Bad size: \"%s\" is too small for XIP\n",
  419. params.cmdname, datafile);
  420. exit (EXIT_FAILURE);
  421. }
  422. for (p = ptr; p < ptr + tparams->header_size; p++) {
  423. if ( *p != 0xff ) {
  424. fprintf (stderr,
  425. "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
  426. params.cmdname, datafile);
  427. exit (EXIT_FAILURE);
  428. }
  429. }
  430. offset = tparams->header_size;
  431. }
  432. size = sbuf.st_size - offset;
  433. if (write(ifd, ptr + offset, size) != size) {
  434. fprintf (stderr, "%s: Write error on %s: %s\n",
  435. params.cmdname, params.imagefile, strerror(errno));
  436. exit (EXIT_FAILURE);
  437. }
  438. tail = size % 4;
  439. if ((pad == 1) && (tail != 0)) {
  440. if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
  441. fprintf (stderr, "%s: Write error on %s: %s\n",
  442. params.cmdname, params.imagefile,
  443. strerror(errno));
  444. exit (EXIT_FAILURE);
  445. }
  446. } else if (pad > 1) {
  447. if (write(ifd, (char *)&zeros, pad) != pad) {
  448. fprintf(stderr, "%s: Write error on %s: %s\n",
  449. params.cmdname, params.imagefile,
  450. strerror(errno));
  451. exit(EXIT_FAILURE);
  452. }
  453. }
  454. (void) munmap((void *)ptr, sbuf.st_size);
  455. (void) close (dfd);
  456. }
  457. static void usage(void)
  458. {
  459. fprintf (stderr, "Usage: %s -l image\n"
  460. " -l ==> list image header information\n",
  461. params.cmdname);
  462. fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp "
  463. "-a addr -e ep -n name -d data_file[:data_file...] image\n"
  464. " -A ==> set architecture to 'arch'\n"
  465. " -O ==> set operating system to 'os'\n"
  466. " -T ==> set image type to 'type'\n"
  467. " -C ==> set compression type 'comp'\n"
  468. " -a ==> set load address to 'addr' (hex)\n"
  469. " -e ==> set entry point to 'ep' (hex)\n"
  470. " -n ==> set image name to 'name'\n"
  471. " -d ==> use image data from 'datafile'\n"
  472. " -x ==> set XIP (execute in place)\n",
  473. params.cmdname);
  474. fprintf(stderr, " %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
  475. params.cmdname);
  476. fprintf(stderr, " -D => set options for device tree compiler\n"
  477. " -f => input filename for FIT source\n");
  478. #ifdef CONFIG_FIT_SIGNATURE
  479. fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
  480. " -k => set directory containing private keys\n"
  481. " -K => write public keys to this .dtb file\n"
  482. " -c => add comment in signature node\n"
  483. " -F => re-sign existing FIT image\n"
  484. " -r => mark keys used as 'required' in dtb\n");
  485. #else
  486. fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
  487. #endif
  488. fprintf (stderr, " %s -V ==> print version information and exit\n",
  489. params.cmdname);
  490. exit (EXIT_FAILURE);
  491. }