summaryrefslogtreecommitdiffstats
path: root/src/dump.c
diff options
context:
space:
mode:
authorpancake <pancake@dazo>2007-06-02 02:23:58 +0200
committerpancake <pancake@dazo>2007-06-02 02:23:58 +0200
commitf299486ef9ee5531ebee567211eb7861ae7a93bf (patch)
tree78d1b86880660f49b10bc9dca7bfc075af985236 /src/dump.c
parent1515b7c7c12097db8c713194217d57477074c6ac (diff)
download0xFFFF-f299486ef9ee5531ebee567211eb7861ae7a93bf.tar.bz2
* Covardly copy the nanddump() function from the mtd-utils to fix dump functionality
- The new function works like the old rf_extract one, no parameters has changed. - Now a complete dump/restore will be possible. - Check for badblocks while copying data - Shows information about the partition * Better use of query_error_message() for debugging
Diffstat (limited to 'src/dump.c')
-rw-r--r--src/dump.c317
1 files changed, 298 insertions, 19 deletions
diff --git a/src/dump.c b/src/dump.c
index b286fe3..5c29c4a 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -24,6 +24,13 @@
#include <stdlib.h>
#include <string.h>
+/*
+ * Extracts a piece from an mtd device
+ * -----------------------------------
+ * This function is known to be buggy, It does not takes care about
+ * badblocks and oob data. It is replaced by nanddump(), but will
+ * probably be fixed in the future or it will die.
+ */
int rf_extract(char *dev, off_t from, off_t to, char *file)
{
off_t i, blk = 0xfffff;
@@ -60,6 +67,272 @@ __rf_extract_exit:
return 1;
}
+/*
+ * This function was covardly copied from nanddump.c @ mtd-utils-20060907
+ */
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+
+// configuration for nanddump //
+int ignoreerrors = 1; // ignore errors
+int pretty_print = 0; // print nice in ascii
+int noecc = 0; // don't error correct
+int omitoob = 1; // omit oob data
+int omitbad = 1;
+// configuration for nanddump //
+
+int nanddump(char *mtddev, unsigned long start_addr, unsigned long length, char *dumpfile)
+{
+ unsigned char readbuf[2048];
+ unsigned char oobbuf[64];
+ struct nand_oobinfo none_oobinfo = {
+ .useecc = MTD_NANDECC_OFF,
+ };
+ unsigned long ofs, end_addr = 0;
+ unsigned long long blockstart = 1;
+ int i, fd, ofd, bs, badblock = 0;
+ struct mtd_oob_buf oob = {0, 16, oobbuf};
+ mtd_info_t meminfo;
+ char pretty_buf[80];
+ int oobinfochanged = 0 ;
+ int badblocks = 1;
+ struct nand_oobinfo old_oobinfo;
+ struct mtd_ecc_stats stat1, stat2;
+ int eccstats = 0;
+
+ printf("\nExtracting %s from %s...\n", dumpfile, mtddev);
+
+ /* Open MTD device */
+ if ((fd = open(mtddev, O_RDONLY)) == -1) {
+ perror("open flash");
+ return 1;
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ return 1;
+ }
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ return 1;
+ }
+ /* Read the real oob length */
+ oob.length = meminfo.oobsize;
+
+ if (noecc) {
+ switch (ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW)) {
+ case -ENOTTY:
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ oobinfochanged = 1;
+ break;
+
+ case 0:
+ oobinfochanged = 2;
+ break;
+ default:
+ perror ("MTDFILEMODE");
+ close (fd);
+ return 1;
+ }
+ } else {
+ /* check if we can read ecc stats */
+ if (!ioctl(fd, ECCGETSTATS, &stat1)) {
+ eccstats = 1;
+ fprintf(stderr, "ECC failed: %d\n", stat1.failed);
+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
+ } else
+ perror("No ECC status information available");
+ }
+
+ /* Open output file for writing. If file name is "-", write to standard
+ * output. */
+ if (!dumpfile) {
+ ofd = STDOUT_FILENO;
+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
+ perror ("open outfile");
+ close(fd);
+ return 1;
+ }
+
+ /* Initialize start/end addresses and block size */
+ if (length)
+ end_addr = start_addr + length;
+ if (!length || end_addr > meminfo.size)
+ end_addr = meminfo.size;
+
+ bs = meminfo.writesize;
+
+ /* Print informative message */
+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
+ fprintf(stderr,
+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n",
+ (unsigned int) start_addr, (unsigned int) end_addr);
+
+ /* Dump the flash contents */
+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
+
+ progressbar(ofs, end_addr);
+
+ // new eraseblock , check for bad block
+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
+ blockstart = ofs & (~meminfo.erasesize + 1);
+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ goto closeall;
+ }
+ }
+
+ if (badblock) {
+ if (omitbad)
+ continue;
+ memset (readbuf, 0xff, bs);
+ } else {
+ /* Read page data and exit on failure */
+ if (pread(fd, readbuf, bs, ofs) != bs) {
+ perror("pread");
+ goto closeall;
+ }
+ }
+
+ /* ECC stats available ? */
+ if (eccstats) {
+ if (ioctl(fd, ECCGETSTATS, &stat2)) {
+ perror("ioctl(ECCGETSTATS)");
+ goto closeall;
+ }
+ if (stat1.failed != stat2.failed)
+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
+ " at offset 0x%08lx\n",
+ stat2.failed - stat1.failed, ofs);
+ if (stat1.corrected != stat2.corrected)
+ fprintf(stderr, "ECC: %d corrected bitflip(s) at"
+ " offset 0x%08lx\n",
+ stat2.corrected - stat1.corrected, ofs);
+ stat1 = stat2;
+ }
+
+ /* Write out page data */
+ if (pretty_print) {
+ for (i = 0; i < bs; i += 16) {
+ sprintf(pretty_buf,
+ "0x%08x: %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ (unsigned int) (ofs + i), readbuf[i],
+ readbuf[i+1], readbuf[i+2],
+ readbuf[i+3], readbuf[i+4],
+ readbuf[i+5], readbuf[i+6],
+ readbuf[i+7], readbuf[i+8],
+ readbuf[i+9], readbuf[i+10],
+ readbuf[i+11], readbuf[i+12],
+ readbuf[i+13], readbuf[i+14],
+ readbuf[i+15]);
+ write(ofd, pretty_buf, 60);
+ }
+ } else
+ write(ofd, readbuf, bs);
+
+
+ if (badblock) {
+ printf("Oops badblock %d at 0x%lx !\n", badblocks++, ofs);
+ memset (readbuf, 0xff, meminfo.oobsize);
+ } else {
+ /* Read OOB data and exit on failure */
+ oob.start = ofs;
+ if (ioctl(fd, MEMREADOOB, &oob) != 0) {
+ perror("ioctl(MEMREADOOB)");
+ goto closeall;
+ }
+ }
+
+ if (omitoob)
+ continue;
+
+ /* Write out OOB data */
+ if (pretty_print) {
+ if (meminfo.oobsize < 16) {
+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
+ "%02x %02x\n",
+ oobbuf[0], oobbuf[1], oobbuf[2],
+ oobbuf[3], oobbuf[4], oobbuf[5],
+ oobbuf[6], oobbuf[7]);
+ write(ofd, pretty_buf, 48);
+ continue;
+ }
+
+ for (i = 0; i < meminfo.oobsize; i += 16) {
+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ oobbuf[i], oobbuf[i+1], oobbuf[i+2],
+ oobbuf[i+3], oobbuf[i+4], oobbuf[i+5],
+ oobbuf[i+6], oobbuf[i+7], oobbuf[i+8],
+ oobbuf[i+9], oobbuf[i+10], oobbuf[i+11],
+ oobbuf[i+12], oobbuf[i+13], oobbuf[i+14],
+ oobbuf[i+15]);
+ write(ofd, pretty_buf, 60);
+ }
+ } else
+ write(ofd, oobbuf, meminfo.oobsize);
+ }
+
+ /* reset oobinfo */
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close(fd);
+ close(ofd);
+ return 1;
+ }
+ }
+ /* Close the output file and MTD device */
+ close(fd);
+ close(ofd);
+
+ /* Exit happy */
+ return 0;
+
+ closeall:
+ /* The new mode change is per file descriptor ! */
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ }
+ }
+ close(fd);
+ close(ofd);
+ return 1;
+}
+
int rf_strip(char *file)
{
FILE *fd = fopen(file, "rw");
@@ -74,18 +347,19 @@ int rf_strip(char *file)
printf("Stripping padding from %s... ", file);
fflush(stdout);
fseek(fd, 0, SEEK_END);
-
- do {
- fseek(fd, -4096, SEEK_CUR);
- ret = fread(buf, 1, 4096, fd);
- fseek(fd, -4096, SEEK_CUR);
- for(ret--;ret>0;ret--)
- if (buf[ret]!=0xff) {
- fseek(fd, ret+1, SEEK_CUR);
- eof = ftell(fd);
- goto __done;
- }
- } while(1);
+ if (ftell(fd)>4096) {
+ do {
+ fseek(fd, -4096, SEEK_CUR);
+ ret = fread(buf, 1, 4096, fd);
+ fseek(fd, -4096, SEEK_CUR);
+ for(ret--;ret>0;ret--)
+ if (buf[ret]!=0xff) {
+ fseek(fd, ret+1, SEEK_CUR);
+ eof = ftell(fd);
+ goto __done;
+ }
+ } while(1);
+ }
__done:
fclose(fd);
@@ -114,21 +388,26 @@ int is_n800()
return n800;
}
-
int reverse_extract_pieces(char *dir)
{
char reply;
chdir(dir);
- rf_extract("/dev/mtd0", is_n800()?0x200:0, 0x003600, "xloader.bin");
- rf_extract("/dev/mtd0", 0x004000, 0x01ffff, "secondary.bin");
- rf_extract("/dev/mtd2", 0x000800, 0x200000, "zImage");
- rf_extract("/dev/mtd3", 0x000000, 0x1D00000, "initfs.jffs2");
+ nanddump("/dev/mtd0", is_n800()?0x200:0, 0x003600, "xloader.bin");
+ //rf_extract("/dev/mtd0", is_n800()?0x200:0, 0x003600, "xloader.bin");
+ nanddump("/dev/mtd0", 0x004000, 0x01ffff, "secondary.bin");
+ //rf_extract("/dev/mtd0", 0x004000, 0x01ffff, "secondary.bin");
+ nanddump("/dev/mtd2", 0x000800, 0x200000, "zImage");
+ //rf_extract("/dev/mtd2", 0x000800, 0x200000, "zImage");
+ nanddump("/dev/mtd3", 0x000000, 0x1D00000, "initfs.jffs2");
+ //rf_extract("/dev/mtd3", 0x000000, 0x1D00000, "initfs.jffs2");
printf("\nWARNING: the rootfs extraction on n800 is known to be buggy! feedback is welcome.\n\n");
printf("Extract rootfs? (y/N): "); fflush(stdout);
read(0, &reply, 1);
- if (reply=='y'||reply=='Y')
- rf_extract("/dev/mtd4", 0x000000, 0x6000000, "rootfs.jffs2");
+ if (reply=='y'||reply=='Y') {
+ nanddump("/dev/mtd4", 0x000000, 0x6000000, "rootfs.jffs2");
+ //rf_extract("/dev/mtd4", 0x000000, 0x6000000, "rootfs.jffs2");
+ }
else printf("*** Ignoring rootfs\n");
rf_strip("xloader.bin");
rf_strip("secondary.bin");