3 Copyright 2003, CyberTAN Inc. All Rights Reserved
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
6 the contents of this file may not be disclosed to third parties,
7 copied or duplicated in any form without the prior written
8 permission of CyberTAN Inc.
10 This software should be used as a reference only, and it not
11 intended for production use!
13 THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
14 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
15 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
16 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
21 Copyright 2005, Broadcom Corporation
24 THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
25 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
26 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
32 Modified for Tomato Firmware
33 Portions, Copyright (C) 2006-2009 Jonathan Zarate
40 #include <sys/sysmacros.h>
41 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <sys/sysinfo.h>
49 #include <linux/compiler.h>
50 #include <mtd/mtd-user.h>
52 #include <linux/mtd/mtd.h>
60 // #define DEBUG_SIMULATE
72 unsigned char res3
[10];
75 // -----------------------------------------------------------------------------
77 static uint32
*crc_table
= NULL
;
79 static void crc_done(void)
85 static int crc_init(void)
90 if (crc_table
== NULL
) {
91 if ((crc_table
= malloc(sizeof(uint32
) * 256)) == NULL
) return 0;
92 for (i
= 255; i
>= 0; --i
) {
94 for (j
= 8; j
> 0; --j
) {
95 if (c
& 1) c
= (c
>> 1) ^ 0xEDB88320L
;
104 static uint32
crc_calc(uint32 crc
, char *buf
, int len
)
107 crc
= crc_table
[(crc
^ *((char *)buf
)) & 0xFF] ^ (crc
>> 8);
113 // -----------------------------------------------------------------------------
115 static int mtd_open(const char *mtdname
, mtd_info_t
*mi
)
122 if (mtd_getinfo(mtdname
, &part
, &size
)) {
123 sprintf(path
, MTD_DEV(%d
), part
);
124 if ((f
= open(path
, O_RDWR
|O_SYNC
)) >= 0) {
125 if ((mi
) && ioctl(f
, MEMGETINFO
, mi
) != 0) {
135 static int _unlock_erase(const char *mtdname
, int erase
)
146 if (!wait_action_idle(5)) return 0;
147 set_action(ACT_ERASE_NVRAM
);
148 if (erase
) led(LED_DIAG
, 1);
154 if ((mf
= mtd_open(mtdname
, &mi
)) >= 0) {
157 ei
.length
= mi
.erasesize
;
158 for (ei
.start
= 0; ei
.start
< mi
.size
; ei
.start
+= mi
.erasesize
) {
159 printf("%sing 0x%x - 0x%x\n", erase
? "Eras" : "Unlock", ei
.start
, (ei
.start
+ ei
.length
) - 1);
164 loff_t offset
= ei
.start
;
166 if ((ret
= ioctl(mf
, MEMGETBADBLOCK
, &offset
)) > 0) {
167 printf("Skipping bad block at 0x%08x\n", ei
.start
);
169 } else if (ret
< 0) {
170 if (errno
== EOPNOTSUPP
) {
171 skipbb
= 1; // Not supported by this device
173 perror("MEMGETBADBLOCK");
180 if (ioctl(mf
, MEMUNLOCK
, &ei
) != 0) {
181 // perror("MEMUNLOCK");
186 if (ioctl(mf
, MEMERASE
, &ei
) != 0) {
197 printf("%sing 0x%x - 0x%x\n", erase
? "Eras" : "Unlock", ei
.start
, ei
.length
- 1);
200 if (ioctl(mf
, MEMUNLOCK
, &ei
) != 0) {
205 if (ioctl(mf
, MEMERASE
, &ei
) != 0) {
214 read(mf
, &buf
, sizeof(buf
));
218 if (erase
) led(LED_DIAG
, 0);
219 set_action(ACT_IDLE
);
221 if (r
) printf("\"%s\" successfully %s.\n", mtdname
, erase
? "erased" : "unlocked");
222 else printf("\nError %sing MTD\n", erase
? "eras" : "unlock");
228 int mtd_unlock(const char *mtdname
)
230 return _unlock_erase(mtdname
, 0);
233 int mtd_erase(const char *mtdname
)
235 return _unlock_erase(mtdname
, 1);
238 int mtd_unlock_erase_main(int argc
, char *argv
[])
243 while ((c
= getopt(argc
, argv
, "d:")) != -1) {
252 usage_exit(argv
[0], "-d part");
255 return _unlock_erase(dev
, strstr(argv
[0], "erase") ? 1 : 0);
258 int mtd_write_main(int argc
, char *argv
[])
264 struct trx_header trx
;
265 struct code_header cth
;
280 while ((c
= getopt(argc
, argv
, "i:d:w")) != -1) {
294 if ((iname
== NULL
) || (dev
== NULL
)) {
295 usage_exit(argv
[0], "-i file -d part");
298 if (!wait_action_idle(10)) {
299 printf("System is busy\n");
302 set_action(ACT_WEB_UPGRADE
);
304 if ((f
= fopen(iname
, "r")) == NULL
) {
305 error
= "Error opening input file";
309 error
= "File contains an invalid header";
311 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
315 case 0x47343557: // W54G G, GL
316 case 0x53343557: // W54S GS
317 case 0x73343557: // W54s GS v4
318 case 0x55343557: // W54U SL
319 case 0x31345257: // WR41 WRH54G
320 case 0x4E303233: // 320N WRT320N
321 case 0x4E583233: // 32XN E2000
322 case 0x4E303136: // 610N WRT610N v2
323 case 0x4E583136: // 61XN E3000
324 case 0x30303845: // E800 E800
325 case 0x30303945: // E900 E900
326 case 0x30303145: // E100 E1000
327 case 0x30323145: // E120 E1200v1
328 case 0x32323145: // E122 E1200v2
329 case 0x30353145: // E150 E1500
330 case 0x30353531: // 1550 E1550
331 case 0x3031304D: // M010 M10
332 case 0x3032304D: // M020 M20
333 case 0x3036314E: // N160 WRT160N
334 case 0x42435745: // EWCB WRT300N v1
335 case 0x4E303133: // 310N WRT310N v1/v2
336 // case 0x32435745: // EWC2 WRT300N?
337 case 0x3035314E: // N150 WRT150N
338 case 0x58353245: // E25X E2500
339 case 0x30303233: // 3200 E3200
340 case 0x30303234: // 4200 E4200
341 if (safe_fread(((char *)&cth
) + 4, 1, sizeof(cth
) - 4, f
) != (sizeof(cth
) - 4)) {
344 if (memcmp(cth
.id
, "U2ND", 4) != 0) {
348 // trx should be next...
349 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
353 case 0x5E24232A: // Netgear
354 // header length is next
355 if (safe_fread(&n
, 1, sizeof(n
), f
) != sizeof(n
)) {
358 // skip the header - we can't use seek() for fifo, so read the rest of the header
359 n
= ntohl(n
) - sizeof(sig
) - sizeof(n
);
360 if ((buf
= malloc(n
+ 1)) == NULL
) {
361 error
= "Not enough memory";
364 if (safe_fread(buf
, 1, n
, f
) != n
) {
369 // trx should be next...
370 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
377 #ifndef CONFIG_BCMWL6
378 case TRX_MAGIC_F7D3301
:
379 case TRX_MAGIC_F7D3302
:
380 case TRX_MAGIC_F7D4302
:
381 case TRX_MAGIC_F5D8235V3
:
389 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
393 case 0x50705710: // WR850G
395 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
405 if (sig
!= TRX_MAGIC
) {
408 if ((safe_fread(((char *)&trx
) + 4, 1, sizeof(trx
) - 4, f
) != (sizeof(trx
) - 4)) || (trx
.len
<= sizeof(trx
))) {
416 #ifndef CONFIG_BCMWL6
418 trx
.magic
= TRX_MAGIC_F7D3301
;
421 trx
.magic
= TRX_MAGIC_F7D3302
;
424 trx
.magic
= TRX_MAGIC_F7D4302
;
426 case MODEL_F5D8235v3
:
427 trx
.magic
= TRX_MAGIC_F5D8235V3
;
437 error
= "Not enough memory";
440 crc
= crc_calc(0xFFFFFFFF, (char *)&trx
.flag_version
, sizeof(struct trx_header
) - OFFSETOF(struct trx_header
, flag_version
));
442 if (trx
.flag_version
& TRX_NO_HEADER
) {
443 trx
.len
-= sizeof(struct trx_header
);
444 _dprintf("don't write header\n");
447 _dprintf("trx len=%db 0x%x\n", trx
.len
, trx
.len
);
449 if ((mf
= mtd_open(dev
, &mi
)) < 0) {
450 error
= "Error opening MTD device";
454 if (mi
.erasesize
< sizeof(struct trx_header
)) {
455 error
= "Error obtaining MTD information";
459 _dprintf("mtd size=%6x, erasesize=%6x\n", mi
.size
, mi
.erasesize
);
461 total
= ROUNDUP(trx
.len
, mi
.erasesize
);
462 if (total
> mi
.size
) {
463 error
= "File is too big to fit in MTD";
468 if ((si
.freeram
* si
.mem_unit
) > (total
+ (256 * 1024))) {
472 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
473 ei
.length
= mi
.erasesize
;
475 _dprintf("freeram=%ld ei.length=%d total=%u\n", si
.freeram
, ei
.length
, total
);
477 if ((buf
= malloc(ei
.length
)) == NULL
) {
478 error
= "Not enough memory";
482 #ifdef DEBUG_SIMULATE
484 if ((of
= fopen("/mnt/out.bin", "w")) == NULL
) {
485 error
= "Error creating test file";
490 if (trx
.flag_version
& TRX_NO_HEADER
) {
494 memcpy(buf
, &trx
, sizeof(trx
));
497 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx
.len
, trx
.len
, ofs
, ofs
);
501 for (ei
.start
= 0; ei
.start
< total
; ei
.start
+= ei
.length
) {
502 n
= MIN(ei
.length
, trx
.len
) - ofs
;
503 if (safe_fread(buf
+ ofs
, 1, n
, f
) != n
) {
504 error
= "Error reading file";
507 trx
.len
-= (n
+ ofs
);
509 crc
= crc_calc(crc
, buf
+ ofs
, n
);
512 _dprintf("crc=%8x trx.crc=%8x\n", crc
, trx
.crc32
);
513 if (crc
!= trx
.crc32
) {
514 error
= "Image is corrupt";
520 printf("Writing %x-%x\r", ei
.start
, (ei
.start
+ ei
.length
) - 1);
523 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
524 ofs
, n
, n
, trx
.len
, ei
.start
, ei
.length
, mi
.erasesize
);
528 _dprintf(" erase start=%x len=%x\n", ei
.start
, ei
.length
);
529 _dprintf(" write %x\n", n
);
531 #ifdef DEBUG_SIMULATE
532 if (fwrite(buf
, 1, n
, of
) != n
) {
534 error
= "Error writing to test file";
538 ioctl(mf
, MEMUNLOCK
, &ei
);
539 if (ioctl(mf
, MEMERASE
, &ei
) != 0 && model
!= MODEL_WNR3500LV2
) {
540 error
= "Error erasing MTD block";
543 if (write(mf
, buf
, n
) != n
) {
544 error
= "Error writing to MTD device";
551 // Netgear WNR3500L: write fake len and checksum at the end of mtd
558 case MODEL_WNR2000v2
:
559 error
= "Error writing fake Netgear crc";
561 // Netgear CFE has the offset of the checksum hardcoded as
562 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
563 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
564 // We rely on linux partition to be sized correctly by the kernel,
565 // so the checksum area doesn't fall outside of the linux partition,
566 // and doesn't override the rootfs.
567 ofs
= (mi
.size
> (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
569 n
= 0x00000004; // fake length - little endian
570 crc
= 0x02C0010E; // fake crc - little endian
571 memcpy(&imageInfo
[0], (char *)&n
, 4);
572 memcpy(&imageInfo
[4], (char *)&crc
, 4);
574 ei
.start
= (ofs
/ mi
.erasesize
) * mi
.erasesize
;
575 ei
.length
= mi
.erasesize
;
577 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
580 if (!(buf
= malloc(mi
.erasesize
)))
582 if (read(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
584 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
587 tmp
= buf
+ (ofs
% mi
.erasesize
);
588 memcpy(tmp
, imageInfo
, sizeof(imageInfo
));
590 #ifdef DEBUG_SIMULATE
591 if (fseek(of
, ei
.start
, SEEK_SET
) < 0)
593 if (fwrite(buf
, 1, mi
.erasesize
, of
) != n
)
596 ioctl(mf
, MEMUNLOCK
, &ei
);
597 if (ioctl(mf
, MEMERASE
, &ei
) != 0)
600 if (write(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
605 _dprintf("%s.\n", error
? : "Write Netgear fake len/crc completed");
606 // ignore crc write errors
611 #ifdef DEBUG_SIMULATE
618 // dummy read to ensure chip(s) are out of lock/suspend state
619 read(mf
, &n
, sizeof(n
));
626 #ifdef DEBUG_SIMULATE
627 set_action(ACT_IDLE
);
630 printf("%s\n", error
? error
: "Image successfully flashed");
631 _dprintf("%s\n", error
? error
: "Image successfully flashed");
632 return (error
? 1 : 0);