RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / btools / fpkg.c
blob838a9a176931cadc5bf3932ef2aaabf4df2bfeeb
1 /*
3 fpkg - Package a firmware
4 Copyright (C) 2007 Jonathan Zarate
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <getopt.h>
28 #include <time.h>
29 #include <stdint.h>
30 #include <sys/stat.h>
31 #include <arpa/inet.h>
33 #define ROUNDUP(n, a) ((n + (a - 1)) & ~(a - 1))
35 #define TRX_MAGIC 0x30524448
36 #define TRX_MAX_OFFSET 4
37 #define TRX_MAX_LEN ((32 * 1024 * 1024) - ((256 + 128) * 1024)) // 32MB - (256K cfe + 128K cfg)
39 typedef struct {
40 uint32_t magic;
41 uint32_t length;
42 uint32_t crc32;
43 uint32_t flag_version;
44 uint32_t offsets[TRX_MAX_OFFSET];
45 } trx_t;
47 char names[TRX_MAX_OFFSET][80];
49 char trx_version = 1;
50 int trx_max_offset = 3;
53 typedef struct {
54 uint32_t crc32;
55 uint32_t magic;
56 } moto_t;
58 typedef struct {
59 uint8_t magic[4];
60 uint8_t extra1[4];
61 uint8_t date[3];
62 uint8_t version[3];
63 uint8_t u2nd[4];
64 uint8_t hardware;
65 uint8_t serial;
66 uint16_t flags;
67 uint8_t extra2[10];
68 } cytan_t;
70 uint32_t *crc_table = NULL;
71 trx_t *trx = NULL;
72 int trx_count = 0;
73 int trx_final = 0;
74 int trx_padding;
75 time_t max_time = 0;
77 inline size_t trx_header_size(void)
79 return sizeof(*trx) - sizeof(trx->offsets) + (trx_max_offset * sizeof(trx->offsets[0]));
82 int crc_init(void)
84 uint32_t c;
85 int i, j;
87 if (crc_table == NULL) {
88 if ((crc_table = malloc(sizeof(uint32_t) * 256)) == NULL) return 0;
89 for (i = 255; i >= 0; --i) {
90 c = i;
91 for (j = 8; j > 0; --j) {
92 if (c & 1) c = (c >> 1) ^ 0xEDB88320L;
93 else c >>= 1;
95 crc_table[i] = c;
98 return 1;
101 void crc_done(void)
103 free(crc_table);
104 crc_table = NULL;
107 uint32_t crc_calc(uint32_t crc, uint8_t *buf, int len)
109 while (len-- > 0) {
110 crc = crc_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
111 ++buf;
113 return crc;
116 void help(void)
118 fprintf(stderr,
119 "fpkg - Package a firmware\n"
120 "Copyright (C) 2007 Jonathan Zarate\n"
121 "\n"
122 "Usage: [-v <trx version>] -i <input> [-a <align>] [-i <input>] [-a <align>] {output}\n"
123 "Output:\n"
124 " TRX: -t <output file>\n"
125 " Linksys/Cisco: -l <id>,<output file>\n"
126 " W54G WRT54G / WRT54GL\n"
127 " W54U WRTSL54GS\n"
128 " W54S WRTS54GS\n"
129 " W54s WRT54GS v4\n"
130 " N160 WRT160N v3\n"
131 " EWCB WRT300N v1\n"
132 " 310N WRT310N v1/v2\n"
133 " 320N WRT320N\n"
134 " 610N WRT610N v2\n"
135 " 32XN E2000\n"
136 " 61XN E3000\n"
137 " Motorola: -m <id>,<output file>\n"
138 " 0x10577000 WE800\n"
139 " 0x10577040 WA840\n"
140 " 0x10577050 WR850\n"
141 " ASUS: -r <id>,<v1>,<v2>,<v3>,<v4>,<output file>\n"
142 "\n"
144 exit(1);
147 void load_image(const char *fname)
149 struct stat st;
150 FILE *f;
151 long rsize;
152 char *p;
154 if (trx_final) {
155 fprintf(stderr, "Cannot load another image if an output has already been written.\n");
156 exit(1);
158 if (trx_count >= trx_max_offset) {
159 fprintf(stderr, "Too many input files.\n");
160 exit(1);
163 if (stat(fname, &st) != 0) {
164 perror(fname);
165 exit(1);
167 if (st.st_ctime > max_time) max_time = st.st_ctime;
169 rsize = ROUNDUP(st.st_size, 4);
170 if ((trx->length + rsize) > TRX_MAX_LEN) {
171 fprintf(stderr, "Total size %lu (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
172 (trx->length + rsize), (trx->length + rsize) / 1024.0,
173 (long unsigned int) TRX_MAX_LEN, TRX_MAX_LEN / 1024.0);
174 exit(1);
177 p = (char *)trx + trx->length;
178 if ((f = fopen(fname, "r")) == NULL) {
179 perror(fname);
180 exit(1);
182 if (fread((char *)trx + trx->length, st.st_size, 1, f) != 1) {
183 perror(fname);
184 exit(1);
186 fclose(f);
187 strncpy(names[trx_count], fname, sizeof(names[0]) -1);
188 trx->offsets[trx_count++] = trx->length;
189 trx->length += rsize;
192 void align_trx(const char *align)
194 uint32_t len;
195 size_t n;
196 char *e;
198 errno = 0;
199 n = strtoul(align, &e, 0);
200 if (errno || (e == align) || *e) {
201 fprintf(stderr, "Illegal numeric string\n");
202 help();
205 if (trx_final) {
206 fprintf(stderr, "Cannot align if an output has already been written.\n");
207 exit(1);
210 len = ROUNDUP(trx->length, n);
211 if (len > TRX_MAX_LEN) {
212 fprintf(stderr, "Total size %u (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
213 len, len / 1024.0, (long unsigned int) TRX_MAX_LEN, TRX_MAX_LEN / 1024.0);
214 exit(1);
216 trx->length = len;
219 void set_trx_version(const char *ver)
221 int n;
222 char *e;
224 errno = 0;
225 n = strtoul(ver, &e, 0);
226 if (errno || (e == ver) || *e) {
227 fprintf(stderr, "Illegal numeric string\n");
228 help();
231 if (trx_count > 0) {
232 fprintf(stderr, "Cannot change trx version after images have already been loaded.\n");
233 exit(1);
236 if (n < 1 || n > 2) {
237 fprintf(stderr, "TRX version %d is not supported.\n", n);
238 exit(1);
241 trx_version = (char)n;
242 switch (trx_version) {
243 case 2:
244 trx_max_offset = 4;
245 break;
246 default:
247 trx_max_offset = 3;
248 break;
250 trx->length = trx_header_size();
253 void finalize_trx(void)
255 uint32_t len;
257 if (trx_count == 0) {
258 fprintf(stderr, "No image was loaded.\n");
259 exit(1);
262 if (trx_final) return;
263 trx_final = 1;
265 len = trx->length;
267 trx->length = ROUNDUP(len, 4096);
268 trx->magic = TRX_MAGIC;
269 trx->flag_version = trx_version << 16;
270 trx->crc32 = crc_calc(0xFFFFFFFF, (void *)&trx->flag_version,
271 trx->length - (sizeof(*trx) - (sizeof(trx->flag_version) + sizeof(trx->offsets))));
273 trx_padding = trx->length - len;
276 void create_trx(const char *fname)
278 FILE *f;
280 finalize_trx();
282 printf("Creating TRX: %s\n", fname);
284 if (((f = fopen(fname, "w")) == NULL) ||
285 (fwrite(trx, trx->length, 1, f) != 1)) {
286 perror(fname);
287 exit(1);
289 fclose(f);
292 void create_cytan(const char *fname, const char *pattern)
294 FILE *f;
295 cytan_t h;
296 char padding[1024 - sizeof(h)];
297 struct tm *tm;
299 if (strlen(pattern) != 4) {
300 fprintf(stderr, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern);
301 exit(1);
304 finalize_trx();
306 printf("Creating Linksys %s: %s\n", pattern, fname);
308 memset(&h, 0, sizeof(h));
309 memcpy(h.magic, pattern, 4);
310 memcpy(h.u2nd, "U2ND", 4);
311 h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h
312 h.flags = 0xFF;
313 tm = localtime(&max_time);
314 h.date[0] = tm->tm_year - 100;
315 h.date[1] = tm->tm_mon + 1;
316 h.date[2] = tm->tm_mday;
318 memset(padding, 0, sizeof(padding));
320 if (((f = fopen(fname, "w")) == NULL) ||
321 (fwrite(&h, sizeof(h), 1, f) != 1) ||
322 (fwrite(trx, trx->length, 1, f) != 1) ||
323 (fwrite(padding, sizeof(padding), 1, f) != 1)) {
324 perror(fname);
325 exit(1);
327 fclose(f);
330 void create_moto(const char *fname, const char *signature)
332 FILE *f;
333 moto_t h;
334 char *p;
336 h.magic = strtoul(signature, &p, 0);
337 if (*p != 0) help();
339 finalize_trx();
341 printf("Creating Motorola 0x%08X: %s\n", h.magic, fname);
343 h.magic = htonl(h.magic);
344 h.crc32 = crc_calc(0xFFFFFFFF, (void *)&h.magic, sizeof(h.magic));
345 h.crc32 = htonl(crc_calc(h.crc32, (void *)trx, trx->length));
347 if (((f = fopen(fname, "w")) == NULL) ||
348 (fwrite(&h, sizeof(h), 1, f) != 1) ||
349 (fwrite(trx, trx->length, 1, f) != 1)) {
350 perror(fname);
351 exit(1);
353 fclose(f);
356 #define MAX_STRING 12
357 #define MAX_VER 4
359 typedef struct {
360 uint8_t major;
361 uint8_t minor;
362 } version_t;
364 typedef struct {
365 version_t kernel;
366 version_t fs;
367 char productid[MAX_STRING];
368 version_t hw[MAX_VER*2];
369 char pad[32];
370 } TAIL;
372 /* usage:
373 * -r <productid>,<version>,<output file>
376 int create_asus(const char *optarg)
378 FILE *f;
379 char value[320];
380 char *next, *pid, *ver, *fname, *p;
381 TAIL asus_tail;
382 uint32_t len;
383 uint32_t v1, v2, v3, v4;
385 memset(&asus_tail, 0, sizeof(TAIL));
387 strncpy(value, optarg, sizeof(value));
388 next = value;
389 pid = strsep(&next, ",");
390 if(!pid) return 0;
392 strncpy(&asus_tail.productid[0], pid, MAX_STRING);
394 ver = strsep(&next, ",");
395 if(!ver) return 0;
397 sscanf(ver, "%d.%d.%d.%d", &v1, &v2, &v3, &v4);
398 asus_tail.kernel.major = (uint8_t)v1;
399 asus_tail.kernel.minor = (uint8_t)v2;
400 asus_tail.fs.major = (uint8_t)v3;
401 asus_tail.fs.minor = (uint8_t)v4;
403 fname = strsep(&next, ",");
404 if(!fname) return 0;
406 // append version information into the latest offset
407 trx->length += sizeof(TAIL);
408 len = trx->length;
409 trx->length = ROUNDUP(len, 4096);
411 p = (char *)trx+trx->length-sizeof(TAIL);
412 memcpy(p, &asus_tail, sizeof(TAIL));
414 finalize_trx();
416 printf("Creating ASUS %s firmware to %s\n", asus_tail.productid, fname);
418 if (((f = fopen(fname, "w")) == NULL) ||
419 (fwrite(trx, trx->length, 1, f) != 1)) {
420 perror(fname);
421 exit(1);
423 fclose(f);
425 return 1;
428 int main(int argc, char **argv)
430 char s[256];
431 char *p;
432 int o;
433 unsigned l, j;
435 printf("\n");
437 if ((!crc_init()) || ((trx = calloc(1, TRX_MAX_LEN)) == NULL)) {
438 fprintf(stderr, "Not enough memory\n");
439 exit(1);
441 trx->length = trx_header_size();
443 while ((o = getopt(argc, argv, "v:i:a:t:l:m:r:")) != -1) {
444 switch (o) {
445 case 'v':
446 set_trx_version(optarg);
447 break;
448 case 'i':
449 load_image(optarg);
450 break;
451 case 'a':
452 align_trx(optarg);
453 break;
454 case 't':
455 create_trx(optarg);
456 break;
457 case 'l':
458 case 'm':
459 if (strlen(optarg) >= sizeof(s)) help();
460 strcpy(s, optarg);
461 if ((p = strchr(s, ',')) == NULL) help();
462 *p = 0;
463 ++p;
464 if (o == 'l') create_cytan(p, s);
465 else create_moto(p, s);
466 break;
467 case 'r':
468 create_asus(optarg);
469 break;
470 default:
471 help();
472 return 1;
476 if (trx_count == 0) {
477 help();
479 else {
480 finalize_trx();
481 l = trx->length - trx_padding - trx_header_size();
482 printf("\nTRX Image:\n");
483 printf(" Total Size .... : %u (%.1f KB) (%.1f MB)\n", trx->length, trx->length / 1024.0, trx->length / 1024.0 / 1024.0);
484 printf(" Images ...... : %u (0x%08x)\n", l , l);
485 printf(" Padding ..... : %d\n", trx_padding);
487 printf(" Avail. for jffs :\n");
489 /* Reserved: 2 EBs for pmon, 1 EB for nvram. */
490 l = trx->length;
491 if (l < (4 * 1024 * 1024) - (3 * 64 * 1024))
492 j = (4 * 1024 * 1024) - (3 * 64 * 1024) - l;
493 else
494 j = 0;
495 printf(" 4MB, 128K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
497 /* Reserved: 4 EBs for pmon, 1 EB for nvram. */
498 if (l < (4 * 1024 * 1024) - (5 * 64 * 1024))
499 j = (4 * 1024 * 1024) - (5 * 64 * 1024) - l;
500 else
501 j = 0;
502 printf(" 4MB, 256K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
504 if (l < (8 * 1024 * 1024) - (5 * 64 * 1024))
505 j = (8 * 1024 * 1024) - (5 * 64 * 1024) - l;
506 else
507 j = 0;
508 printf(" 8MB, 256K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
510 if (l < (32 * 1024 * 1024) - (5 * 64 * 1024))
511 j = (32 * 1024 * 1024) - (5 * 64 * 1024) - l;
512 else
513 j = 0;
514 printf(" 32MB, 256K CFE : %d EBs + %d\n", j / (64*1024), j % (64*1024));
516 printf(" CRC-32 ........ : %8X\n", trx->crc32);
517 l = (ROUNDUP(trx->length, (128 * 1024)) / (128 * 1024));
518 printf(" 128K Blocks ... : %u (0x%08X)\n", l, l);
519 l = (ROUNDUP(trx->length, (64 * 1024)) / (64 * 1024));
520 printf(" 64K Blocks ... : %u (0x%08X)\n", l, l);
521 printf(" Offsets:\n");
522 for (o = 0; o < trx_max_offset; ++o) {
523 printf(" %d: 0x%08X %s\n", o, trx->offsets[o], names[o]);
526 printf("\n");
527 return 0;