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 0x30303945: // E900 E900
325 case 0x30303145: // E100 E1000
326 case 0x30323145: // E120 E1200v1
327 case 0x32323145: // E122 E1200v2
328 case 0x30353145: // E150 E1500
329 case 0x30353531: // 1550 E1550
330 case 0x3031304D: // M010 M10
331 case 0x3032304D: // M020 M20
332 case 0x3036314E: // N160 WRT160N
333 case 0x42435745: // EWCB WRT300N v1
334 case 0x4E303133: // 310N WRT310N v1/v2
335 // case 0x32435745: // EWC2 WRT300N?
336 case 0x3035314E: // N150 WRT150N
337 case 0x58353245: // E25X E2500
338 case 0x30303233: // 3200 E3200
339 case 0x30303234: // 4200 E4200
340 if (safe_fread(((char *)&cth
) + 4, 1, sizeof(cth
) - 4, f
) != (sizeof(cth
) - 4)) {
343 if (memcmp(cth
.id
, "U2ND", 4) != 0) {
347 // trx should be next...
348 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
352 case 0x5E24232A: // Netgear
353 // header length is next
354 if (safe_fread(&n
, 1, sizeof(n
), f
) != sizeof(n
)) {
357 // skip the header - we can't use seek() for fifo, so read the rest of the header
358 n
= ntohl(n
) - sizeof(sig
) - sizeof(n
);
359 if ((buf
= malloc(n
+ 1)) == NULL
) {
360 error
= "Not enough memory";
363 if (safe_fread(buf
, 1, n
, f
) != n
) {
368 // trx should be next...
369 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
376 #ifndef CONFIG_BCMWL6
377 case TRX_MAGIC_F7D3301
:
378 case TRX_MAGIC_F7D3302
:
379 case TRX_MAGIC_F7D4302
:
380 case TRX_MAGIC_F5D8235V3
:
388 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
392 case 0x50705710: // WR850G
394 if (safe_fread(&sig
, 1, sizeof(sig
), f
) != sizeof(sig
)) {
404 if (sig
!= TRX_MAGIC
) {
407 if ((safe_fread(((char *)&trx
) + 4, 1, sizeof(trx
) - 4, f
) != (sizeof(trx
) - 4)) || (trx
.len
<= sizeof(trx
))) {
415 #ifndef CONFIG_BCMWL6
417 trx
.magic
= TRX_MAGIC_F7D3301
;
420 trx
.magic
= TRX_MAGIC_F7D3302
;
423 trx
.magic
= TRX_MAGIC_F7D4302
;
425 case MODEL_F5D8235v3
:
426 trx
.magic
= TRX_MAGIC_F5D8235V3
;
436 error
= "Not enough memory";
439 crc
= crc_calc(0xFFFFFFFF, (char *)&trx
.flag_version
, sizeof(struct trx_header
) - OFFSETOF(struct trx_header
, flag_version
));
441 if (trx
.flag_version
& TRX_NO_HEADER
) {
442 trx
.len
-= sizeof(struct trx_header
);
443 _dprintf("don't write header\n");
446 _dprintf("trx len=%db 0x%x\n", trx
.len
, trx
.len
);
448 if ((mf
= mtd_open(dev
, &mi
)) < 0) {
449 error
= "Error opening MTD device";
453 if (mi
.erasesize
< sizeof(struct trx_header
)) {
454 error
= "Error obtaining MTD information";
458 _dprintf("mtd size=%6x, erasesize=%6x\n", mi
.size
, mi
.erasesize
);
460 total
= ROUNDUP(trx
.len
, mi
.erasesize
);
461 if (total
> mi
.size
) {
462 error
= "File is too big to fit in MTD";
467 if ((si
.freeram
* si
.mem_unit
) > (total
+ (256 * 1024))) {
471 // ei.length = ROUNDUP((si.freeram - (256 * 1024)), mi.erasesize);
472 ei
.length
= mi
.erasesize
;
474 _dprintf("freeram=%ld ei.length=%d total=%u\n", si
.freeram
, ei
.length
, total
);
476 if ((buf
= malloc(ei
.length
)) == NULL
) {
477 error
= "Not enough memory";
481 #ifdef DEBUG_SIMULATE
483 if ((of
= fopen("/mnt/out.bin", "w")) == NULL
) {
484 error
= "Error creating test file";
489 if (trx
.flag_version
& TRX_NO_HEADER
) {
493 memcpy(buf
, &trx
, sizeof(trx
));
496 _dprintf("trx.len=%ub 0x%x ofs=%ub 0x%x\n", trx
.len
, trx
.len
, ofs
, ofs
);
500 for (ei
.start
= 0; ei
.start
< total
; ei
.start
+= ei
.length
) {
501 n
= MIN(ei
.length
, trx
.len
) - ofs
;
502 if (safe_fread(buf
+ ofs
, 1, n
, f
) != n
) {
503 error
= "Error reading file";
506 trx
.len
-= (n
+ ofs
);
508 crc
= crc_calc(crc
, buf
+ ofs
, n
);
511 _dprintf("crc=%8x trx.crc=%8x\n", crc
, trx
.crc32
);
512 if (crc
!= trx
.crc32
) {
513 error
= "Image is corrupt";
519 printf("Writing %x-%x\r", ei
.start
, (ei
.start
+ ei
.length
) - 1);
522 _dprintf("ofs=%ub n=%ub 0x%x trx.len=%ub ei.start=0x%x ei.length=0x%x mi.erasesize=0x%x\n",
523 ofs
, n
, n
, trx
.len
, ei
.start
, ei
.length
, mi
.erasesize
);
527 _dprintf(" erase start=%x len=%x\n", ei
.start
, ei
.length
);
528 _dprintf(" write %x\n", n
);
530 #ifdef DEBUG_SIMULATE
531 if (fwrite(buf
, 1, n
, of
) != n
) {
533 error
= "Error writing to test file";
537 ioctl(mf
, MEMUNLOCK
, &ei
);
538 if (ioctl(mf
, MEMERASE
, &ei
) != 0 && model
!= MODEL_WNR3500LV2
) {
539 error
= "Error erasing MTD block";
542 if (write(mf
, buf
, n
) != n
) {
543 error
= "Error writing to MTD device";
550 // Netgear WNR3500L: write fake len and checksum at the end of mtd
557 case MODEL_WNR2000v2
:
558 error
= "Error writing fake Netgear crc";
560 // Netgear CFE has the offset of the checksum hardcoded as
561 // 0x78FFF8 on 8MB flash, and 0x38FFF8 on 4MB flash - in both
562 // cases this is 8 last bytes in the block exactly 6 blocks to the end.
563 // We rely on linux partition to be sized correctly by the kernel,
564 // so the checksum area doesn't fall outside of the linux partition,
565 // and doesn't override the rootfs.
566 ofs
= (mi
.size
> (4 *1024 * 1024) ? 0x78FFF8 : 0x38FFF8) - 0x040000;
568 n
= 0x00000004; // fake length - little endian
569 crc
= 0x02C0010E; // fake crc - little endian
570 memcpy(&imageInfo
[0], (char *)&n
, 4);
571 memcpy(&imageInfo
[4], (char *)&crc
, 4);
573 ei
.start
= (ofs
/ mi
.erasesize
) * mi
.erasesize
;
574 ei
.length
= mi
.erasesize
;
576 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
579 if (!(buf
= malloc(mi
.erasesize
)))
581 if (read(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
583 if (lseek(mf
, ei
.start
, SEEK_SET
) < 0)
586 tmp
= buf
+ (ofs
% mi
.erasesize
);
587 memcpy(tmp
, imageInfo
, sizeof(imageInfo
));
589 #ifdef DEBUG_SIMULATE
590 if (fseek(of
, ei
.start
, SEEK_SET
) < 0)
592 if (fwrite(buf
, 1, mi
.erasesize
, of
) != n
)
595 ioctl(mf
, MEMUNLOCK
, &ei
);
596 if (ioctl(mf
, MEMERASE
, &ei
) != 0)
599 if (write(mf
, buf
, mi
.erasesize
) != mi
.erasesize
)
604 _dprintf("%s.\n", error
? : "Write Netgear fake len/crc completed");
605 // ignore crc write errors
610 #ifdef DEBUG_SIMULATE
617 // dummy read to ensure chip(s) are out of lock/suspend state
618 read(mf
, &n
, sizeof(n
));
625 #ifdef DEBUG_SIMULATE
626 set_action(ACT_IDLE
);
629 printf("%s\n", error
? error
: "Image successfully flashed");
630 _dprintf("%s\n", error
? error
: "Image successfully flashed");
631 return (error
? 1 : 0);