Merge branch 'tomato-ND-usbmod-mixvpn' into tomato-ND-USBmod
[tomato.git] / release / src / btools / fpkg.c
blobedf60deeeb29f36f99c81c6bf2fd796186b6d3b8
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.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <getopt.h>
26 #include <time.h>
27 #include <stdint.h>
28 #include <sys/stat.h>
29 #include <arpa/inet.h>
32 #define ROUNDUP(n, a) ((n + (a - 1)) & ~(a - 1))
34 #define TRX_MAGIC 0x30524448
35 #define TRX_VERSION 1
36 #define TRX_MAX_OFFSET 3
37 #define TRX_MAX_LEN ((8 * 1024 * 1024) - ((256 + 128) * 1024)) // 8MB - (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];
50 typedef struct {
51 uint32_t crc32;
52 uint32_t magic;
53 } moto_t;
55 typedef struct {
56 uint8_t magic[4];
57 uint8_t extra1[4];
58 uint8_t date[3];
59 uint8_t version[3];
60 uint8_t u2nd[4];
61 uint8_t hardware;
62 uint8_t serial;
63 uint16_t flags;
64 uint8_t extra2[10];
65 } cytan_t;
67 uint32_t *crc_table = NULL;
68 trx_t *trx = NULL;
69 int trx_count = 0;
70 int trx_final = 0;
71 int trx_padding;
72 time_t max_time = 0;
74 int crc_init(void)
76 uint32_t c;
77 int i, j;
79 if (crc_table == NULL) {
80 if ((crc_table = malloc(sizeof(uint32_t) * 256)) == NULL) return 0;
81 for (i = 255; i >= 0; --i) {
82 c = i;
83 for (j = 8; j > 0; --j) {
84 if (c & 1) c = (c >> 1) ^ 0xEDB88320L;
85 else c >>= 1;
87 crc_table[i] = c;
90 return 1;
93 void crc_done(void)
95 free(crc_table);
96 crc_table = NULL;
99 uint32_t crc_calc(uint32_t crc, uint8_t *buf, int len)
101 while (len-- > 0) {
102 crc = crc_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
103 ++buf;
105 return crc;
108 void help(void)
110 fprintf(stderr,
111 "fpkg - Package a firmware\n"
112 "Copyright (C) 2007 Jonathan Zarate\n"
113 "\n"
114 "Usage: -i <input> [-i <input>] {output}\n"
115 "Output:\n"
116 " TRX: -t <output file>\n"
117 " Linksys: -l <id>,<output file>\n"
118 " W54G WRT54G / WRT54GL\n"
119 " W54U WRTSL54GS\n"
120 " W54S WRTS54GS\n"
121 " W54s WRT54GS v4\n"
122 " Motorola: -m <id>,<output file>\n"
123 " 0x10577000 WE800\n"
124 " 0x10577040 WA840\n"
125 " 0x10577050 WR850\n"
126 "\n"
128 exit(1);
131 void load_image(const char *fname)
133 struct stat st;
134 FILE *f;
135 long rsize;
136 char *p;
138 if (trx_final) {
139 fprintf(stderr, "Cannot load another image if an output has already been written.\n");
140 exit(1);
142 if (trx_count >= TRX_MAX_OFFSET) {
143 fprintf(stderr, "Too many input files.\n");
144 exit(1);
147 if (stat(fname, &st) != 0) {
148 perror(fname);
149 exit(1);
151 if (st.st_ctime > max_time) max_time = st.st_ctime;
153 rsize = ROUNDUP(st.st_size, 4);
154 if ((trx->length + rsize) > TRX_MAX_LEN) {
155 fprintf(stderr, "Total size is too big.\n");
156 exit(1);
159 p = (char *)trx + trx->length;
160 if ((f = fopen(fname, "r")) == NULL) {
161 perror(fname);
162 exit(1);
164 if (fread((char *)trx + trx->length, st.st_size, 1, f) != 1) {
165 perror(fname);
166 exit(1);
168 fclose(f);
169 strncpy(names[trx_count], fname, sizeof(names[0]) -1);
170 trx->offsets[trx_count++] = trx->length;
171 trx->length += rsize;
174 void finalize_trx(void)
176 uint32_t len;
178 if (trx_count == 0) {
179 fprintf(stderr, "No image was loaded.\n");
180 exit(1);
183 if (trx_final) return;
184 trx_final = 1;
186 len = trx->length;
188 trx->length = ROUNDUP(len, 4096);
189 trx->magic = TRX_MAGIC;
190 trx->flag_version = TRX_VERSION << 16;
191 trx->crc32 = crc_calc(0xFFFFFFFF, (void *)&trx->flag_version,
192 trx->length - (sizeof(*trx) - (sizeof(trx->flag_version) + sizeof(trx->offsets))));
194 trx_padding = trx->length - len;
197 void create_trx(const char *fname)
199 FILE *f;
201 finalize_trx();
203 printf("Creating TRX: %s\n", fname);
205 if (((f = fopen(fname, "w")) == NULL) ||
206 (fwrite(trx, trx->length, 1, f) != 1)) {
207 perror(fname);
208 exit(1);
210 fclose(f);
213 void create_cytan(const char *fname, const char *pattern)
215 FILE *f;
216 cytan_t h;
217 char padding[1024 - sizeof(h)];
218 struct tm *tm;
220 if (strlen(pattern) != 4) {
221 fprintf(stderr, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern);
222 exit(1);
225 finalize_trx();
227 printf("Creating Linksys %s: %s\n", pattern, fname);
229 memset(&h, 0, sizeof(h));
230 memcpy(h.magic, pattern, 4);
231 memcpy(h.u2nd, "U2ND", 4);
232 h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h
233 h.flags = 0xFF;
234 tm = localtime(&max_time);
235 h.date[0] = tm->tm_year - 100;
236 h.date[1] = tm->tm_mon + 1;
237 h.date[2] = tm->tm_mday;
239 memset(padding, 0, sizeof(padding));
241 if (((f = fopen(fname, "w")) == NULL) ||
242 (fwrite(&h, sizeof(h), 1, f) != 1) ||
243 (fwrite(trx, trx->length, 1, f) != 1) ||
244 (fwrite(padding, sizeof(padding), 1, f) != 1)) {
245 perror(fname);
246 exit(1);
248 fclose(f);
251 void create_moto(const char *fname, const char *signature)
253 FILE *f;
254 moto_t h;
255 char *p;
257 h.magic = strtoul(signature, &p, 0);
258 if (*p != 0) help();
260 finalize_trx();
262 printf("Creating Motorola 0x%08X: %s\n", h.magic, fname);
264 h.magic = htonl(h.magic);
265 h.crc32 = crc_calc(0xFFFFFFFF, (void *)&h.magic, sizeof(h.magic));
266 h.crc32 = htonl(crc_calc(h.crc32, (void *)trx, trx->length));
268 if (((f = fopen(fname, "w")) == NULL) ||
269 (fwrite(&h, sizeof(h), 1, f) != 1) ||
270 (fwrite(trx, trx->length, 1, f) != 1)) {
271 perror(fname);
272 exit(1);
274 fclose(f);
277 int main(int argc, char **argv)
279 char s[256];
280 char *p;
281 int o;
282 unsigned l;
284 printf("\n");
286 if ((!crc_init()) || ((trx = calloc(1, TRX_MAX_LEN)) == NULL)) {
287 fprintf(stderr, "Not enough memory\n");
288 exit(1);
290 trx->length = sizeof(*trx);
292 while ((o = getopt(argc, argv, "i:t:l:m:")) != -1) {
293 switch (o) {
294 case 'i':
295 load_image(optarg);
296 break;
297 case 't':
298 create_trx(optarg);
299 break;
300 case 'l':
301 case 'm':
302 if (strlen(optarg) >= sizeof(s)) help();
303 strcpy(s, optarg);
304 if ((p = strchr(s, ',')) == NULL) help();
305 *p = 0;
306 ++p;
307 if (o == 'l') create_cytan(p, s);
308 else create_moto(p, s);
309 break;
310 default:
311 help();
312 return 1;
316 if (trx_count == 0) {
317 help();
319 else {
320 finalize_trx();
321 l = trx->length - trx_padding - sizeof(*trx);
322 printf("\nTRX Image:\n");
323 printf(" Total Size .... : %u (%.1f KB) (%.1f MB)\n", trx->length, trx->length / 1024.0, trx->length / 1024.0 / 1024.0);
324 printf(" Images ...... : %u (0x%08x)\n", l , l);
325 printf(" Padding ..... : %d\n", trx_padding);
326 /* Reserved: 2 EBs for pmon, 1 EB for nvram. */
327 if (l < (4 * 1024 * 1024) - (3 * 64 * 1024))
328 l = (4 * 1024 * 1024) - (3 * 64 * 1024) - l;
329 else
330 l = 0;
331 printf(" Avail for jffs. : %d EBs + %d\n", l / (64*1024), l % (64*1024));
332 printf(" CRC-32 ........ : %8X\n", trx->crc32);
333 l = (ROUNDUP(trx->length, (128 * 1024)) / (128 * 1024));
334 printf(" 128K Blocks ... : %u (0x%08X)\n", l, l);
335 l = (ROUNDUP(trx->length, (64 * 1024)) / (64 * 1024));
336 printf(" 64K Blocks ... : %u (0x%08X)\n", l, l);
337 printf(" Offsets:\n");
338 for (o = 0; o < TRX_MAX_OFFSET; ++o) {
339 printf(" %d: 0x%08X %s\n", o, trx->offsets[o], names[o]);
342 printf("\n");
343 return 0;