mkchkimg.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. * Make CHK Image
  3. *
  4. * This utility creates Netgear .chk files.
  5. *
  6. * Copyright (C) 2008 Dave C. Reeve <Dave.Reeve@dreeve.org>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <stdarg.h>
  26. #include <errno.h>
  27. #include <arpa/inet.h>
  28. #include <unistd.h>
  29. #define BUF_LEN (2048)
  30. #define MAX_BOARD_ID_LEN (64)
  31. struct chk_header {
  32. uint32_t magic;
  33. uint32_t header_len;
  34. uint8_t reserved[8];
  35. uint32_t kernel_chksum;
  36. uint32_t rootfs_chksum;
  37. uint32_t kernel_len;
  38. uint32_t rootfs_len;
  39. uint32_t image_chksum;
  40. uint32_t header_chksum;
  41. /* char board_id[] - upto MAX_BOARD_ID_LEN */
  42. };
  43. static void __attribute__ ((format (printf, 2, 3)))
  44. fatal_error (int maybe_errno, const char * format, ...)
  45. {
  46. va_list ap;
  47. fprintf (stderr, "mkchkimg: ");
  48. va_start (ap, format);
  49. vfprintf (stderr, format, ap);
  50. va_end (ap);
  51. if (maybe_errno) {
  52. fprintf (stderr, ": %s\n", strerror (maybe_errno));
  53. } else {
  54. fprintf (stderr, "\n");
  55. }
  56. exit (EXIT_FAILURE);
  57. }
  58. static void __attribute__ ((format (printf, 1, 2)))
  59. message (const char * format, ...)
  60. {
  61. va_list ap;
  62. fprintf (stderr, "mkchkimg: ");
  63. va_start (ap, format);
  64. vfprintf (stderr, format, ap);
  65. va_end (ap);
  66. fprintf (stderr, "\n");
  67. }
  68. struct ngr_checksum {
  69. uint32_t c0;
  70. uint32_t c1;
  71. };
  72. static inline void
  73. netgear_checksum_init (struct ngr_checksum * c)
  74. {
  75. c->c0 = c->c1 = 0;
  76. }
  77. static inline void
  78. netgear_checksum_add (struct ngr_checksum * c, unsigned char * buf, size_t len)
  79. {
  80. size_t i;
  81. for (i=0; i<len; i++) {
  82. c->c0 += buf[i] & 0xff;
  83. c->c1 += c->c0;
  84. }
  85. }
  86. static inline unsigned long
  87. netgear_checksum_fini (struct ngr_checksum * c)
  88. {
  89. uint32_t b, checksum;
  90. b = (c->c0 & 65535) + ((c->c0 >> 16) & 65535);
  91. c->c0 = ((b >> 16) + b) & 65535;
  92. b = (c->c1 & 65535) + ((c->c1 >> 16) & 65535);
  93. c->c1 = ((b >> 16) + b) & 65535;
  94. checksum = ((c->c1 << 16) | c->c0);
  95. return checksum;
  96. }
  97. static void
  98. print_help (void)
  99. {
  100. fprintf (stderr, "Usage: mkchkimg -o output -k kernel [-f filesys] [-b board_id] [-r region]\n");
  101. }
  102. int
  103. main (int argc, char * argv[])
  104. {
  105. int opt;
  106. char * ptr;
  107. size_t len;
  108. size_t header_len;
  109. struct chk_header * hdr;
  110. struct ngr_checksum chk_part, chk_whole;
  111. char buf[BUF_LEN];
  112. char * output_file, * kern_file, * fs_file;
  113. FILE * out_fp, * kern_fp, * fs_fp;
  114. char * board_id;
  115. unsigned long region;
  116. /* Default values */
  117. board_id = "U12H072T00_NETGEAR";
  118. region = 1; /* 1=WW, 2=NA */
  119. output_file = NULL;
  120. kern_file = NULL;
  121. fs_file = NULL;
  122. fs_fp = NULL;
  123. while ((opt = getopt (argc, argv, ":b:r:k:f:o:h")) != -1) {
  124. switch (opt) {
  125. case 'b':
  126. /* Board Identity */
  127. if (strlen (optarg) > MAX_BOARD_ID_LEN) {
  128. fatal_error (0, "Board lenght exceeds %d",
  129. MAX_BOARD_ID_LEN);
  130. }
  131. board_id = optarg;
  132. break;
  133. case 'r':
  134. /* Region */
  135. errno = 0;
  136. region = strtoul (optarg, &ptr, 0);
  137. if (errno || ptr==optarg || *ptr!='\0') {
  138. fatal_error (0, "Cannot parse region %s", optarg);
  139. }
  140. if (region > 0xff) {
  141. fatal_error (0, "Region cannot exceed 0xff");
  142. }
  143. break;
  144. case 'k':
  145. /* Kernel */
  146. kern_file = optarg;
  147. break;
  148. case 'f':
  149. /* Filing System */
  150. fs_file = optarg;
  151. break;
  152. case 'o':
  153. /* Output file */
  154. output_file = optarg;
  155. break;
  156. case 'h':
  157. print_help ();
  158. return EXIT_SUCCESS;
  159. case ':':
  160. print_help ();
  161. fatal_error (0, "Option -%c missing argument", optopt);
  162. break;
  163. case '?':
  164. print_help ();
  165. fatal_error (0, "Unknown argument -%c", optopt);
  166. break;
  167. default:
  168. break;
  169. }
  170. }
  171. /* Check we have all the options expected */
  172. if (!kern_file) {
  173. print_help ();
  174. fatal_error (0, "Kernel file expected");
  175. }
  176. if (!output_file) {
  177. print_help ();
  178. fatal_error (0, "Output file required");
  179. }
  180. message ("Netgear CHK writer - v0.1");
  181. /* Open the input file */
  182. kern_fp = fopen (kern_file, "r");
  183. if (!kern_fp) {
  184. fatal_error (errno, "Cannot open %s", kern_file);
  185. }
  186. /* Open the fs file, if specified */
  187. if (fs_file) {
  188. fs_fp = fopen (fs_file, "r");
  189. if (!fs_fp) {
  190. fatal_error (errno, "Cannot open %s", fs_file);
  191. }
  192. }
  193. /* Open the output file */
  194. out_fp = fopen (output_file, "w+");
  195. if (!out_fp) {
  196. fatal_error (errno, "Cannot open %s", output_file);
  197. }
  198. /* Write zeros when the chk header will be */
  199. buf[0] = '\0';
  200. header_len = sizeof (struct chk_header) + strlen (board_id);
  201. if (fwrite (buf, 1, header_len, out_fp) != header_len) {
  202. fatal_error (errno, "Cannot write header");
  203. }
  204. /* Allocate storage for header, we fill in as we go */
  205. hdr = malloc (sizeof (struct chk_header));
  206. if (!hdr) {
  207. fatal_error (0, "malloc failed");
  208. }
  209. bzero (hdr, sizeof (struct chk_header));
  210. /* Fill in known values */
  211. hdr->magic = htonl (0x2a23245e);
  212. hdr->header_len = htonl(header_len);
  213. hdr->reserved[0] = (unsigned char)(region & 0xff);
  214. hdr->reserved[1] = 1; /* Major */
  215. hdr->reserved[2] = 1; /* Minor */
  216. hdr->reserved[3] = 99; /* Build */
  217. hdr->reserved[4] = 0; /* Unknown t1 ? was 1 */
  218. hdr->reserved[5] = 0; /* Unknonw t2 ? was 0 */
  219. hdr->reserved[6] = 0; /* Unknonw t3 ? was 1 */
  220. hdr->reserved[7] = 0; /* Unused ? */
  221. message (" Board Id: %s", board_id);
  222. message (" Region: %s", region == 1 ? "World Wide (WW)"
  223. : (region == 2 ? "North America (NA)" : "Unknown"));
  224. /* Copy the trx file, calculating the checksum as we go */
  225. netgear_checksum_init (&chk_part);
  226. netgear_checksum_init (&chk_whole);
  227. while (!feof (kern_fp)) {
  228. len = fread (buf, 1, BUF_LEN, kern_fp);
  229. if (len < 1) {
  230. break;
  231. }
  232. if (fwrite (buf, len, 1, out_fp) != 1) {
  233. fatal_error (errno, "Write error");
  234. }
  235. hdr->kernel_len += len;
  236. netgear_checksum_add (&chk_part, (unsigned char *)buf, len);
  237. netgear_checksum_add (&chk_whole, (unsigned char *)buf, len);
  238. }
  239. hdr->kernel_chksum = netgear_checksum_fini (&chk_part);
  240. message (" Kernel Len: %u", hdr->kernel_len);
  241. message ("Kernel Checksum: 0x%08x", hdr->kernel_chksum);
  242. hdr->kernel_len = htonl (hdr->kernel_len);
  243. hdr->kernel_chksum = htonl (hdr->kernel_chksum);
  244. /* Now copy the root fs, calculating the checksum as we go */
  245. if (fs_fp) {
  246. netgear_checksum_init (&chk_part);
  247. while (!feof (fs_fp)) {
  248. len = fread (buf, 1, BUF_LEN, fs_fp);
  249. if (len < 1) {
  250. break;
  251. }
  252. if (fwrite (buf, len, 1, out_fp) != 1) {
  253. fatal_error (errno, "Write error");
  254. }
  255. hdr->rootfs_len += len;
  256. netgear_checksum_add (&chk_part, (unsigned char *)buf, len);
  257. netgear_checksum_add (&chk_whole, (unsigned char *)buf, len);
  258. }
  259. hdr->rootfs_chksum = (netgear_checksum_fini (&chk_part));
  260. message (" Rootfs Len: %u", hdr->rootfs_len);
  261. message ("Rootfs Checksum: 0x%08x", hdr->rootfs_chksum);
  262. hdr->rootfs_len = htonl (hdr->rootfs_len);
  263. hdr->rootfs_chksum = htonl (hdr->rootfs_chksum);
  264. }
  265. /* Calcautate the image checksum */
  266. hdr->image_chksum = netgear_checksum_fini (&chk_whole);
  267. message (" Image Checksum: 0x%08x", hdr->image_chksum);
  268. hdr->image_chksum = htonl (hdr->image_chksum);
  269. /* Calculate the header checksum */
  270. netgear_checksum_init (&chk_part);
  271. netgear_checksum_add (&chk_part, (unsigned char *)hdr,
  272. sizeof (struct chk_header));
  273. netgear_checksum_add (&chk_part, (unsigned char *)board_id,
  274. strlen (board_id));
  275. hdr->header_chksum = htonl (netgear_checksum_fini (&chk_part));
  276. /* Finally rewind the output and write headers */
  277. rewind (out_fp);
  278. if (fwrite (hdr, sizeof (struct chk_header), 1, out_fp) != 1) {
  279. fatal_error (errno, "Cannot write header");
  280. }
  281. if (fwrite (board_id, strlen (board_id), 1, out_fp) != 1) {
  282. fatal_error (errno, "Cannot write board id");
  283. }
  284. /* Success */
  285. return EXIT_SUCCESS;
  286. }