mkzcfw.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License version 2 as published
  6. * by the Free Software Foundation.
  7. *
  8. */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <stdint.h>
  12. #include <string.h>
  13. #include <unistd.h> /* for unlink() */
  14. #include <libgen.h>
  15. #include <getopt.h> /* for getopt() */
  16. #include <stdarg.h>
  17. #include <errno.h>
  18. #include <sys/stat.h>
  19. #include "cyg_crc.h"
  20. #if (__BYTE_ORDER == __BIG_ENDIAN)
  21. # define HOST_TO_BE32(x) (x)
  22. # define BE32_TO_HOST(x) (x)
  23. # define HOST_TO_LE32(x) bswap_32(x)
  24. # define LE32_TO_HOST(x) bswap_32(x)
  25. #else
  26. # define HOST_TO_BE32(x) bswap_32(x)
  27. # define BE32_TO_HOST(x) bswap_32(x)
  28. # define HOST_TO_LE32(x) (x)
  29. # define LE32_TO_HOST(x) (x)
  30. #endif
  31. #define MAGIC_FIRMWARE 0x6d726966 /* 'firm' */
  32. #define MAGIC_KERNEL 0x676d694b /* 'Kimg' */
  33. #define MAGIC_ROOTFS 0x676d6952 /* 'Rimg' */
  34. struct file_info {
  35. char *file_name; /* name of the file */
  36. uint32_t file_size; /* length of the file */
  37. };
  38. struct fw_header {
  39. uint32_t magic;
  40. uint32_t length;
  41. uint32_t unk1;
  42. uint32_t unk2;
  43. } __attribute__ ((packed));
  44. struct fw_tail {
  45. uint32_t hw_id;
  46. uint32_t crc;
  47. } __attribute__ ((packed));
  48. struct board_info {
  49. char *id;
  50. uint32_t hw_id;
  51. uint32_t kernel_len;
  52. uint32_t rootfs_len;
  53. };
  54. /*
  55. * Globals
  56. */
  57. static char *ofname;
  58. static char *progname;
  59. static char *board_id;
  60. static struct board_info *board;
  61. static struct file_info kernel_info;
  62. static struct file_info rootfs_info;
  63. static struct board_info boards[] = {
  64. {
  65. .id = "ZCN-1523H-2-8",
  66. .hw_id = 0x66661523,
  67. .kernel_len = 0x170000,
  68. .rootfs_len = 0x610000,
  69. }, {
  70. .id = "ZCN-1523H-5-16",
  71. .hw_id = 0x6615235A,
  72. .kernel_len = 0x170000,
  73. .rootfs_len = 0x610000,
  74. }, {
  75. /* terminating entry */
  76. }
  77. };
  78. /*
  79. * Message macros
  80. */
  81. #define ERR(fmt, ...) do { \
  82. fflush(0); \
  83. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  84. progname, ## __VA_ARGS__ ); \
  85. } while (0)
  86. #define ERRS(fmt, ...) do { \
  87. int save = errno; \
  88. fflush(0); \
  89. fprintf(stderr, "[%s] *** error: " fmt "\n", \
  90. progname, ## __VA_ARGS__, strerror(save)); \
  91. } while (0)
  92. #define DBG(fmt, ...) do { \
  93. fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
  94. } while (0)
  95. static struct board_info *find_board(char *id)
  96. {
  97. struct board_info *ret;
  98. struct board_info *board;
  99. ret = NULL;
  100. for (board = boards; board->id != NULL; board++){
  101. if (strcasecmp(id, board->id) == 0) {
  102. ret = board;
  103. break;
  104. }
  105. };
  106. return ret;
  107. }
  108. static void usage(int status)
  109. {
  110. FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
  111. struct board_info *board;
  112. fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
  113. fprintf(stream,
  114. "\n"
  115. "Options:\n"
  116. " -B <board> create image for the board specified with <board>\n"
  117. " -k <file> read kernel image from the file <file>\n"
  118. " -r <file> read rootfs image from the file <file>\n"
  119. " -o <file> write output to the file <file>\n"
  120. " -h show this screen\n"
  121. );
  122. exit(status);
  123. }
  124. static int get_file_stat(struct file_info *fdata)
  125. {
  126. struct stat st;
  127. int res;
  128. if (fdata->file_name == NULL)
  129. return 0;
  130. res = stat(fdata->file_name, &st);
  131. if (res){
  132. ERRS("stat failed on %s", fdata->file_name);
  133. return res;
  134. }
  135. fdata->file_size = st.st_size;
  136. return 0;
  137. }
  138. static int read_to_buf(struct file_info *fdata, char *buf)
  139. {
  140. FILE *f;
  141. int ret = EXIT_FAILURE;
  142. f = fopen(fdata->file_name, "r");
  143. if (f == NULL) {
  144. ERRS("could not open \"%s\" for reading", fdata->file_name);
  145. goto out;
  146. }
  147. errno = 0;
  148. fread(buf, fdata->file_size, 1, f);
  149. if (errno != 0) {
  150. ERRS("unable to read from file \"%s\"", fdata->file_name);
  151. goto out_close;
  152. }
  153. ret = EXIT_SUCCESS;
  154. out_close:
  155. fclose(f);
  156. out:
  157. return ret;
  158. }
  159. static int check_options(void)
  160. {
  161. int ret;
  162. if (board_id == NULL) {
  163. ERR("no board specified");
  164. return -1;
  165. }
  166. board = find_board(board_id);
  167. if (board == NULL) {
  168. ERR("unknown/unsupported board id \"%s\"", board_id);
  169. return -1;
  170. }
  171. if (kernel_info.file_name == NULL) {
  172. ERR("no kernel image specified");
  173. return -1;
  174. }
  175. ret = get_file_stat(&kernel_info);
  176. if (ret)
  177. return ret;
  178. if (kernel_info.file_size > board->kernel_len) {
  179. ERR("kernel image is too big");
  180. return -1;
  181. }
  182. if (rootfs_info.file_name == NULL) {
  183. ERR("no rootfs image specified");
  184. return -1;
  185. }
  186. ret = get_file_stat(&rootfs_info);
  187. if (ret)
  188. return ret;
  189. if (rootfs_info.file_size > board->rootfs_len) {
  190. ERR("rootfs image is too big");
  191. return -1;
  192. }
  193. if (ofname == NULL) {
  194. ERR("no output file specified");
  195. return -1;
  196. }
  197. return 0;
  198. }
  199. static int write_fw(char *data, int len)
  200. {
  201. FILE *f;
  202. int ret = EXIT_FAILURE;
  203. f = fopen(ofname, "w");
  204. if (f == NULL) {
  205. ERRS("could not open \"%s\" for writing", ofname);
  206. goto out;
  207. }
  208. errno = 0;
  209. fwrite(data, len, 1, f);
  210. if (errno) {
  211. ERRS("unable to write output file");
  212. goto out_flush;
  213. }
  214. DBG("firmware file \"%s\" completed", ofname);
  215. ret = EXIT_SUCCESS;
  216. out_flush:
  217. fflush(f);
  218. fclose(f);
  219. if (ret != EXIT_SUCCESS) {
  220. unlink(ofname);
  221. }
  222. out:
  223. return ret;
  224. }
  225. static int build_fw(void)
  226. {
  227. int buflen;
  228. char *buf;
  229. char *p;
  230. int ret = EXIT_FAILURE;
  231. int writelen = 0;
  232. uint32_t crc;
  233. struct fw_header *hdr;
  234. struct fw_tail *tail;
  235. buflen = 3 * sizeof(struct fw_header) +
  236. kernel_info.file_size + rootfs_info.file_size +
  237. 3 * sizeof(struct fw_tail);
  238. buf = malloc(buflen);
  239. if (!buf) {
  240. ERR("no memory for buffer\n");
  241. goto out;
  242. }
  243. p = buf;
  244. memset(p, 0, buflen);
  245. /* fill firmware header */
  246. hdr = (struct fw_header *) p;
  247. hdr->magic = HOST_TO_LE32(MAGIC_FIRMWARE);
  248. hdr->length = HOST_TO_LE32(buflen - sizeof(struct fw_header));
  249. p += sizeof(struct fw_header);
  250. /* fill kernel block header */
  251. hdr = (struct fw_header *) p;
  252. hdr->magic = HOST_TO_LE32(MAGIC_KERNEL);
  253. hdr->length = HOST_TO_LE32(kernel_info.file_size +
  254. sizeof(struct fw_tail));
  255. p += sizeof(struct fw_header);
  256. /* read kernel data */
  257. ret = read_to_buf(&kernel_info, p);
  258. if (ret)
  259. goto out_free_buf;
  260. /* fill firmware tail */
  261. tail = (struct fw_tail *) (p + kernel_info.file_size);
  262. tail->hw_id = HOST_TO_BE32(board->hw_id);
  263. tail->crc = HOST_TO_BE32(cyg_crc32(p, kernel_info.file_size +
  264. sizeof(struct fw_tail) - 4));
  265. p += kernel_info.file_size + sizeof(struct fw_tail);
  266. /* fill rootfs block header */
  267. hdr = (struct fw_header *) p;
  268. hdr->magic = HOST_TO_LE32(MAGIC_ROOTFS);
  269. hdr->length = HOST_TO_LE32(rootfs_info.file_size +
  270. sizeof(struct fw_tail));
  271. p += sizeof(struct fw_header);
  272. /* read rootfs data */
  273. ret = read_to_buf(&rootfs_info, p);
  274. if (ret)
  275. goto out_free_buf;
  276. /* fill firmware tail */
  277. tail = (struct fw_tail *) (p + rootfs_info.file_size);
  278. tail->hw_id = HOST_TO_BE32(board->hw_id);
  279. tail->crc = HOST_TO_BE32(cyg_crc32(p, rootfs_info.file_size +
  280. sizeof(struct fw_tail) - 4));
  281. p += rootfs_info.file_size + sizeof(struct fw_tail);
  282. /* fill firmware tail */
  283. tail = (struct fw_tail *) p;
  284. tail->hw_id = HOST_TO_BE32(board->hw_id);
  285. tail->crc = HOST_TO_BE32(cyg_crc32(buf + sizeof(struct fw_header),
  286. buflen - sizeof(struct fw_header) - 4));
  287. ret = write_fw(buf, buflen);
  288. if (ret)
  289. goto out_free_buf;
  290. ret = EXIT_SUCCESS;
  291. out_free_buf:
  292. free(buf);
  293. out:
  294. return ret;
  295. }
  296. int main(int argc, char *argv[])
  297. {
  298. int ret = EXIT_FAILURE;
  299. int err;
  300. FILE *outfile;
  301. progname = basename(argv[0]);
  302. while ( 1 ) {
  303. int c;
  304. c = getopt(argc, argv, "B:k:r:o:h");
  305. if (c == -1)
  306. break;
  307. switch (c) {
  308. case 'B':
  309. board_id = optarg;
  310. break;
  311. case 'k':
  312. kernel_info.file_name = optarg;
  313. break;
  314. case 'r':
  315. rootfs_info.file_name = optarg;
  316. break;
  317. case 'o':
  318. ofname = optarg;
  319. break;
  320. case 'h':
  321. usage(EXIT_SUCCESS);
  322. break;
  323. default:
  324. usage(EXIT_FAILURE);
  325. break;
  326. }
  327. }
  328. ret = check_options();
  329. if (ret)
  330. goto out;
  331. ret = build_fw();
  332. out:
  333. return ret;
  334. }