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;
70 uint32_t *crc_table
= NULL
;
77 inline size_t trx_header_size(void)
79 return sizeof(*trx
) - sizeof(trx
->offsets
) + (trx_max_offset
* sizeof(trx
->offsets
[0]));
87 if (crc_table
== NULL
) {
88 if ((crc_table
= malloc(sizeof(uint32_t) * 256)) == NULL
) return 0;
89 for (i
= 255; i
>= 0; --i
) {
91 for (j
= 8; j
> 0; --j
) {
92 if (c
& 1) c
= (c
>> 1) ^ 0xEDB88320L
;
107 uint32_t crc_calc(uint32_t crc
, uint8_t *buf
, int len
)
110 crc
= crc_table
[(crc
^ *buf
) & 0xFF] ^ (crc
>> 8);
119 "fpkg - Package a firmware\n"
120 "Copyright (C) 2007 Jonathan Zarate\n"
122 "Usage: [-v <trx version>] -i <input> [-a <align>] [-i <input>] [-a <align>] {output}\n"
124 " TRX: -t <output file>\n"
125 " Linksys/Cisco: -l <id>,<output file>\n"
126 " W54G WRT54G / WRT54GL\n"
132 " 310N WRT310N v1/v2\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"
147 void load_image(const char *fname
)
155 fprintf(stderr
, "Cannot load another image if an output has already been written.\n");
158 if (trx_count
>= trx_max_offset
) {
159 fprintf(stderr
, "Too many input files.\n");
163 if (stat(fname
, &st
) != 0) {
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);
177 p
= (char *)trx
+ trx
->length
;
178 if ((f
= fopen(fname
, "r")) == NULL
) {
182 if (fread((char *)trx
+ trx
->length
, st
.st_size
, 1, f
) != 1) {
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
)
199 n
= strtoul(align
, &e
, 0);
200 if (errno
|| (e
== align
) || *e
) {
201 fprintf(stderr
, "Illegal numeric string\n");
206 fprintf(stderr
, "Cannot align if an output has already been written.\n");
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);
219 void set_trx_version(const char *ver
)
225 n
= strtoul(ver
, &e
, 0);
226 if (errno
|| (e
== ver
) || *e
) {
227 fprintf(stderr
, "Illegal numeric string\n");
232 fprintf(stderr
, "Cannot change trx version after images have already been loaded.\n");
236 if (n
< 1 || n
> 2) {
237 fprintf(stderr
, "TRX version %d is not supported.\n", n
);
241 trx_version
= (char)n
;
242 switch (trx_version
) {
250 trx
->length
= trx_header_size();
253 void finalize_trx(void)
257 if (trx_count
== 0) {
258 fprintf(stderr
, "No image was loaded.\n");
262 if (trx_final
) return;
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
)
282 printf("Creating TRX: %s\n", fname
);
284 if (((f
= fopen(fname
, "w")) == NULL
) ||
285 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
292 void create_cytan(const char *fname
, const char *pattern
)
296 char padding
[1024 - sizeof(h
)];
299 if (strlen(pattern
) != 4) {
300 fprintf(stderr
, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern
);
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
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)) {
330 void create_moto(const char *fname
, const char *signature
)
336 h
.magic
= strtoul(signature
, &p
, 0);
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)) {
356 #define MAX_STRING 12
367 char productid
[MAX_STRING
];
368 version_t hw
[MAX_VER
*2];
373 * -r <productid>,<version>,<output file>
376 int create_asus(const char *optarg
)
380 char *next
, *pid
, *ver
, *fname
, *p
;
383 uint32_t v1
, v2
, v3
, v4
;
385 memset(&asus_tail
, 0, sizeof(TAIL
));
387 strncpy(value
, optarg
, sizeof(value
));
389 pid
= strsep(&next
, ",");
392 strncpy(&asus_tail
.productid
[0], pid
, MAX_STRING
);
394 ver
= strsep(&next
, ",");
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
, ",");
406 // append version information into the latest offset
407 trx
->length
+= sizeof(TAIL
);
409 trx
->length
= ROUNDUP(len
, 4096);
411 p
= (char *)trx
+trx
->length
-sizeof(TAIL
);
412 memcpy(p
, &asus_tail
, sizeof(TAIL
));
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)) {
428 int main(int argc
, char **argv
)
437 if ((!crc_init()) || ((trx
= calloc(1, TRX_MAX_LEN
)) == NULL
)) {
438 fprintf(stderr
, "Not enough memory\n");
441 trx
->length
= trx_header_size();
443 while ((o
= getopt(argc
, argv
, "v:i:a:t:l:m:r:")) != -1) {
446 set_trx_version(optarg
);
459 if (strlen(optarg
) >= sizeof(s
)) help();
461 if ((p
= strchr(s
, ',')) == NULL
) help();
464 if (o
== 'l') create_cytan(p
, s
);
465 else create_moto(p
, s
);
476 if (trx_count
== 0) {
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. */
491 if (l
< (4 * 1024 * 1024) - (3 * 64 * 1024))
492 j
= (4 * 1024 * 1024) - (3 * 64 * 1024) - l
;
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
;
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
;
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
;
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
]);