WRT54G3GV2-VF introduced new trx format (v2). Router has 16MB flash, but it
is splitted into primary and backup parts and only half of flash can be
used. My changes fixes version ( should be 2) in trx header for
WRT54G3GV2-VF and version information is used to  calculate crc and length
of primary image. CFE checks also if image has been sucessfully booted and
stores this information in image. I've added new parameter to mtd and mtd
runs on every successfull boot from /etc/init.d/done to mark image as
stable. I'm not c programmer so please review. Patches tested on
WRT54G3GV2-VF and WRT54GL (2.4 kernel). With small modifications should
work on 2.6. This patches could be related to ticket #7420.


Signed-off-by: Michal Osowiecki michal-osowiecki at tlen.pl 

Index: target/linux/brcm-2.4/files/drivers/mtd/maps/bcm947xx-flash.c
===================================================================
--- target/linux/brcm-2.4/files/drivers/mtd/maps/bcm947xx-flash.c       (wersja 
21701)
+++ target/linux/brcm-2.4/files/drivers/mtd/maps/bcm947xx-flash.c       (kopia 
robocza)
@@ -59,8 +59,18 @@
 #include <sbconfig.h>
 #include <sbchipc.h>
 #include <sbutils.h>
-#include <trxhdr.h>
+#define TRX_MAGIC       0x30524448      /* "HDR0" */
+#define TRX_MAX_LEN     0x720000
+#define TRX_NO_HEADER   1               /* Do not write TRX header */   
 
+struct trx_header {
+        uint32_t magic;                 /* "HDR0" */
+        uint32_t len;                   /* Length of file including header */
+        uint32_t crc32;                 /* 32-bit CRC from flag_version to end 
of file */
+        uint32_t flag_version;  /* 0:15 flags, 16:31 version */
+        uint32_t offsets[4];    /* Offsets of partitions from start of header 
*/
+};
+
 /* Global SB handle */
 extern void *bcm947xx_sbh;
 extern spinlock_t bcm947xx_sbh_lock;
@@ -269,8 +279,39 @@
        return 0;
 }
 
+static int __init
+find_dual_image_off (struct mtd_info *mtd, size_t size)
+{
+struct trx_header trx;
+       unsigned char buf[512], *block;
+       int off, blocksize;
+       u32 i;
+       size_t len;
 
+       blocksize = mtd->erasesize;
+       if (blocksize < 0x10000)
+               blocksize = 0x10000;
 
+       for (off = (128*1024); off < size; off += blocksize) {
+               memset(&trx, 0xe5, sizeof(trx));
+               /*
+                * Read into buffer 
+                */
+               if (MTD_READ(mtd, off, sizeof(trx), &len, (char *) &trx) ||
+                   len != sizeof(trx))
+                       return 0;
+               /* found last TRX header */
+               if (le32_to_cpu(trx.magic) == TRX_MAGIC){ 
+                       printk("TRX MAGIC FOUND");
+                       if (le32_to_cpu(trx.flag_version >> 16)==2){
+                               return size/2;
+                       } else {
+                               return 0;
+                       }
+               }
+       }
+       return 0;
+}
 
 static int __init
 find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
@@ -339,26 +380,50 @@
                printk(KERN_INFO "%s: Filesystem type: unknown\n", mtd->name);
                return 0;
        }
