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.
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)
43 uint32_t flag_version
;
44 uint32_t offsets
[TRX_MAX_OFFSET
];
47 char names
[TRX_MAX_OFFSET
][80];
50 int trx_max_offset
= 3;
52 uint32_t trx_magic
= TRX_MAGIC
;
71 uint32_t *crc_table
= NULL
;
78 inline size_t trx_header_size(void)
80 return sizeof(*trx
) - sizeof(trx
->offsets
) + (trx_max_offset
* sizeof(trx
->offsets
[0]));
88 if (crc_table
== NULL
) {
89 if ((crc_table
= malloc(sizeof(uint32_t) * 256)) == NULL
) return 0;
90 for (i
= 255; i
>= 0; --i
) {
92 for (j
= 8; j
> 0; --j
) {
93 if (c
& 1) c
= (c
>> 1) ^ 0xEDB88320L
;
108 uint32_t crc_calc(uint32_t crc
, uint8_t *buf
, int len
)
111 crc
= crc_table
[(crc
^ *buf
) & 0xFF] ^ (crc
>> 8);
120 "fpkg - Package a firmware\n"
121 "Copyright (C) 2007 Jonathan Zarate\n"
123 "Usage: [-v <trx version>] -i <input> [-a <align>] [-i <input>] [-a <align>] {output}\n"
125 " TRX: -t <output file>\n"
126 " Linksys/Cisco: -l <id>,<output file>\n"
127 " W54G WRT54G / WRT54GL\n"
133 " 310N WRT310N v1/v2\n"
139 " Motorola: -m <id>,<output file>\n"
140 " 0x10577000 WE800\n"
141 " 0x10577040 WA840\n"
142 " 0x10577050 WR850\n"
143 " Belkin: -b <id>,<output file>\n"
144 " 0x20100322 F7D3301 (Share Max)\n"
145 " 0x20090928 F7D3302 (Share)\n"
146 " 0x20091006 F7D4302 (Play)\n"
147 " 0x00017116 F5D8235 v3\n"
148 " 0x12345678 QA (QA firmware)\n"
149 " Asus: -r <id>,<v1>,<v2>,<v3>,<v4>,<output file>\n"
155 void load_image(const char *fname
)
163 fprintf(stderr
, "Cannot load another image if an output has already been written.\n");
166 if (trx_count
>= trx_max_offset
) {
167 fprintf(stderr
, "Too many input files.\n");
171 if (stat(fname
, &st
) != 0) {
175 if (st
.st_ctime
> max_time
) max_time
= st
.st_ctime
;
177 rsize
= ROUNDUP(st
.st_size
, 4);
178 if ((trx
->length
+ rsize
) > TRX_MAX_LEN
) {
179 fprintf(stderr
, "Total size %lu (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
180 (trx
->length
+ rsize
), (trx
->length
+ rsize
) / 1024.0,
181 (long unsigned int) TRX_MAX_LEN
, TRX_MAX_LEN
/ 1024.0);
185 p
= (char *)trx
+ trx
->length
;
186 if ((f
= fopen(fname
, "r")) == NULL
) {
190 if (fread((char *)trx
+ trx
->length
, st
.st_size
, 1, f
) != 1) {
195 strncpy(names
[trx_count
], fname
, sizeof(names
[0]) -1);
196 trx
->offsets
[trx_count
++] = trx
->length
;
197 trx
->length
+= rsize
;
200 void align_trx(const char *align
)
207 n
= strtoul(align
, &e
, 0);
208 if (errno
|| (e
== align
) || *e
) {
209 fprintf(stderr
, "Illegal numeric string\n");
214 fprintf(stderr
, "Cannot align if an output has already been written.\n");
218 len
= ROUNDUP(trx
->length
, n
);
219 if (len
> TRX_MAX_LEN
) {
220 fprintf(stderr
, "Total size %u (%.1f KB) is too big. Maximum is %lu (%.1f KB).\n",
221 len
, len
/ 1024.0, (long unsigned int) TRX_MAX_LEN
, TRX_MAX_LEN
/ 1024.0);
227 void set_trx_version(const char *ver
)
233 n
= strtoul(ver
, &e
, 0);
234 if (errno
|| (e
== ver
) || *e
) {
235 fprintf(stderr
, "Illegal numeric string\n");
240 fprintf(stderr
, "Cannot change trx version after images have already been loaded.\n");
244 if (n
< 1 || n
> 2) {
245 fprintf(stderr
, "TRX version %d is not supported.\n", n
);
249 trx_version
= (char)n
;
250 switch (trx_version
) {
258 trx
->length
= trx_header_size();
261 void finalize_trx(void)
265 if (trx_count
== 0) {
266 fprintf(stderr
, "No image was loaded.\n");
271 trx
->magic
= trx_magic
;
278 trx
->length
= ROUNDUP(len
, 4096);
279 trx
->magic
= trx_magic
;
280 trx
->flag_version
= trx_version
<< 16;
281 trx
->crc32
= crc_calc(0xFFFFFFFF, (void *)&trx
->flag_version
,
282 trx
->length
- (sizeof(*trx
) - (sizeof(trx
->flag_version
) + sizeof(trx
->offsets
))));
284 trx_padding
= trx
->length
- len
;
287 void create_trx(const char *fname
)
293 printf("Creating TRX: %s\n", fname
);
295 if (((f
= fopen(fname
, "w")) == NULL
) ||
296 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
303 void create_cytan(const char *fname
, const char *pattern
)
307 char padding
[1024 - sizeof(h
)];
310 if (strlen(pattern
) != 4) {
311 fprintf(stderr
, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern
);
317 printf("Creating Linksys %s: %s\n", pattern
, fname
);
319 memset(&h
, 0, sizeof(h
));
320 memcpy(h
.magic
, pattern
, 4);
321 memcpy(h
.u2nd
, "U2ND", 4);
322 h
.version
[0] = 4; // stock fw has version check
325 // h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h
327 tm
= localtime(&max_time
);
328 h
.date
[0] = tm
->tm_year
- 100;
329 h
.date
[1] = tm
->tm_mon
+ 1;
330 h
.date
[2] = tm
->tm_mday
;
332 memset(padding
, 0, sizeof(padding
));
334 if (((f
= fopen(fname
, "w")) == NULL
) ||
335 (fwrite(&h
, sizeof(h
), 1, f
) != 1) ||
336 (fwrite(trx
, trx
->length
, 1, f
) != 1) ||
337 (fwrite(padding
, sizeof(padding
), 1, f
) != 1)) {
344 void create_moto(const char *fname
, const char *signature
)
350 h
.magic
= strtoul(signature
, &p
, 0);
355 printf("Creating Motorola 0x%08X: %s\n", h
.magic
, fname
);
357 h
.magic
= htonl(h
.magic
);
358 h
.crc32
= crc_calc(0xFFFFFFFF, (void *)&h
.magic
, sizeof(h
.magic
));
359 h
.crc32
= htonl(crc_calc(h
.crc32
, (void *)trx
, trx
->length
));
361 if (((f
= fopen(fname
, "w")) == NULL
) ||
362 (fwrite(&h
, sizeof(h
), 1, f
) != 1) ||
363 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
370 #define MAX_STRING 12
381 char productid
[MAX_STRING
];
382 version_t hw
[MAX_VER
*2];
387 * -r <productid>,<version>,<output file>
390 int create_asus(const char *optarg
)
394 char *next
, *pid
, *ver
, *fname
, *p
;
397 uint32_t v1
, v2
, v3
, v4
;
399 memset(&asus_tail
, 0, sizeof(TAIL
));
401 strncpy(value
, optarg
, sizeof(value
));
403 pid
= strsep(&next
, ",");
406 strncpy(&asus_tail
.productid
[0], pid
, MAX_STRING
);
408 ver
= strsep(&next
, ",");
411 sscanf(ver
, "%d.%d.%d.%d", &v1
, &v2
, &v3
, &v4
);
412 asus_tail
.kernel
.major
= (uint8_t)v1
;
413 asus_tail
.kernel
.minor
= (uint8_t)v2
;
414 asus_tail
.fs
.major
= (uint8_t)v3
;
415 asus_tail
.fs
.minor
= (uint8_t)v4
;
417 fname
= strsep(&next
, ",");
420 // append version information into the latest offset
421 trx
->length
+= sizeof(TAIL
);
423 trx
->length
= ROUNDUP(len
, 4096);
425 p
= (char *)trx
+trx
->length
-sizeof(TAIL
);
426 memcpy(p
, &asus_tail
, sizeof(TAIL
));
430 printf("Creating Asus %s firmware to %s\n", asus_tail
.productid
, fname
);
432 if (((f
= fopen(fname
, "w")) == NULL
) ||
433 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
442 int main(int argc
, char **argv
)
451 if ((!crc_init()) || ((trx
= calloc(1, TRX_MAX_LEN
)) == NULL
)) {
452 fprintf(stderr
, "Not enough memory\n");
455 trx
->length
= trx_header_size();
456 trx_magic
= TRX_MAGIC
;
458 while ((o
= getopt(argc
, argv
, "v:i:a:t:l:m:b:r:")) != -1) {
461 set_trx_version(optarg
);
470 if (strlen(optarg
) >= sizeof(s
)) help();
472 if ((p
= strchr(s
, ',')) == NULL
) help();
475 trx_magic
= strtoul(s
, &e
, 0);
478 trx_magic
= TRX_MAGIC
;
485 if (strlen(optarg
) >= sizeof(s
)) help();
487 if ((p
= strchr(s
, ',')) == NULL
) help();
490 if (o
== 'l') create_cytan(p
, s
);
491 else create_moto(p
, s
);
502 trx_magic
= TRX_MAGIC
;
503 if (trx_count
== 0) {
508 l
= trx
->length
- trx_padding
- trx_header_size();
509 printf("\nTRX Image:\n");
510 printf(" Total Size .... : %u (%.1f KB) (%.1f MB)\n", trx
->length
, trx
->length
/ 1024.0, trx
->length
/ 1024.0 / 1024.0);
511 printf(" Images ...... : %u (0x%08x)\n", l
, l
);
512 printf(" Padding ..... : %d\n", trx_padding
);
514 printf(" Avail. for jffs :\n");
516 /* Reserved: 2 EBs for pmon, 1 EB for nvram. */
518 if (l
< (4 * 1024 * 1024) - (3 * 64 * 1024))
519 j
= (4 * 1024 * 1024) - (3 * 64 * 1024) - l
;
522 printf(" 4MB, 128K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
524 /* Reserved: 4 EBs for pmon, 1 EB for nvram. */
525 if (l
< (4 * 1024 * 1024) - (5 * 64 * 1024))
526 j
= (4 * 1024 * 1024) - (5 * 64 * 1024) - l
;
529 printf(" 4MB, 256K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
531 if (l
< (8 * 1024 * 1024) - (5 * 64 * 1024))
532 j
= (8 * 1024 * 1024) - (5 * 64 * 1024) - l
;
535 printf(" 8MB, 256K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
537 if (l
< (32 * 1024 * 1024) - (5 * 64 * 1024))
538 j
= (32 * 1024 * 1024) - (5 * 64 * 1024) - l
;
541 printf(" 32MB, 256K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
543 printf(" Note : Netgear routers have 6 EBs less available!\n");
545 printf(" CRC-32 ........ : %8X\n", trx
->crc32
);
546 l
= (ROUNDUP(trx
->length
, (128 * 1024)) / (128 * 1024));
547 printf(" 128K Blocks ... : %u (0x%08X)\n", l
, l
);
548 l
= (ROUNDUP(trx
->length
, (64 * 1024)) / (64 * 1024));
549 printf(" 64K Blocks ... : %u (0x%08X)\n", l
, l
);
550 printf(" Offsets:\n");
551 for (o
= 0; o
< trx_max_offset
; ++o
) {
552 printf(" %d: 0x%08X %s\n", o
, trx
->offsets
[o
], names
[o
]);