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
)
142 if (!wait_action_idle(5)) return 0;
143 set_action(ACT_ERASE_NVRAM
);
144 if (erase
) led(LED_DIAG
, 1);
147 if ((mf
= mtd_open(mtdname
, &mi
)) >= 0) {
150 ei
.length
= mi
.erasesize
;
151 for (ei
.start
= 0; ei
.start
< mi
.size
; ei
.start
+= mi
.erasesize
) {
152 printf("%sing 0x%x - 0x%x\n", erase
? "Eras" : "Unlock", ei
.start
, (ei
.start
+ ei
.length
) - 1);
155 if (ioctl(mf
, MEMUNLOCK
, &ei
) != 0) {
156 // perror("MEMUNLOCK");
161 if (ioctl(mf
, MEMERASE
, &ei
) != 0) {
172 printf("%sing 0x%x - 0x%x\n", erase
? "Eras" : "Unlock", ei
.start
, ei
.length
- 1);
175 if (ioctl(mf
, MEMUNLOCK
, &ei
) != 0) {
180 if (ioctl(mf
, MEMERASE
, &ei
) != 0) {
189 read(mf
, &buf
, sizeof(buf
));
193 if (erase
) led(LED_DIAG
, 0);
194 set_action(ACT_IDLE
);
196 if (r
) printf("\"%s\" successfully %s.\n", mtdname
, erase
? "erased" : "unlocked");
197 else printf("\nError %sing MTD\n", erase
? "eras" : "unlock");
203 int mtd_unlock(const char *mtdname
)
205 return _unlock_erase(mtdname
, 0);
208 int mtd_erase(const char *mtdname
)
210 return _unlock_erase(mtdname
, 1);
213 int mtd_unlock_erase_main(int argc
, char *argv
[])
218 while ((c
= getopt(argc
, argv
, "d:")) != -1) {
227 usage_exit(argv
[0], "-d part");
230 return _unlock_erase(dev
, strstr(argv
[0], "erase") ? 1 : 0);
233 int mtd_write_main(int argc
, char *argv
[])
239 struct trx_header trx
;
240 struct code_header cth
;
255 while ((c
= getopt(argc
, argv
, "i:d:w")) != -1) {
269 if ((iname
== NULL
) || (dev
== NULL
)) {
270 usage_exit(argv
[0], "-i file -d part");
273 if (!wait_action_idle(10)) {
274 printf("System is busy\n");
277 set_action(ACT_WEB_UPGRADE
);
279 if ((f
= fopen(iname
, "r")) == NULL
) {
280 error
= "Error opening input file";
284 error
= "File contains an invalid header";
286 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
290 case 0x47343557: // W54G G, GL
291 case 0x53343557: // W54S GS
292 case 0x73343557: // W54s GS v4
293 case 0x55343557: // W54U SL
294 case 0x31345257: // WR41 WRH54G
295 case 0x4E303233: // 320N WRT320N
296 case 0x4E583233: // 32XN E2000
297 case 0x4E303136: // 610N WRT610N v2
298 case 0x4E583136: // 61XN E3000
299 case 0x30303145: // E100 E1000
300 case 0x3031304D: // M010 M10
301 case 0x3032304D: // M020 M20
302 case 0x3036314E: // N160 WRT160N
303 case 0x42435745: // EWCB WRT300N v1
304 case 0x4E303133: // 310N WRT310N v1/v2
305 // case 0x32435745: // EWC2 WRT300N?
306 case 0x3035314E: // N150 WRT150N
307 case 0x30303234: // 4200 E4200
308 if (safe_fread(((char *)&cth
) + 4, 1, sizeof(cth
) - 4, f
) != (sizeof(cth
) - 4)) {
311 if (memcmp(cth
.id
, "U2ND", 4) != 0) {
315 // trx should be next...
316 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
320 case 0x5E24232A: // Netgear
321 // header length is next
322 if (safe_fread(&n
, 1, sizeof(n
), f
) != sizeof(n
)) {
325 // skip the header - we can't use seek() for fifo, so read the rest of the header
326 n
= ntohl(n
) - sizeof(sig
) - sizeof(n
);
327 if ((buf
= malloc(n
+ 1)) == NULL
) {
328 error
= "Not enough memory";
331 if (safe_fread(buf
, 1, n
, f
) != n
) {
336 // trx should be next...
337 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
344 case TRX_MAGIC_F7D3301
:
345 case TRX_MAGIC_F7D3302
:
346 case TRX_MAGIC_F7D4302
:
347 case TRX_MAGIC_F5D8235V3
:
354 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
358 case 0x50705710: // WR850G
360 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
370 if (sig
!= TRX_MAGIC
) {
373 if ((safe_fread(((char *)&trx
) + 4, 1, sizeof(trx
) - 4, f
) != (sizeof(trx
) - 4)) || (trx
.len
<= sizeof(trx
))) {
382 trx
.magic
= TRX_MAGIC_F7D3301
;
385 trx
.magic
= TRX_MAGIC_F7D3302
;
388 trx
.magic
= TRX_MAGIC_F7D4302
;
390 case MODEL_F5D8235v3
:
391 trx
.magic
= TRX_MAGIC_F5D8235V3
;
400 error
= "Not enough memory";
403 crc
= crc_calc(0xFFFFFFFF, (char *)&trx
.flag_version
, sizeof(struct trx_header
) - OFFSETOF(struct trx_header
, flag_version
));
405 if (trx
.flag_version
& TRX_NO_HEADER
) {
406 trx
.len
-= sizeof(struct trx_header
);
407 _dprintf("don't write header\n");
410 _dprintf("trx len=%db 0x%x\n", trx
.len
, trx
.len
);
412 if ((mf
= mtd_open(dev
, &mi
)) < 0) {
413 error
= "Error opening MTD device";
417 if (mi
.erasesize
< sizeof(struct trx_header
)) {
418 error
= "Error obtaining MTD information";
422 _dprintf("mtd size=%6x, erasesize=%6x\n", mi
.size
, mi
.erasesize
);
424 total
= ROUNDUP(trx
.len
, mi
.erasesize
);
425 if (total
> mi
.size
) {
426 error
= "File is too big to fit in MTD";
431 if ((si
.freeram
* si
.mem_unit
) > (total
+ (256 * 1024))) {
435 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
436 ei
.length
= mi
.erasesize
;
438 _dprintf("freeram=%ld ei.length=%d total=%u\n", si
.freeram
, ei
.length
, total
);
440 if ((buf
= malloc(ei
.length
)) == NULL
) {
441 error
= "Not enough memory";
445 #ifdef DEBUG_SIMULATE
447 if ((of
= fopen("/mnt/out.bin", "w")) == NULL
) {
448 error
= "Error creating test file";
453 if (trx
.flag_version
& TRX_NO_HEADER
) {
457 memcpy(buf
, &trx
, sizeof(trx
));
460 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx
.len
, trx
.len
, ofs
, ofs
);
464 for (ei
.start
= 0; ei
.start
< total
; ei
.start
+= ei
.length
) {
465 n
= MIN(ei
.length
, trx
.len
) - ofs
;
466 if (safe_fread(buf
+ ofs
, 1, n
, f
) != n
) {
467 error
= "Error reading file";
470 trx
.len
-= (n
+ ofs
);
472 crc
= crc_calc(crc
, buf
+ ofs
, n
);
475 _dprintf("crc=%8x trx.crc=%8x\n", crc
, trx
.crc32
);
476 if (crc
!= trx
.crc32
) {
477 error
= "Image is corrupt";
483 printf("Writing %x-%x\r", ei
.start
, (ei
.start
+ ei
.length
) - 1);
486 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
487 ofs
, n
, n
, trx
.len
, ei
.start
, ei
.length
, mi
.erasesize
);
491 _dprintf(" erase start=%x len=%x\n", ei
.start
, ei
.length
);
492 _dprintf(" write %x\n", n
);
494 #ifdef DEBUG_SIMULATE
495 if (fwrite(buf
, 1, n
, of
) != n
) {
497 error
= "Error writing to test file";
501 ioctl(mf
, MEMUNLOCK
, &ei
);
502 if (ioctl(mf
, MEMERASE
, &ei
) != 0) {
503 error
= "Error erasing MTD block";
506 if (write(mf
, buf
, n
) != n
) {
507 error
= "Error writing to MTD device";
514 // Netgear WNR3500L: write fake len and checksum at the end of mtd
521 case MODEL_WNR2000v2
:
522 error
= "Error writing fake Netgear crc";
524 // Netgear CFE has the offset of the checksum hardcoded as
525 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
526 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
527 // We rely on linux partition to be sized correctly by the kernel,
528 // so the checksum area doesn't fall outside of the linux partition,
529 // and doesn't override the rootfs.
530 ofs
= (mi
.size
> (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
532 n
= 0x00000004; // fake length - little endian
533 crc
= 0x02C0010E; // fake crc - little endian
534 memcpy(&imageInfo
[0], (char *)&n
, 4);
535 memcpy(&imageInfo
[4], (char *)&crc
, 4);
537 ei
.start
= (ofs
/ mi
.erasesize
) * mi
.erasesize
;
538 ei
.length
= mi
.erasesize
;
540 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
543 if (!(buf
= malloc(mi
.erasesize
)))
545 if (read(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
547 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
550 tmp
= buf
+ (ofs
% mi
.erasesize
);
551 memcpy(tmp
, imageInfo
, sizeof(imageInfo
));
553 #ifdef DEBUG_SIMULATE
554 if (fseek(of
, ei
.start
, SEEK_SET
) < 0)
556 if (fwrite(buf
, 1, mi
.erasesize
, of
) != n
)
559 ioctl(mf
, MEMUNLOCK
, &ei
);
560 if (ioctl(mf
, MEMERASE
, &ei
) != 0)
563 if (write(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
568 _dprintf("%s.\n", error
? : "Write Netgear fake len/crc completed");
569 // ignore crc write errors
574 #ifdef DEBUG_SIMULATE
581 // dummy read to ensure chip(s) are out of lock/suspend state
582 read(mf
, &n
, sizeof(n
));
589 #ifdef DEBUG_SIMULATE
590 set_action(ACT_IDLE
);
593 printf("%s\n", error
? error
: "Image successfully flashed");
594 _dprintf("%s\n", error
? error
: "Image successfully flashed");
595 return (error
? 1 : 0);