-
-       if (trx.len != part->offset + part->size - off) {
-               /* Update the trx offsets and length */
-               trx.len = part->offset + part->size - off;
        
-               /* Update the trx crc32 */
-               for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i 
<= trx.len; i += sizeof(buf)) {
-                       if (MTD_READ(mtd, off + i, sizeof(buf), &len, buf) || 
len != sizeof(buf))
-                               return 0;
-                       crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
-               }
-               trx.crc32 = crc;
+       if (le32_to_cpu((trx.flag_version >> 16))==2){
+#undef  ROUND
+#define ROUND 0x1000
+               if (trx.len != trx.offsets[3] + (ROUND - (trx.offsets[3] & 
(ROUND-1))) ) {
+                       trx.len=trx.offsets[3]+22;
+               
+                       /* Update the trx crc32 */
+                       for (i = (u32) &(((struct trx_header 
*)NULL)->flag_version); i <= (trx.len); i += sizeof(buf)) {
+                               if (MTD_READ(mtd, off + i, sizeof(buf), &len, 
buf) || len != sizeof(buf))
+                                       return 0;
+                               crc = crc32_le(crc, buf, min(sizeof(buf), 
trx.len - i));
+                       }
+                       memset(buf,0xff,8);
+                       crc = crc32_le(crc, buf, 8);
+                       memset(buf,0x00,sizeof(buf));
+                       trx.len=trx.offsets[3]+(ROUND - (trx.offsets[3] & 
(ROUND-1)));
 
-               /* read first eraseblock from the trx */
-               trx2 = block = kmalloc(mtd->erasesize, GFP_KERNEL);
-               if (MTD_READ(mtd, off, mtd->erasesize, &len, block) || len != 
mtd->erasesize) {
-                       printk("Error accessing the first trx eraseblock\n");
-                       return 0;
+                       for (i = (trx.offsets[3]+30); i <= (trx.len); i += 
sizeof(buf)) {
+                               crc = crc32_le(crc, buf, min(sizeof(buf), 
trx.len - i));
+                       }
+                       trx.crc32=crc;
                }
+       } else {
+               if (trx.len != part->offset + part->size - off) {
+                       /* Update the trx offsets and length */
+                       trx.len = part->offset + part->size - off;
                
+                       /* Update the trx crc32 */
+                       for (i = (u32) &(((struct trx_header 
*)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
+                               if (MTD_READ(mtd, off + i, sizeof(buf), &len, 
buf) || len != sizeof(buf))
+                                       return 0;
+                               crc = crc32_le(crc, buf, min(sizeof(buf), 
trx.len - i));
+                       }
+                       trx.crc32 = crc;
+               }
+       }
+       /* read first eraseblock from the trx */
+       trx2 = block = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (MTD_READ(mtd, off, mtd->erasesize, &len, block) || len != 
mtd->erasesize) {
+               printk("Error accessing the first trx eraseblock\n");
+               return 0;
+       }
+       if (trx.crc32 != trx2->crc32 || trx.len!=trx2->len) {
                printk("Updating TRX offsets and length:\n");
                printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x 
crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], 
trx2->len, trx2->crc32);
                printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x 
crc32=0x%08x\n",   trx.offsets[0],   trx.offsets[1],   trx.offsets[2],   
trx.len, trx.crc32);
@@ -373,7 +438,6 @@
                kfree(block);
                printk("Done\n");
        }
-       
        return part->size;
 }
 
@@ -381,6 +445,7 @@
 init_mtd_partitions(struct mtd_info *mtd, size_t size)
 {
        int cfe_size;
+       int dual_image_offset = 0;
 
        if ((cfe_size = find_cfe_size(mtd,size)) < 0)
                return NULL;
@@ -399,10 +464,12 @@
                bcm947xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
        }
 
+       /* dual image offset*/
+       dual_image_offset=find_dual_image_off(mtd,size);
        /* linux (kernel and rootfs) */
        if (cfe_size != 384 * 1024) {
                bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
-               bcm947xx_parts[1].size   = bcm947xx_parts[3].offset - 
+               bcm947xx_parts[1].size   = bcm947xx_parts[3].offset -  
dual_image_offset -
                        bcm947xx_parts[1].offset;
        } else {
                /* do not count the elf loader, which is on one block */
@@ -418,7 +485,7 @@
        if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
                /* entirely jffs2 */
                bcm947xx_parts[4].name = NULL;
-               bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset - 
+               bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset -
                                bcm947xx_parts[3].size;
        } else {
                /* legacy setup */
@@ -430,7 +497,7 @@
                                bcm947xx_parts[4].offset += mtd->erasesize - 
                                        (bcm947xx_parts[4].offset % 
mtd->erasesize);
                        }
-                       bcm947xx_parts[4].size = bcm947xx_parts[3].offset - 
+                       bcm947xx_parts[4].size = bcm947xx_parts[3].offset - 
dual_image_offset -
                                bcm947xx_parts[4].offset;
                } else {
                        bcm947xx_parts[4].offset = bcm947xx_parts[2].offset + 
Index: package/mtd/src/mtd.c
===================================================================
--- package/mtd/src/mtd.c       (wersja 21701)
+++ package/mtd/src/mtd.c       (kopia robocza)
@@ -66,9 +66,26 @@
        uint32_t len;           /* Length of file including header */
        uint32_t crc32;         /* 32-bit CRC from flag_version to end of file 
*/
        uint32_t flag_version;  /* 0:15 flags, 16:31 version */
-       uint32_t offsets[3];    /* Offsets of partitions from start of header */
+       uint32_t offsets[4];    /* Offsets of partitions from start of header */
 };
 
+struct code_header {                    /* from cyutils.h */
+        char magic[4];
+        char res1[4];                           /* for extra magic */
+        char fwdate[3];
+        char fwvern[3];
+        char id[4];                                     /* U2ND */
+        char hw_ver;                            /* 0: for 4702, 1: for 4712 -- 
new in 2.04.3 */
+
+        unsigned char  sn;              // Serial Number
+        unsigned char  flags[2];        /* SUPPORT_ flags new for 3.37.2 
(WRT54G v2.2 and WRT54GS v1.1) */
+        unsigned char  stable[2];       // The image is stable (for dual image)
+        unsigned char  try1[2];         // Try to boot image first time (for 
dual image)
+        unsigned char  try2[2];         // Try to boot image second time (for 
dual image)
+        unsigned char  try3[2];         // Try to boot image third time (for 
dual_image)
+        unsigned char  res3[2];
+} ;
+
 static char *buf = NULL;
 static char *imagefile = NULL;
 static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
