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