X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=package%2Fsystem%2Fmtd%2Fsrc%2Fmtd.c;h=60ae7adcdfac56541deb6a460175679a91baaffa;hb=8a60a419512db35f4d3583589e0e623a1a2f00c9;hp=604ca28ae29e7411739285cf66fc8a1fa97b3cae;hpb=608f4fe3b040089b30a019f1a28efeda1ca5809f;p=librecmc%2Flibrecmc.git diff --git a/package/system/mtd/src/mtd.c b/package/system/mtd/src/mtd.c index 604ca28ae2..60ae7adcdf 100644 --- a/package/system/mtd/src/mtd.c +++ b/package/system/mtd/src/mtd.c @@ -21,6 +21,8 @@ * The code is based on the linux-mtd examples. */ +#define _GNU_SOURCE +#include #include #include #include @@ -49,8 +51,32 @@ #define MAX_ARGS 8 #define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */ +#define TRX_MAGIC 0x48445230 /* "HDR0" */ +#define SEAMA_MAGIC 0x5ea3a417 + +#if !defined(__BYTE_ORDER) +#error "Unknown byte order" +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_be32(x) (x) +#define be32_to_cpu(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_be32(x) bswap_32(x) +#define be32_to_cpu(x) bswap_32(x) +#else +#error "Unsupported endianness" +#endif + +enum mtd_image_format { + MTD_IMAGE_FORMAT_UNKNOWN, + MTD_IMAGE_FORMAT_TRX, + MTD_IMAGE_FORMAT_SEAMA, +}; + static char *buf = NULL; static char *imagefile = NULL; +static enum mtd_image_format imageformat = MTD_IMAGE_FORMAT_UNKNOWN; static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR; static int buflen = 0; int quiet; @@ -67,10 +93,12 @@ int mtd_open(const char *mtd, bool block) int i; int ret; int flags = O_RDWR | O_SYNC; + char name[PATH_MAX]; + snprintf(name, sizeof(name), "\"%s\"", mtd); if ((fp = fopen("/proc/mtd", "r"))) { while (fgets(dev, sizeof(dev), fp)) { - if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) { + if (sscanf(dev, "mtd%d:", &i) && strstr(dev, name)) { snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i); if ((ret=open(dev, flags))<0) { snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i); @@ -146,13 +174,46 @@ int mtd_write_buffer(int fd, const char *buf, int offset, int length) return 0; } - static int image_check(int imagefd, const char *mtd) { + uint32_t magic; int ret = 1; - if (trx_check) { - ret = trx_check(imagefd, mtd, buf, &buflen); + int bufread; + + while (buflen < sizeof(magic)) { + bufread = read(imagefd, buf + buflen, sizeof(magic) - buflen); + if (bufread < 1) + break; + + buflen += bufread; + } + + if (buflen < sizeof(magic)) { + fprintf(stdout, "Could not get image magic\n"); + return 0; + } + + magic = ((uint32_t *)buf)[0]; + + if (be32_to_cpu(magic) == TRX_MAGIC) + imageformat = MTD_IMAGE_FORMAT_TRX; + else if (be32_to_cpu(magic) == SEAMA_MAGIC) + imageformat = MTD_IMAGE_FORMAT_SEAMA; + + switch (imageformat) { + case MTD_IMAGE_FORMAT_TRX: + if (trx_check) + ret = trx_check(imagefd, mtd, buf, &buflen); + break; + case MTD_IMAGE_FORMAT_SEAMA: + break; + default: +#ifdef target_brcm + if (!strcmp(mtd, "firmware")) + ret = 0; +#endif + break; } return ret; @@ -270,6 +331,58 @@ mtd_erase(const char *mtd) } +static int +mtd_dump(const char *mtd, int part_offset, int size) +{ + int ret = 0, offset = 0; + int fd; + char *buf; + + if (quiet < 2) + fprintf(stderr, "Dumping %s ...\n", mtd); + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + return -1; + } + + if (!size) + size = mtdsize; + + if (part_offset) + lseek(fd, part_offset, SEEK_SET); + + buf = malloc(erasesize); + if (!buf) + return -1; + + do { + int len = (size > erasesize) ? (erasesize) : (size); + int rlen = read(fd, buf, len); + + if (rlen < 0) { + if (errno == EINTR) + continue; + ret = -1; + goto out; + } + if (!rlen || rlen != len) + break; + if (mtd_block_is_bad(fd, offset)) { + fprintf(stderr, "skipping bad block at 0x%08x\n", offset); + } else { + size -= rlen; + write(1, buf, rlen); + } + offset += rlen; + } while (size > 0); + +out: + close(fd); + return ret; +} + static int mtd_verify(const char *mtd, char *file) { @@ -282,7 +395,7 @@ mtd_verify(const char *mtd, char *file) if (quiet < 2) fprintf(stderr, "Verifying %s against %s ...\n", mtd, file); - if (stat(file, &s) || md5sum(file, f_md5)) { + if (stat(file, &s) || md5sum(file, f_md5) < 0) { fprintf(stderr, "Failed to hash %s\n", file); return -1; } @@ -502,7 +615,7 @@ resume: if (mtd_block_is_bad(fd, e)) { if (!quiet) - fprintf(stderr, "\nSkipping bad block at 0x%08x ", e); + fprintf(stderr, "\nSkipping bad block at 0x%08zx ", e); skip_bad_blocks += erasesize; e += erasesize; @@ -553,14 +666,24 @@ resume: offset = 0; } - if (jffs2_replaced && trx_fixup) { - trx_fixup(fd, mtd); + if (jffs2_replaced) { + switch (imageformat) { + case MTD_IMAGE_FORMAT_TRX: + if (trx_fixup) + trx_fixup(fd, mtd); + break; + case MTD_IMAGE_FORMAT_SEAMA: + if (mtd_fixseama) + mtd_fixseama(mtd, 0); + break; + default: + break; + } } if (!quiet) fprintf(stderr, "\b\b\b\b "); -done: if (quiet < 2) fprintf(stderr, "\n"); @@ -586,6 +709,10 @@ static void usage(void) " verify |- verify (use - for stdin) to device\n" " write |- write (use - for stdin) to device\n" " jffs2write append to the jffs2 partition on the device\n"); + if (mtd_resetbc) { + fprintf(stderr, + " resetbc reset the uboot boot counter\n"); + } if (mtd_fixtrx) { fprintf(stderr, " fixtrx fix the checksum in a trx header on first boot\n"); @@ -594,7 +721,7 @@ static void usage(void) fprintf(stderr, " fixseama fix the checksum in a seama header on first boot\n"); } - fprintf(stderr, + fprintf(stderr, "Following options are available:\n" " -q quiet mode (once: no [w] on writing,\n" " twice: no status messages)\n" @@ -605,11 +732,12 @@ static void usage(void) " -d directory for jffs2write, defaults to \"tmp\"\n" " -j integrate into jffs2 data when writing an image\n" " -s skip the first n bytes when appending data to the jffs2 partiton, defaults to \"0\"\n" - " -p write beginning at partition offset\n"); + " -p write beginning at partition offset\n" + " -l the length of data that we want to dump\n"); if (mtd_fixtrx) { fprintf(stderr, " -o offset offset of the image header in the partition(for fixtrx)\n"); - } + } fprintf(stderr, #ifdef FIS_SUPPORT " -F [:[:]][,...]\n" @@ -641,7 +769,7 @@ int main (int argc, char **argv) int ch, i, boot, imagefd = 0, force, unlocked; char *erase[MAX_ARGS], *device = NULL; char *fis_layout = NULL; - size_t offset = 0, part_offset = 0; + size_t offset = 0, part_offset = 0, dump_len = 0; enum { CMD_ERASE, CMD_WRITE, @@ -650,6 +778,8 @@ int main (int argc, char **argv) CMD_FIXTRX, CMD_FIXSEAMA, CMD_VERIFY, + CMD_DUMP, + CMD_RESETBC, } cmd = -1; erase[0] = NULL; @@ -663,7 +793,7 @@ int main (int argc, char **argv) #ifdef FIS_SUPPORT "F:" #endif - "frnqe:d:s:j:p:o:")) != -1) + "frnqe:d:s:j:p:o:l:")) != -1) switch (ch) { case 'f': force = 1; @@ -707,11 +837,15 @@ int main (int argc, char **argv) usage(); } break; - case 'o': - if (!mtd_fixtrx) { - fprintf(stderr, "-o: is not available on this platform\n"); + case 'l': + errno = 0; + dump_len = strtoul(optarg, 0, 0); + if (errno) { + fprintf(stderr, "-l: illegal numeric string\n"); usage(); } + break; + case 'o': errno = 0; offset = strtoul(optarg, 0, 0); if (errno) { @@ -740,6 +874,9 @@ int main (int argc, char **argv) } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { cmd = CMD_ERASE; device = argv[1]; + } else if (((strcmp(argv[0], "resetbc") == 0) && (argc == 2)) && mtd_resetbc) { + cmd = CMD_RESETBC; + device = argv[1]; } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) { cmd = CMD_FIXTRX; device = argv[1]; @@ -750,6 +887,9 @@ int main (int argc, char **argv) cmd = CMD_VERIFY; imagefile = argv[1]; device = argv[2]; + } else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) { + cmd = CMD_DUMP; + device = argv[1]; } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; @@ -807,6 +947,9 @@ int main (int argc, char **argv) case CMD_VERIFY: mtd_verify(device, imagefile); break; + case CMD_DUMP: + mtd_dump(device, offset, dump_len); + break; case CMD_ERASE: if (!unlocked) mtd_unlock(device); @@ -823,12 +966,16 @@ int main (int argc, char **argv) mtd_write_jffs2(device, imagefile, jffs2dir); break; case CMD_FIXTRX: - if (mtd_fixtrx) { - mtd_fixtrx(device, offset); - } + if (mtd_fixtrx) { + mtd_fixtrx(device, offset); + } + case CMD_RESETBC: + if (mtd_resetbc) { + mtd_resetbc(device); + } case CMD_FIXSEAMA: if (mtd_fixseama) - mtd_fixseama(device, 0); + mtd_fixseama(device, 0); break; }