@@ -341,6 +358,94 @@
 }
 
 static int
+mtd_stable(const char *mtd)
+{
+       int fd;
+       struct trx_header *trx;
+       struct code_header *code_hdr;
+       char *buf;
+       ssize_t res;
+       size_t block_offset =0;
+       size_t offset =0;
+
+       fd = mtd_check_open(mtd);
+       if(fd < 0) {
+               fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+               exit(1);
+       }
+       buf = malloc(erasesize);
+       if (!buf) {
+               perror("malloc");
+               exit(1);
+       }
+
+       res = pread(fd, buf, erasesize, block_offset);
+       if (res != erasesize) {
+               perror("pread");
+               exit(1);
+       }
+
+       trx = (struct trx_header *) (buf+block_offset);
+       if (trx->magic != STORE32_LE(0x30524448)) {
+               fprintf(stderr, "No trx magic found\n");
+               exit(1);
+       }
+
+       if ((trx->flag_version >> 16 ) != 2) {
+               fprintf(stderr, "Not a trx version 2 image\n"); 
+               exit(1);
+       }
+       offset=trx->offsets[3];
+       block_offset = offset & ~(erasesize - 1);
+       offset -= block_offset;
+
+       if (offset + 32 > erasesize) {
+               fprintf(stderr, "Code header split into 2 eraseblocks, 
exiting\n");
+               exit(1);
+       }
+
+       res = pread(fd, buf, erasesize, block_offset);
+       if (res != erasesize) {
+               perror("pread");
+               exit(1);
+       }
+       code_hdr = (struct code_header *) (buf+offset);
+       if (code_hdr->stable[0]== 0x73 && code_hdr->stable[1]==0x00) {
+               if (quiet < 3)
+                       fprintf(stderr, "Image already marked stable, 
exiting\n");
+               close(fd);
+               return 0;
+       }
+       code_hdr->stable[0]=0x73;
+       code_hdr->stable[1]=0x00;
+       code_hdr->try2[0]=0xff;
+       code_hdr->try2[1]=0xff;
+       code_hdr->try3[0]=0xff;
+       code_hdr->try3[1]=0xff;
+
+       if (mtd_erase_block(fd, block_offset)) {
+               fprintf(stderr, "Can't erease block at 0x%x (%s)\n", 
block_offset, strerror(errno));
+               exit(1);
+       }
+       if (quiet < 2)
+               fprintf(stderr, "Writing stable mark.\n");
+
+       if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+               fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+               exit(1);
+       }
+
+       if (quiet < 2)
+               fprintf(stderr, "Done.\n");
+
+       close (fd);
+       sync();
+       return 0;
+
+}
+
+
+static int
 mtd_refresh(const char *mtd)
 {
        int fd;
@@ -570,6 +675,7 @@
        "        write <imagefile>|-     write <imagefile> (use - for stdin) to 
device\n"
        "        jffs2write <file>       append <file> to the jffs2 partition 
on the device\n"
        "        fixtrx                  fix the checksum in a trx header on 
first boot\n"
+        "        stable                  mark trx2 image stable\n"
        "Following options are available:\n"
        "        -q                      quiet mode (once: no [w] on writing,\n"
        "                                           twice: no status 
messages)\n"
@@ -617,6 +723,7 @@
                CMD_REFRESH,
                CMD_JFFS2WRITE,
                CMD_FIXTRX,
+               CMD_STABLE,
        } cmd = -1;
 
        erase[0] = NULL;
@@ -722,6 +829,9 @@
                        fprintf(stderr, "Can't open device for writing!\n");
                        exit(1);
                }
+       } else if ((strcmp(argv[0], "stable") == 0) && (argc == 2)) {
+               cmd = CMD_STABLE;
+               device = argv[1];
        } else {
                usage();
        }
@@ -764,6 +874,9 @@
                case CMD_FIXTRX:
                        mtd_fixtrx(device, offset);
                        break;
+               case CMD_STABLE:
+                       mtd_stable(device);
+                       break;
        }
 
        sync();
Index: package/base-files/files/etc/init.d/done
===================================================================
--- package/base-files/files/etc/init.d/done    (wersja 21701)
+++ package/base-files/files/etc/init.d/done    (kopia robocza)
@@ -14,6 +14,11 @@
                sh /etc/rc.local
        }
 
+       #set trx v2 stable
+       [ -f /sbin/mtd ] {
+       /sbin/mtd stable mtd1
+       }
+
        # set leds to normal state
        . /etc/diag.sh
        set_state done
Index: tools/firmware-utils/src/trx.c
===================================================================
--- tools/firmware-utils/src/trx.c      (wersja 21701)
+++ tools/firmware-utils/src/trx.c      (kopia robocza)
@@ -129,6 +129,7 @@
                                else {
                                        trx_version = 2;
                                        cur_len += 4;
+                                       p->flag_version = 
STORE32_LE((trx_version << 16));
                                }
                                break;
                        case 'A':
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to