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 0x30303945: // E900 E900
300 case 0x30303145: // E100 E1000
301 case 0x30323145: // E120 E1200v1
302 case 0x32323145: // E122 E1200v2
303 case 0x30353145: // E150 E1500
304 case 0x30353531: // 1550 E1550
305 case 0x3031304D: // M010 M10
306 case 0x3032304D: // M020 M20
307 case 0x3036314E: // N160 WRT160N
308 case 0x42435745: // EWCB WRT300N v1
309 case 0x4E303133: // 310N WRT310N v1/v2
310 // case 0x32435745: // EWC2 WRT300N?
311 case 0x3035314E: // N150 WRT150N
312 case 0x58353245: // E25X E2500
313 case 0x30303233: // 3200 E3200
314 case 0x30303234: // 4200 E4200
315 if (safe_fread(((char *)&cth
) + 4, 1, sizeof(cth
) - 4, f
) != (sizeof(cth
) - 4)) {
318 if (memcmp(cth
.id
, "U2ND", 4) != 0) {
322 // trx should be next...
323 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
327 case 0x5E24232A: // Netgear
328 // header length is next
329 if (safe_fread(&n
, 1, sizeof(n
), f
) != sizeof(n
)) {
332 // skip the header - we can't use seek() for fifo, so read the rest of the header
333 n
= ntohl(n
) - sizeof(sig
) - sizeof(n
);
334 if ((buf
= malloc(n
+ 1)) == NULL
) {
335 error
= "Not enough memory";
338 if (safe_fread(buf
, 1, n
, f
) != n
) {
343 // trx should be next...
344 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
351 case TRX_MAGIC_F7D3301
:
352 case TRX_MAGIC_F7D3302
:
353 case TRX_MAGIC_F7D4302
:
354 case TRX_MAGIC_F5D8235V3
:
361 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
365 case 0x50705710: // WR850G
367 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
377 if (sig
!= TRX_MAGIC
) {
380 if ((safe_fread(((char *)&trx
) + 4, 1, sizeof(trx
) - 4, f
) != (sizeof(trx
) - 4)) || (trx
.len
<= sizeof(trx
))) {
389 trx
.magic
= TRX_MAGIC_F7D3301
;
392 trx
.magic
= TRX_MAGIC_F7D3302
;
395 trx
.magic
= TRX_MAGIC_F7D4302
;
397 case MODEL_F5D8235v3
:
398 trx
.magic
= TRX_MAGIC_F5D8235V3
;
407 error
= "Not enough memory";
410 crc
= crc_calc(0xFFFFFFFF, (char *)&trx
.flag_version
, sizeof(struct trx_header
) - OFFSETOF(struct trx_header
, flag_version
));
412 if (trx
.flag_version
& TRX_NO_HEADER
) {
413 trx
.len
-= sizeof(struct trx_header
);
414 _dprintf("don't write header\n");
417 _dprintf("trx len=%db 0x%x\n", trx
.len
, trx
.len
);
419 if ((mf
= mtd_open(dev
, &mi
)) < 0) {
420 error
= "Error opening MTD device";
424 if (mi
.erasesize
< sizeof(struct trx_header
)) {
425 error
= "Error obtaining MTD information";
429 _dprintf("mtd size=%6x, erasesize=%6x\n", mi
.size
, mi
.erasesize
);
431 total
= ROUNDUP(trx
.len
, mi
.erasesize
);
432 if (total
> mi
.size
) {
433 error
= "File is too big to fit in MTD";
438 if ((si
.freeram
* si
.mem_unit
) > (total
+ (256 * 1024))) {
442 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
443 ei
.length
= mi
.erasesize
;
445 _dprintf("freeram=%ld ei.length=%d total=%u\n", si
.freeram
, ei
.length
, total
);
447 if ((buf
= malloc(ei
.length
)) == NULL
) {
448 error
= "Not enough memory";
452 #ifdef DEBUG_SIMULATE
454 if ((of
= fopen("/mnt/out.bin", "w")) == NULL
) {
455 error
= "Error creating test file";
460 if (trx
.flag_version
& TRX_NO_HEADER
) {
464 memcpy(buf
, &trx
, sizeof(trx
));
467 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx
.len
, trx
.len
, ofs
, ofs
);
471 for (ei
.start
= 0; ei
.start
< total
; ei
.start
+= ei
.length
) {
472 n
= MIN(ei
.length
, trx
.len
) - ofs
;
473 if (safe_fread(buf
+ ofs
, 1, n
, f
) != n
) {
474 error
= "Error reading file";
477 trx
.len
-= (n
+ ofs
);
479 crc
= crc_calc(crc
, buf
+ ofs
, n
);
482 _dprintf("crc=%8x trx.crc=%8x\n", crc
, trx
.crc32
);
483 if (crc
!= trx
.crc32
) {
484 error
= "Image is corrupt";
490 printf("Writing %x-%x\r", ei
.start
, (ei
.start
+ ei
.length
) - 1);
493 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
494 ofs
, n
, n
, trx
.len
, ei
.start
, ei
.length
, mi
.erasesize
);
498 _dprintf(" erase start=%x len=%x\n", ei
.start
, ei
.length
);
499 _dprintf(" write %x\n", n
);
501 #ifdef DEBUG_SIMULATE
502 if (fwrite(buf
, 1, n
, of
) != n
) {
504 error
= "Error writing to test file";
508 ioctl(mf
, MEMUNLOCK
, &ei
);
509 if (ioctl(mf
, MEMERASE
, &ei
) != 0 && model
!= MODEL_WNR3500LV2
) {
510 error
= "Error erasing MTD block";
513 if (write(mf
, buf
, n
) != n
) {
514 error
= "Error writing to MTD device";
521 // Netgear WNR3500L: write fake len and checksum at the end of mtd
528 case MODEL_WNR2000v2
:
529 error
= "Error writing fake Netgear crc";
531 // Netgear CFE has the offset of the checksum hardcoded as
532 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
533 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
534 // We rely on linux partition to be sized correctly by the kernel,
535 // so the checksum area doesn't fall outside of the linux partition,
536 // and doesn't override the rootfs.
537 ofs
= (mi
.size
> (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
539 n
= 0x00000004; // fake length - little endian
540 crc
= 0x02C0010E; // fake crc - little endian
541 memcpy(&imageInfo
[0], (char *)&n
, 4);
542 memcpy(&imageInfo
[4], (char *)&crc
, 4);
544 ei
.start
= (ofs
/ mi
.erasesize
) * mi
.erasesize
;
545 ei
.length
= mi
.erasesize
;
547 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
550 if (!(buf
= malloc(mi
.erasesize
)))
552 if (read(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
554 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
557 tmp
= buf
+ (ofs
% mi
.erasesize
);
558 memcpy(tmp
, imageInfo
, sizeof(imageInfo
));
560 #ifdef DEBUG_SIMULATE
561 if (fseek(of
, ei
.start
, SEEK_SET
) < 0)
563 if (fwrite(buf
, 1, mi
.erasesize
, of
) != n
)
566 ioctl(mf
, MEMUNLOCK
, &ei
);
567 if (ioctl(mf
, MEMERASE
, &ei
) != 0)
570 if (write(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
575 _dprintf("%s.\n", error
? : "Write Netgear fake len/crc completed");
576 // ignore crc write errors
581 #ifdef DEBUG_SIMULATE
588 // dummy read to ensure chip(s) are out of lock/suspend state
589 read(mf
, &n
, sizeof(n
));
596 #ifdef DEBUG_SIMULATE
597 set_action(ACT_IDLE
);
600 printf("%s\n", error
? error
: "Image successfully flashed");
601 _dprintf("%s\n", error
? error
: "Image successfully flashed");
602 return (error
? 1 : 0);