mkrtn56uimg.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. *
  3. * Copyright (C) 2014 OpenWrt.org
  4. * Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published
  8. * by the Free Software Foundation.
  9. *
  10. */
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <netinet/in.h>
  17. #include <sys/mman.h>
  18. #include <sys/stat.h>
  19. #include <time.h>
  20. #include <unistd.h>
  21. #include <zlib.h>
  22. #define IH_MAGIC 0x27051956
  23. #define IH_NMLEN 32
  24. #define IH_PRODLEN 23
  25. #define IH_TYPE_INVALID 0
  26. #define IH_TYPE_STANDALONE 1
  27. #define IH_TYPE_KERNEL 2
  28. #define IH_TYPE_RAMDISK 3
  29. #define IH_TYPE_MULTI 4
  30. #define IH_TYPE_FIRMWARE 5
  31. #define IH_TYPE_SCRIPT 6
  32. #define IH_TYPE_FILESYSTEM 7
  33. /*
  34. * Compression Types
  35. */
  36. #define IH_COMP_NONE 0
  37. #define IH_COMP_GZIP 1
  38. #define IH_COMP_BZIP2 2
  39. #define IH_COMP_LZMA 3
  40. typedef struct {
  41. uint8_t major;
  42. uint8_t minor;
  43. } version_t;
  44. typedef struct {
  45. version_t kernel;
  46. version_t fs;
  47. uint8_t productid[IH_PRODLEN];
  48. uint8_t sub_fs;
  49. uint32_t ih_ksz;
  50. } asus_t;
  51. typedef struct image_header {
  52. uint32_t ih_magic;
  53. uint32_t ih_hcrc;
  54. uint32_t ih_time;
  55. uint32_t ih_size;
  56. uint32_t ih_load;
  57. uint32_t ih_ep;
  58. uint32_t ih_dcrc;
  59. uint8_t ih_os;
  60. uint8_t ih_arch;
  61. uint8_t ih_type;
  62. uint8_t ih_comp;
  63. union {
  64. uint8_t ih_name[IH_NMLEN];
  65. asus_t asus;
  66. } tail;
  67. } image_header_t;
  68. typedef struct squashfs_sb {
  69. uint32_t s_magic;
  70. uint32_t pad0[9];
  71. uint64_t bytes_used;
  72. } squashfs_sb_t;
  73. typedef enum {
  74. NONE, FACTORY, SYSUPGRADE,
  75. } op_mode_t;
  76. void
  77. calc_crc(image_header_t *hdr, void *data, uint32_t len)
  78. {
  79. /*
  80. * Calculate payload checksum
  81. */
  82. hdr->ih_dcrc = htonl(crc32(0, (Bytef *)data, len));
  83. hdr->ih_size = htonl(len);
  84. /*
  85. * Calculate header checksum
  86. */
  87. hdr->ih_hcrc = 0;
  88. hdr->ih_hcrc = htonl(crc32(0, (Bytef *)hdr, sizeof(image_header_t)));
  89. }
  90. static void
  91. usage(const char *progname, int status)
  92. {
  93. FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
  94. int i;
  95. fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
  96. fprintf(stream, "\n"
  97. "Options:\n"
  98. " -f <file> generate a factory flash image <file>\n"
  99. " -s <file> generate a sysupgrade flash image <file>\n"
  100. " -h show this screen\n");
  101. exit(status);
  102. }
  103. int
  104. process_image(char *progname, char *filename, op_mode_t opmode)
  105. {
  106. int fd, len;
  107. void *data, *ptr;
  108. char namebuf[IH_NMLEN];
  109. struct stat sbuf;
  110. uint32_t checksum, offset_kernel, offset_sqfs, offset_end,
  111. offset_sec_header, offset_eb, offset_image_end;
  112. squashfs_sb_t *sqs;
  113. image_header_t *hdr;
  114. if ((fd = open(filename, O_RDWR, 0666)) < 0) {
  115. fprintf (stderr, "%s: Can't open %s: %s\n",
  116. progname, filename, strerror(errno));
  117. return (EXIT_FAILURE);
  118. }
  119. if (fstat(fd, &sbuf) < 0) {
  120. fprintf (stderr, "%s: Can't stat %s: %s\n",
  121. progname, filename, strerror(errno));
  122. return (EXIT_FAILURE);
  123. }
  124. if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
  125. fprintf (stderr,
  126. "%s: Bad size: \"%s\" is no valid image\n",
  127. progname, filename);
  128. return (EXIT_FAILURE);
  129. }
  130. ptr = (void *)mmap(0, sbuf.st_size,
  131. PROT_READ | PROT_WRITE,
  132. MAP_SHARED,
  133. fd, 0);
  134. if ((caddr_t)ptr == (caddr_t)-1) {
  135. fprintf (stderr, "%s: Can't read %s: %s\n",
  136. progname, filename, strerror(errno));
  137. return (EXIT_FAILURE);
  138. }
  139. hdr = ptr;
  140. if (ntohl(hdr->ih_magic) != IH_MAGIC) {
  141. fprintf (stderr,
  142. "%s: Bad Magic Number: \"%s\" is no valid image\n",
  143. progname, filename);
  144. return (EXIT_FAILURE);
  145. }
  146. if (opmode == FACTORY) {
  147. strncpy(namebuf, hdr->tail.ih_name, IH_NMLEN);
  148. hdr->tail.asus.kernel.major = 0;
  149. hdr->tail.asus.kernel.minor = 0;
  150. hdr->tail.asus.fs.major = 0;
  151. hdr->tail.asus.fs.minor = 0;
  152. strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN);
  153. }
  154. if (hdr->tail.asus.ih_ksz == 0)
  155. hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t));
  156. offset_kernel = sizeof(image_header_t);
  157. offset_sqfs = ntohl(hdr->tail.asus.ih_ksz);
  158. sqs = ptr + offset_sqfs;
  159. offset_sec_header = offset_sqfs + sqs->bytes_used;
  160. /*
  161. * Reserve space for the second header.
  162. */
  163. offset_end = offset_sec_header + sizeof(image_header_t);
  164. offset_eb = ((offset_end>>16)+1)<<16;
  165. if (opmode == FACTORY)
  166. offset_image_end = offset_eb + 4;
  167. else
  168. offset_image_end = sbuf.st_size;
  169. /*
  170. * Move the second header at the end of the image.
  171. */
  172. offset_end = offset_sec_header;
  173. offset_sec_header = offset_eb - sizeof(image_header_t);
  174. /*
  175. * Remove jffs2 markers between squashfs and eb boundary.
  176. */
  177. if (opmode == FACTORY)
  178. memset(ptr+offset_end, 0xff ,offset_eb - offset_end);
  179. /*
  180. * Grow the image if needed.
  181. */
  182. if (offset_image_end > sbuf.st_size) {
  183. (void) munmap((void *)ptr, sbuf.st_size);
  184. ftruncate(fd, offset_image_end);
  185. ptr = (void *)mmap(0, offset_image_end,
  186. PROT_READ | PROT_WRITE,
  187. MAP_SHARED,
  188. fd, 0);
  189. /*
  190. * jffs2 marker
  191. */
  192. if (opmode == FACTORY) {
  193. *(uint8_t *)(ptr+offset_image_end-4) = 0xde;
  194. *(uint8_t *)(ptr+offset_image_end-3) = 0xad;
  195. *(uint8_t *)(ptr+offset_image_end-2) = 0xc0;
  196. *(uint8_t *)(ptr+offset_image_end-1) = 0xde;
  197. }
  198. }
  199. /*
  200. * Calculate checksums for the second header to be used after flashing.
  201. */
  202. if (opmode == FACTORY) {
  203. hdr = ptr+offset_sec_header;
  204. memcpy(hdr, ptr, sizeof(image_header_t));
  205. strncpy(hdr->tail.ih_name, namebuf, IH_NMLEN);
  206. calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel);
  207. calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel);
  208. } else {
  209. calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel);
  210. }
  211. if (sbuf.st_size > offset_image_end)
  212. (void) munmap((void *)ptr, sbuf.st_size);
  213. else
  214. (void) munmap((void *)ptr, offset_image_end);
  215. ftruncate(fd, offset_image_end);
  216. (void) close (fd);
  217. return EXIT_SUCCESS;
  218. }
  219. int
  220. main(int argc, char **argv)
  221. {
  222. int opt;
  223. char *filename, *progname;
  224. op_mode_t opmode = NONE;
  225. progname = argv[0];
  226. while ((opt = getopt(argc, argv,":s:f:h?")) != -1) {
  227. switch (opt) {
  228. case 's':
  229. opmode = SYSUPGRADE;
  230. filename = optarg;
  231. break;
  232. case 'f':
  233. opmode = FACTORY;
  234. filename = optarg;
  235. break;
  236. case 'h':
  237. opmode = NONE;
  238. default:
  239. usage(progname, EXIT_FAILURE);
  240. opmode = NONE;
  241. }
  242. }
  243. if(filename == NULL)
  244. opmode = NONE;
  245. switch (opmode) {
  246. case NONE:
  247. usage(progname, EXIT_FAILURE);
  248. break;
  249. case FACTORY:
  250. case SYSUPGRADE:
  251. return process_image(progname, filename, opmode);
  252. break;
  253. }
  254. return EXIT_SUCCESS;
  255. }