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.
31 #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 ((8 * 1024 * 1024) - ((256 + 128) * 1024)) // 8MB - (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"
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");
270 if (trx_final
) return;
275 trx
->length
= ROUNDUP(len
, 4096);
276 trx
->magic
= trx_magic
;
277 trx
->flag_version
= trx_version
<< 16;
278 trx
->crc32
= crc_calc(0xFFFFFFFF, (void *)&trx
->flag_version
,
279 trx
->length
- (sizeof(*trx
) - (sizeof(trx
->flag_version
) + sizeof(trx
->offsets
))));
281 trx_padding
= trx
->length
- len
;
284 void create_trx(const char *fname
)
290 printf("Creating TRX: %s\n", fname
);
292 if (((f
= fopen(fname
, "w")) == NULL
) ||
293 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
300 void create_cytan(const char *fname
, const char *pattern
)
304 char padding
[1024 - sizeof(h
)];
307 if (strlen(pattern
) != 4) {
308 fprintf(stderr
, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern
);
314 printf("Creating Linksys %s: %s\n", pattern
, fname
);
316 memset(&h
, 0, sizeof(h
));
317 memcpy(h
.magic
, pattern
, 4);
318 memcpy(h
.u2nd
, "U2ND", 4);
319 h
.version
[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h
321 tm
= localtime(&max_time
);
322 h
.date
[0] = tm
->tm_year
- 100;
323 h
.date
[1] = tm
->tm_mon
+ 1;
324 h
.date
[2] = tm
->tm_mday
;
326 memset(padding
, 0, sizeof(padding
));
328 if (((f
= fopen(fname
, "w")) == NULL
) ||
329 (fwrite(&h
, sizeof(h
), 1, f
) != 1) ||
330 (fwrite(trx
, trx
->length
, 1, f
) != 1) ||
331 (fwrite(padding
, sizeof(padding
), 1, f
) != 1)) {
338 void create_moto(const char *fname
, const char *signature
)
344 h
.magic
= strtoul(signature
, &p
, 0);
349 printf("Creating Motorola 0x%08X: %s\n", h
.magic
, fname
);
351 h
.magic
= htonl(h
.magic
);
352 h
.crc32
= crc_calc(0xFFFFFFFF, (void *)&h
.magic
, sizeof(h
.magic
));
353 h
.crc32
= htonl(crc_calc(h
.crc32
, (void *)trx
, trx
->length
));
355 if (((f
= fopen(fname
, "w")) == NULL
) ||
356 (fwrite(&h
, sizeof(h
), 1, f
) != 1) ||
357 (fwrite(trx
, trx
->length
, 1, f
) != 1)) {
364 int main(int argc
, char **argv
)
373 if ((!crc_init()) || ((trx
= calloc(1, TRX_MAX_LEN
)) == NULL
)) {
374 fprintf(stderr
, "Not enough memory\n");
377 trx
->length
= trx_header_size();
379 while ((o
= getopt(argc
, argv
, "v:i:a:t:l:m:b:")) != -1) {
382 set_trx_version(optarg
);
391 if (strlen(optarg
) >= sizeof(s
)) help();
393 if ((p
= strchr(s
, ',')) == NULL
) help();
396 trx_magic
= strtoul(s
, &e
, 0);
399 trx_magic
= TRX_MAGIC
;
406 if (strlen(optarg
) >= sizeof(s
)) help();
408 if ((p
= strchr(s
, ',')) == NULL
) help();
411 if (o
== 'l') create_cytan(p
, s
);
412 else create_moto(p
, s
);
420 if (trx_count
== 0) {
425 l
= trx
->length
- trx_padding
- trx_header_size();
426 printf("\nTRX Image:\n");
427 printf(" Total Size .... : %u (%.1f KB) (%.1f MB)\n", trx
->length
, trx
->length
/ 1024.0, trx
->length
/ 1024.0 / 1024.0);
428 printf(" Images ...... : %u (0x%08x)\n", l
, l
);
429 printf(" Padding ..... : %d\n", trx_padding
);
431 printf(" Avail. for jffs :\n");
433 /* Reserved: 2 EBs for pmon, 1 EB for nvram. */
435 if (l
< (4 * 1024 * 1024) - (3 * 64 * 1024))
436 j
= (4 * 1024 * 1024) - (3 * 64 * 1024) - l
;
439 printf(" 4MB, 128K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
441 /* Reserved: 4 EBs for pmon, 1 EB for nvram. */
442 if (l
< (4 * 1024 * 1024) - (5 * 64 * 1024))
443 j
= (4 * 1024 * 1024) - (5 * 64 * 1024) - l
;
446 printf(" 4MB, 256K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
448 if (l
< (8 * 1024 * 1024) - (5 * 64 * 1024))
449 j
= (8 * 1024 * 1024) - (5 * 64 * 1024) - l
;
452 printf(" 8MB, 256K CFE : %d EBs + %d\n", j
/ (64*1024), j
% (64*1024));
454 printf(" Note : Netgear routers have 6 EBs less available!\n");
456 printf(" CRC-32 ........ : %8X\n", trx
->crc32
);
457 l
= (ROUNDUP(trx
->length
, (128 * 1024)) / (128 * 1024));
458 printf(" 128K Blocks ... : %u (0x%08X)\n", l
, l
);
459 l
= (ROUNDUP(trx
->length
, (64 * 1024)) / (64 * 1024));
460 printf(" 64K Blocks ... : %u (0x%08X)\n", l
, l
);
461 printf(" Offsets:\n");
462 for (o
= 0; o
< trx_max_offset
; ++o
) {
463 printf(" %d: 0x%08X %s\n", o
, trx
->offsets
[o
], names
[o
]);