Changes for kernel and Busybox
[tomato.git] / release / src / btools / fpkg.c
blobacbd7c165b8623a30c2ab4b2cde4cd57e6b905b5
1 /*
3 fpkg - Package a firmware
4 Copyright (C) 2007 Jonathan Zarate
5 Portions Copyright (C) 2010 Fedor Kozhevnikov
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <getopt.h>
29 #include <time.h>
30 #include <stdint.h>
31 #include <sys/stat.h>
32 #include <arpa/inet.h>
34 #define ROUNDUP(n, a) ((n + (a - 1)) & ~(a - 1))
36 #define TRX_MAGIC 0x30524448
37 #define TRX_MAX_OFFSET 4
38 #define TRX_MAX_LEN ((32 * 1024 * 1024) - ((256 + 128) * 1024)) // 32MB - (256K cfe + 128K cfg)
40 typedef struct {
41 uint32_t magic;
42 uint32_t length;
43 uint32_t crc32;
44 uint32_t flag_version;
45 uint32_t offsets[TRX_MAX_OFFSET];
46 } trx_t;
48 char names[TRX_MAX_OFFSET][80];
50 char trx_version = 1;
51 int trx_max_offset = 3;
53 uint32_t trx_magic = TRX_MAGIC;
55 typedef struct {
56 uint32_t crc32;
57 uint32_t magic;
58 } moto_t;
60 typedef struct {
61 uint8_t magic[4];
62 uint8_t extra1[4];
63 uint8_t date[3];
64 uint8_t version[3];
65 uint8_t u2nd[4];
66 uint8_t hardware;
67 uint8_t serial;
68 uint16_t flags;
69 uint8_t extra2[10];
70 } cytan_t;
72 uint32_t *crc_table = NULL;
73 trx_t *trx = NULL;
74 int trx_count = 0;
75 int trx_final = 0;
76 int trx_padding;
77 time_t max_time = 0;
79 inline size_t trx_header_size(void)
81 return sizeof(*trx) - sizeof(trx->offsets) + (trx_max_offset * sizeof(trx->offsets[0]));
84 int crc_init(void)
86 uint32_t c;
87 int i, j;
89 if (crc_table == NULL) {
90 if ((crc_table = malloc(sizeof(uint32_t) * 256)) == NULL) return 0;
91 for (i = 255; i >= 0; --i) {
92 c = i;
93 for (j = 8; j > 0; --j) {
94 if (c & 1) c = (c >> 1) ^ 0xEDB88320L;
95 else c >>= 1;
97 crc_table[i] = c;
100 return 1;
103 void crc_done(void)
105 free(crc_table);
106 crc_table = NULL;
109 uint32_t crc_calc(uint32_t crc, uint8_t *buf, int len)
111 while (len-- > 0) {
112 crc = crc_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
113 ++buf;
115 return crc;
118 void help(void)
120 fprintf(stderr,
121 "fpkg - Package a firmware\n"
122 "Copyright (C) 2007 Jonathan Zarate\n"
123 "\n"
124 "Usage: [-v <trx version>] -i <input> [-a <align>] [-i <input>] [-a <align>] {output}\n"
125 "Output:\n"
126 " TRX: -t <output file>\n"
127 " Linksys/Cisco: -l <id>,<output file>\n"
128 " W54G WRT54G / WRT54GL\n"
129 " W54U WRTSL54GS\n"
130 " W54S WRTS54GS\n"
131 " W54s WRT54GS v4\n"
132 " N160 WRT160N v3\n"
133 " EWCB WRT300N v1\n"
134 " 310N WRT310N v1/v2\n"
135 " 320N WRT320N\n"
136 " 610N WRT610N v2\n"
137 " 32XN E2000\n"
138 " 61XN E3000\n"
139 " 4200 E4200\n"
140 " Motorola: -m <id>,<output file>\n"
141 " 0x10577000 WE800\n"
142 " 0x10577040 WA840\n"
143 " 0x10577050 WR850\n"
144 " Belkin: -b <id>,<output file>\n"
145 " 0x20100322 F7D3301 (Share Max)\n"
146 " 0x20090928 F7D3302 (Share)\n"
147 " 0x20091006 F7D4302 (Play)\n"
148 " 0x00017116 F5D8235 v3\n"
149 " 0x12345678 QA (QA firmware)\n"
150 " Asus: -r <id>,<v1>,<v2>,<v3>,<v4>,<output file>\n"
151 "\n"
153 exit(1);
156 void load_image(const char *fname)
158 struct stat st;
159 FILE *f;
160 long rsize;
161 char *p;
163 if (trx_final) {
164 fprintf(stderr, "Cannot load another image if an output has already been written.\n");
165 exit(1);
167 if (trx_count >= trx_max_offset) {
168 fprintf(stderr, "Too many input files.\n");
169 exit(1);
172 if (stat(fname, &st) != 0) {
173 perror(fname);
174 exit(1);
176 if (st.st_ctime > max_time) max_time = st.st_ctime;
178 rsize = ROUNDUP(st.st_size, 4);
179 if ((trx->length + rsize) > TRX_MAX_LEN) {
180 fprintf(stderr, "Total size %lu (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
181 (trx->length + rsize), (trx->length + rsize) / 1024.0,
182 (long unsigned int) TRX_MAX_LEN, TRX_MAX_LEN / 1024.0);
183 exit(1);
186 p = (char *)trx + trx->length;
187 if ((f = fopen(fname, "r")) == NULL) {
188 perror(fname);
189 exit(1);
191 if (fread((char *)trx + trx->length, st.st_size, 1, f) != 1) {
192 perror(fname);
193 exit(1);
195 fclose(f);
196 strncpy(names[trx_count], fname, sizeof(names[0]) -1);
197 trx->offsets[trx_count++] = trx->length;
198 trx->length += rsize;
201 void align_trx(const char *align)
203 uint32_t len;
204 size_t n;
205 char *e;
207 errno = 0;
208 n = strtoul(align, &e, 0);
209 if (errno || (e == align) || *e) {
210 fprintf(stderr, "Illegal numeric string\n");
211 help();
214 if (trx_final) {
215 fprintf(stderr, "Cannot align if an output has already been written.\n");
216 exit(1);
219 len = ROUNDUP(trx->length, n);
220 if (len > TRX_MAX_LEN) {
221 fprintf(stderr, "Total size %u (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
222 len, len / 1024.0, (long unsigned int) TRX_MAX_LEN, TRX_MAX_LEN / 1024.0);
223 exit(1);
225 trx->length = len;
228 void set_trx_version(const char *ver)
230 int n;
231 char *e;
233 errno = 0;
234 n = strtoul(ver, &e, 0);
235 if (errno || (e == ver) || *e) {
236 fprintf(stderr, "Illegal numeric string\n");
237 help();
240 if (trx_count > 0) {
241 fprintf(stderr, "Cannot change trx version after images have already been loaded.\n");
242 exit(1);
245 if (n < 1 || n > 2) {
246 fprintf(stderr, "TRX version %d is not supported.\n", n);
247 exit(1);
250 trx_version = (char)n;
251 switch (trx_version) {
252 case 2:
253 trx_max_offset = 4;
254 break;
255 default:
256 trx_max_offset = 3;
257 break;
259 trx->length = trx_header_size();
262 void finalize_trx(void)
264 uint32_t len;
266 if (trx_count == 0) {
267 fprintf(stderr, "No image was loaded.\n");
268 exit(1);
271 if (trx_final) {
272 trx->magic = trx_magic;
273 return;
275 trx_final = 1;
277 len = trx->length;
279 trx->length = ROUNDUP(len, 4096);
280 trx->magic = trx_magic;
281 trx->flag_version = trx_version << 16;
282 trx->crc32 = crc_calc(0xFFFFFFFF, (void *)&trx->flag_version,
283 trx->length - (sizeof(*trx) - (sizeof(trx->flag_version) + sizeof(trx->offsets))));
285 trx_padding = trx->length - len;
288 void create_trx(const char *fname)
290 FILE *f;
292 finalize_trx();
294 printf("Creating TRX: %s\n", fname);
296 if (((f = fopen(fname, "w")) == NULL) ||
297 (fwrite(trx, trx->length, 1, f) != 1)) {
298 perror(fname);
299 exit(1);
301 fclose(f);
304 void create_cytan(const char *fname, const char *pattern)
306 FILE *f;
307 cytan_t h;
308 char padding[1024 - sizeof(h)];
309 struct tm *tm;
311 if (strlen(pattern) != 4) {
312 fprintf(stderr, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern);
313 exit(1);
316 finalize_trx();
318 printf("Creating Linksys %s: %s\n", pattern, fname);
320 memset(&h, 0, sizeof(h));
321 memcpy(h.magic, pattern, 4);
322 memcpy(h.u2nd, "U2ND", 4);
323 h.version[0] = 4; // stock fw has version check
324 h.version[1] = 20;
325 h.version[2] = 6;
326 // h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h
327 h.flags = 0xFF;
328 tm = localtime(&max_time);
329 h.date[0] = tm->tm_year - 100;
330 h.date[1] = tm->tm_mon + 1;
331 h.date[2] = tm->tm_mday;
333 memset(padding, 0, sizeof(padding));
335 if (((f = fopen(fname, "w")) == NULL) ||
336 (fwrite(&h, sizeof(h), 1, f) != 1) ||
337 (fwrite(trx, trx->length, 1, f) != 1) ||
338 (fwrite(padding, sizeof(padding), 1, f) != 1)) {
339 perror(fname);
340 exit(1);
342 fclose(f);
345 void create_moto(const char *fname, const char *signature)
347 FILE *f;
348 moto_t h;
349 char *p;
351 h.magic = strtoul(signature, &p, 0);
352 if (*p != 0) help();
354 finalize_trx();
356 printf("Creating Motorola 0x%08X: %s\n", h.magic, fname);
358 h.magic = htonl(h.magic);
359 h.crc32 = crc_calc(0xFFFFFFFF, (void *)&h.magic, sizeof(h.magic));
360 h.crc32 = htonl(crc_calc(h.crc32, (void *)trx, trx->length));
362 if (((f = fopen(fname, "w")) == NULL) ||
363 (fwrite(&h, sizeof(h), 1, f) != 1) ||
364 (fwrite(trx, trx->length, 1, f) != 1)) {
365 perror(fname);
366 exit(1);
368 fclose(f);
371 #define MAX_STRING 12
372 #define MAX_VER 4
374 typedef struct {
375 uint8_t major;
376 uint8_t minor;
377 } version_t;
379 typedef struct {
380 version_t kernel;
381 version_t fs;
382 char productid[MAX_STRING];
383 version_t hw[MAX_VER*2];
384 char pad[32];
385 } TAIL;
387 /* usage:
388 * -r <productid>,<version>,<output file>
391 int create_asus(const char *optarg)
393 FILE *f;
394 char value[320];
395 char *next, *pid, *ver, *fname, *p;
396 TAIL asus_tail;
397 uint32_t len;
398 uint32_t v1, v2, v3, v4;
400 memset(&asus_tail, 0, sizeof(TAIL));
402 strncpy(value, optarg, sizeof(value));
403 next = value;
404 pid = strsep(&next, ",");
405 if(!pid) return 0;
407 strncpy(&asus_tail.productid[0], pid, MAX_STRING);
409 ver = strsep(&next, ",");
410 if(!ver) return 0;
412 sscanf(ver, "%d.%d.%d.%d", &v1, &v2, &v3, &v4);
413 asus_tail.kernel.major = (uint8_t)v1;
414 asus_tail.kernel.minor = (uint8_t)v2;
415 asus_tail.fs.major = (uint8_t)v3;
416 asus_tail.fs.minor = (uint8_t)v4;
418 fname = strsep(&next, ",");
419 if(!fname) return 0;
421 // append version information into the latest offset
422 trx->length += sizeof(TAIL);
423 len = trx->length;
424 trx->length = ROUNDUP(len, 4096);
426 p = (char *)trx+trx->length-sizeof(TAIL);
427 memcpy(p, &asus_tail, sizeof(TAIL));
429 finalize_trx();
431 printf("Creating Asus %s firmware to %s\n", asus_tail.productid, fname);
433 if (((f = fopen(fname, "w")) == NULL) ||
434 (fwrite(trx, trx->length, 1, f) != 1)) {
435 perror(fname);
436 exit(1);
438 fclose(f);
440 return 1;
443 int main(int argc, char **argv)
445 char s[256];
446 char *p, *e;
447 int o;
448 unsigned l, j;
450 printf("\n");
452 if ((!crc_init()) || ((trx = calloc(1, TRX_MAX_LEN)) == NULL)) {
453 fprintf(stderr, "Not enough memory\n");
454 exit(1);
456 trx->length = trx_header_size();
457 trx_magic = TRX_MAGIC;
459 while ((o = getopt(argc, argv, "v:i:a:t:l:m:b:r:")) != -1) {
460 switch (o) {
461 case 'v':
462 set_trx_version(optarg);
463 break;
464 case 'i':
465 load_image(optarg);
466 break;
467 case 'a':
468 align_trx(optarg);
469 break;
470 case 'b':
471 if (strlen(optarg) >= sizeof(s)) help();
472 strcpy(s, optarg);
473 if ((p = strchr(s, ',')) == NULL) help();
474 *p = 0;
475 ++p;
476 trx_magic = strtoul(s, &e, 0);
477 if (*e != 0) help();
478 create_trx(p);
479 trx_magic = TRX_MAGIC;
480 break;
481 case 't':
482 create_trx(optarg);
483 break;
484 case 'l':
485 case 'm':
486 if (strlen(optarg) >= sizeof(s)) help();
487 strcpy(s, optarg);
488 if ((p = strchr(s, ',')) == NULL) help();
489 *p = 0;
490 ++p;
491 if (o == 'l') create_cytan(p, s);
492 else create_moto(p, s);
493 break;
494 case 'r':
495 create_asus(optarg);
496 break;
497 default:
498 help();
499 return 1;
503 trx_magic = TRX_MAGIC;
504 if (trx_count == 0) {
505 help();
507 else {
508 finalize_trx();
509 l = trx->length - trx_padding - trx_header_size();
510 printf("\nTRX Image:\n");
511 printf(" Total Size .... : %u (%.1f KB) (%.1f MB)\n", trx->length, trx->length / 1024.0, trx->length / 1024.0 / 1024.0);
512 printf(" Images ...... : %u (0x%08x)\n", l , l);
513 printf(" Padding ..... : %d\n", trx_padding);
515 printf(" Avail. for jffs :\n");
517 /* Reserved: 2 EBs for pmon, 1 EB for nvram. */
518 l = trx->length;
519 if (l < (4 * 1024 * 1024) - (3 * 64 * 1024))
520 j = (4 * 1024 * 1024) - (3 * 64 * 1024) - l;
521 else
522 j = 0;
523 printf(" 4MB, 128K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
525 /* Reserved: 4 EBs for pmon, 1 EB for nvram. */
526 if (l < (4 * 1024 * 1024) - (5 * 64 * 1024))
527 j = (4 * 1024 * 1024) - (5 * 64 * 1024) - l;
528 else
529 j = 0;
530 printf(" 4MB, 256K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
532 if (l < (8 * 1024 * 1024) - (5 * 64 * 1024))
533 j = (8 * 1024 * 1024) - (5 * 64 * 1024) - l;
534 else
535 j = 0;
536 printf(" 8MB, 256K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
538 printf(" Note : Netgear routers have 6 EBs less available!\n");
540 printf(" CRC-32 ........ : %8X\n", trx->crc32);
541 l = (ROUNDUP(trx->length, (128 * 1024)) / (128 * 1024));
542 printf(" 128K Blocks ... : %u (0x%08X)\n", l, l);
543 l = (ROUNDUP(trx->length, (64 * 1024)) / (64 * 1024));
544 printf(" 64K Blocks ... : %u (0x%08X)\n", l, l);
545 printf(" Offsets:\n");
546 for (o = 0; o < trx_max_offset; ++o) {
547 printf(" %d: 0x%08X %s\n", o, trx->offsets[o], names[o]);
550 printf("\n");
551 return 0;