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.
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)
44 uint32_t flag_version
;
45 uint32_t offsets
[TRX_MAX_OFFSET
];
48 char names
[TRX_MAX_OFFSET
][80];
51 int trx_max_offset
= 3;
53 uint32_t trx_magic
= TRX_MAGIC
;
72 uint32_t *crc_table
= NULL
;
79 inline size_t trx_header_size(void)
81 return sizeof(*trx
) - sizeof(trx
->offsets
) + (trx_max_offset
* sizeof(trx
->offsets
[0]));
89 if (crc_table
== NULL
) {
90 if ((crc_table
= malloc(sizeof(uint32_t) * 256)) == NULL
) return 0;
91 for (i
= 255; i
>= 0; --i
) {
93 for (j
= 8; j
> 0; --j
) {
94 if (c
& 1) c
= (c
>> 1) ^ 0xEDB88320L
;
109 uint32_t crc_calc(uint32_t crc
, uint8_t *buf
, int len
)
112 crc
= crc_table
[(crc
^ *buf
) & 0xFF] ^ (crc
>> 8);
121 "fpkg - Package a firmware\n"
122 "Copyright (C) 2007 Jonathan Zarate\n"
124 "Usage: [-v <trx version>] -i <input> [-a <align>] [-i <input>] [-a <align>] {output}\n"
126 " TRX: -t <output file>\n"
127 " Linksys/Cisco: -l <id>,<output file>\n"
128 " W54G WRT54G / WRT54GL\n"
134 " 310N WRT310N v1/v2\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"
156 void load_image(const char *fname
)
164 fprintf(stderr
, "Cannot load another image if an output has already been written.\n");
167 if (trx_count
>= trx_max_offset
) {
168 fprintf(stderr
, "Too many input files.\n");
172 if (stat(fname
, &st
) != 0) {
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);
186 p
= (char *)trx
+ trx
->length
;
187 if ((f
= fopen(fname
, "r")) == NULL
) {
191 if (fread((char *)trx
+ trx
->length
, st
.st_size
, 1, f
) != 1) {
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
)
208 n
= strtoul(align
, &e
, 0);
209 if (errno
|| (e
== align
) || *e
) {
210 fprintf(stderr
, "Illegal numeric string\n");
215 fprintf(stderr
, "Cannot align if an output has already been written.\n");
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);
228 void set_trx_version(const char *ver
)
234 n
= strtoul(ver
, &e
, 0);
235 if (errno
|| (e
== ver
) || *e
) {
236 fprintf(stderr
, "Illegal numeric string\n");
241 fprintf(stderr
, "Cannot change trx version after images have already been loaded.\n");
245 if (n
< 1 || n
> 2) {
246 fprintf(stderr
, "TRX version %d is not supported.\n", n
);
250 trx_version
= (char)n
;
251 switch (trx_version
) {
259 trx
->length
= trx_header_size();
262 void finalize_trx(void)
266 if (trx_count
== 0) {
267 fprintf(stderr
, "No image was loaded.\n");
272 trx
->magic
= trx_magic
;
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
)
294 printf("Creating TRX: %s\n", fname
);
296 if (((f
= fopen(fname
, "w")) == NULL
) ||
297 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
304 void create_cytan(const char *fname
, const char *pattern
)
308 char padding
[1024 - sizeof(h
)];
311 if (strlen(pattern
) != 4) {
312 fprintf(stderr
, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern
);
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
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 printf(" Note : Netgear routers have 6 EBs less available!\n");
539 printf(" CRC-32 ........ : %8X\n", trx
->crc32
);
540 l
= (ROUNDUP(trx
->length
, (128 * 1024)) / (128 * 1024));
541 printf(" 128K Blocks ... : %u (0x%08X)\n", l
, l
);
542 l
= (ROUNDUP(trx
->length
, (64 * 1024)) / (64 * 1024));
543 printf(" 64K Blocks ... : %u (0x%08X)\n", l
, l
);
544 printf(" Offsets:\n");
545 for (o
= 0; o
< trx_max_offset
; ++o
) {
546 printf(" %d: 0x%08X %s\n", o
, trx
->offsets
[o
], names
[o
]);