diff options
Diffstat (limited to 'nanddump.c')
-rw-r--r-- | nanddump.c | 490 |
1 files changed, 0 insertions, 490 deletions
diff --git a/nanddump.c b/nanddump.c deleted file mode 100644 index 4ee7ed4..0000000 --- a/nanddump.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * nanddump.c - * - * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org) - * Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Overview: - * This utility dumps the contents of raw NAND chips or NAND - * chips contained in DoC devices. - */ - -#define PROGRAM_NAME "nanddump" - -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <stdbool.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> -#include "common.h" -#include <libmtd.h> - -static void display_help(int status) -{ - fprintf(status == EXIT_SUCCESS ? stdout : stderr, -"Usage: %s [OPTIONS] MTD-device\n" -"Dumps the contents of a nand mtd partition.\n" -"\n" -"-h --help Display this help and exit\n" -" --version Output version information and exit\n" -" --bb=METHOD Choose bad block handling method (see below).\n" -"-a --forcebinary Force printing of binary data to tty\n" -"-c --canonicalprint Print canonical Hex+ASCII dump\n" -"-f file --file=file Dump to file\n" -"-l length --length=length Length\n" -"-n --noecc Read without error correction\n" -" --omitoob Omit OOB data (default)\n" -"-o --oob Dump OOB data\n" -"-p --prettyprint Print nice (hexdump)\n" -"-q --quiet Don't display progress and status messages\n" -"-s addr --startaddress=addr Start address\n" -"\n" -"--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':\n" -" padbad: dump flash data, substituting 0xFF for any bad blocks\n" -" dumpbad: dump flash data, including any bad blocks\n" -" skipbad: dump good data, completely skipping any bad blocks (default)\n", - PROGRAM_NAME); - exit(status); -} - -static void display_version(void) -{ - printf("%1$s " VERSION "\n" - "\n" - "%1$s comes with NO WARRANTY\n" - "to the extent permitted by law.\n" - "\n" - "You may redistribute copies of %1$s\n" - "under the terms of the GNU General Public Licence.\n" - "See the file `COPYING' for more information.\n", - PROGRAM_NAME); - exit(EXIT_SUCCESS); -} - -// Option variables - -static bool pretty_print = false; // print nice -static bool noecc = false; // don't error correct -static bool omitoob = true; // omit oob data -static long long start_addr; // start address -static long long length; // dump length -static const char *mtddev; // mtd device name -static const char *dumpfile; // dump file name -static bool quiet = false; // suppress diagnostic output -static bool canonical = false; // print nice + ascii -static bool forcebinary = false; // force printing binary to tty - -static enum { - padbad, // dump flash data, substituting 0xFF for any bad blocks - dumpbad, // dump flash data, including any bad blocks - skipbad, // dump good data, completely skipping any bad blocks -} bb_method = skipbad; - -static void process_options(int argc, char * const argv[]) -{ - int error = 0; - bool oob_default = true; - - for (;;) { - int option_index = 0; - static const char short_options[] = "hs:f:l:opqnca"; - static const struct option long_options[] = { - {"version", no_argument, 0, 0}, - {"bb", required_argument, 0, 0}, - {"omitoob", no_argument, 0, 0}, - {"help", no_argument, 0, 'h'}, - {"forcebinary", no_argument, 0, 'a'}, - {"canonicalprint", no_argument, 0, 'c'}, - {"file", required_argument, 0, 'f'}, - {"oob", no_argument, 0, 'o'}, - {"prettyprint", no_argument, 0, 'p'}, - {"startaddress", required_argument, 0, 's'}, - {"length", required_argument, 0, 'l'}, - {"noecc", no_argument, 0, 'n'}, - {"quiet", no_argument, 0, 'q'}, - {0, 0, 0, 0}, - }; - - int c = getopt_long(argc, argv, short_options, - long_options, &option_index); - if (c == EOF) { - break; - } - - switch (c) { - case 0: - switch (option_index) { - case 0: - display_version(); - break; - case 1: - /* Handle --bb=METHOD */ - if (!strcmp(optarg, "padbad")) - bb_method = padbad; - else if (!strcmp(optarg, "dumpbad")) - bb_method = dumpbad; - else if (!strcmp(optarg, "skipbad")) - bb_method = skipbad; - else - error++; - break; - case 2: /* --omitoob */ - if (oob_default) { - oob_default = false; - omitoob = true; - } else { - errmsg_die("--oob and --oomitoob are mutually exclusive"); - } - break; - } - break; - case 's': - start_addr = simple_strtoll(optarg, &error); - break; - case 'f': - dumpfile = xstrdup(optarg); - break; - case 'l': - length = simple_strtoll(optarg, &error); - break; - case 'o': - if (oob_default) { - oob_default = false; - omitoob = false; - } else { - errmsg_die("--oob and --oomitoob are mutually exclusive"); - } - break; - case 'a': - forcebinary = true; - break; - case 'c': - canonical = true; - case 'p': - pretty_print = true; - break; - case 'q': - quiet = true; - break; - case 'n': - noecc = true; - break; - case 'h': - display_help(EXIT_SUCCESS); - break; - case '?': - error++; - break; - } - } - - if (start_addr < 0) - errmsg_die("Can't specify negative offset with option -s: %lld", - start_addr); - - if (length < 0) - errmsg_die("Can't specify negative length with option -l: %lld", length); - - if (quiet && pretty_print) { - fprintf(stderr, "The quiet and pretty print options are mutually-\n" - "exclusive. Choose one or the other.\n"); - exit(EXIT_FAILURE); - } - - if (forcebinary && pretty_print) { - fprintf(stderr, "The forcebinary and pretty print options are\n" - "mutually-exclusive. Choose one or the " - "other.\n"); - exit(EXIT_FAILURE); - } - - if ((argc - optind) != 1 || error) - display_help(EXIT_FAILURE); - - mtddev = argv[optind]; -} - -#define PRETTY_ROW_SIZE 16 -#define PRETTY_BUF_LEN 80 - -/** - * pretty_dump_to_buffer - formats a blob of data to "hex ASCII" in memory - * @buf: data blob to dump - * @len: number of bytes in the @buf - * @linebuf: where to put the converted data - * @linebuflen: total size of @linebuf, including space for terminating NULL - * @pagedump: true - dumping as page format; false - dumping as OOB format - * @ascii: dump ascii formatted data next to hexdump - * @prefix: address to print before line in a page dump, ignored if !pagedump - * - * pretty_dump_to_buffer() works on one "line" of output at a time, i.e., - * PRETTY_ROW_SIZE bytes of input data converted to hex + ASCII output. - * - * Given a buffer of unsigned char data, pretty_dump_to_buffer() converts the - * input data to a hex/ASCII dump at the supplied memory location. A prefix - * is included based on whether we are dumping page or OOB data. The converted - * output is always NULL-terminated. - * - * e.g. - * pretty_dump_to_buffer(data, data_len, prettybuf, linelen, true, - * false, 256); - * produces: - * 0x00000100: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f - * NOTE: This function was adapted from linux kernel, "lib/hexdump.c" - */ -static void pretty_dump_to_buffer(const unsigned char *buf, size_t len, - char *linebuf, size_t linebuflen, bool pagedump, bool ascii, - unsigned long long prefix) -{ - static const char hex_asc[] = "0123456789abcdef"; - unsigned char ch; - unsigned int j, lx = 0, ascii_column; - - if (pagedump) - lx += sprintf(linebuf, "0x%.8llx: ", prefix); - else - lx += sprintf(linebuf, " OOB Data: "); - - if (!len) - goto nil; - if (len > PRETTY_ROW_SIZE) /* limit to one line at a time */ - len = PRETTY_ROW_SIZE; - - for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { - ch = buf[j]; - linebuf[lx++] = hex_asc[(ch & 0xf0) >> 4]; - linebuf[lx++] = hex_asc[ch & 0x0f]; - linebuf[lx++] = ' '; - } - if (j) - lx--; - - ascii_column = 3 * PRETTY_ROW_SIZE + 14; - - if (!ascii) - goto nil; - - /* Spacing between hex and ASCII - ensure at least one space */ - lx += sprintf(linebuf + lx, "%*s", - MAX((int)MIN(linebuflen, ascii_column) - 1 - lx, 1), - " "); - - linebuf[lx++] = '|'; - for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) - linebuf[lx++] = (isascii(buf[j]) && isprint(buf[j])) ? buf[j] - : '.'; - linebuf[lx++] = '|'; -nil: - linebuf[lx++] = '\n'; - linebuf[lx++] = '\0'; -} - - -/* - * Main program - */ -int main(int argc, char * const argv[]) -{ - long long ofs, end_addr = 0; - long long blockstart = 1; - int i, fd, ofd = 0, bs, badblock = 0; - struct mtd_dev_info mtd; - char pretty_buf[PRETTY_BUF_LEN]; - int firstblock = 1; - struct mtd_ecc_stats stat1, stat2; - bool eccstats = false; - unsigned char *readbuf = NULL, *oobbuf = NULL; - libmtd_t mtd_desc; - - process_options(argc, argv); - - /* Initialize libmtd */ - mtd_desc = libmtd_open(); - if (!mtd_desc) - return errmsg("can't initialize libmtd"); - - /* Open MTD device */ - if ((fd = open(mtddev, O_RDONLY)) == -1) { - perror(mtddev); - exit(EXIT_FAILURE); - } - - /* Fill in MTD device capability structure */ - if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0) - return errmsg("mtd_get_dev_info failed"); - - /* Allocate buffers */ - oobbuf = xmalloc(sizeof(oobbuf) * mtd.oob_size); - readbuf = xmalloc(sizeof(readbuf) * mtd.min_io_size); - - if (noecc) { - if (ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW) != 0) { - perror("MTDFILEMODE"); - goto closeall; - } - } else { - /* check if we can read ecc stats */ - if (!ioctl(fd, ECCGETSTATS, &stat1)) { - eccstats = true; - if (!quiet) { - 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(dumpfile); - goto closeall; - } - - if (!pretty_print && !forcebinary && isatty(ofd)) { - fprintf(stderr, "Not printing binary garbage to tty. Use '-a'\n" - "or '--forcebinary' to override.\n"); - goto closeall; - } - - /* Initialize start/end addresses and block size */ - if (start_addr & (mtd.min_io_size - 1)) { - fprintf(stderr, "the start address (-s parameter) is not page-aligned!\n" - "The pagesize of this NAND Flash is 0x%x.\n", - mtd.min_io_size); - goto closeall; - } - if (length) - end_addr = start_addr + length; - if (!length || end_addr > mtd.size) - end_addr = mtd.size; - - bs = mtd.min_io_size; - - /* Print informative message */ - if (!quiet) { - fprintf(stderr, "Block size %d, page size %d, OOB size %d\n", - mtd.eb_size, mtd.min_io_size, mtd.oob_size); - fprintf(stderr, - "Dumping data starting at 0x%08llx and ending at 0x%08llx...\n", - start_addr, end_addr); - } - - /* Dump the flash contents */ - for (ofs = start_addr; ofs < end_addr; ofs += bs) { - /* Check for bad block */ - if (bb_method == dumpbad) { - badblock = 0; - } else if (blockstart != (ofs & (~mtd.eb_size + 1)) || - firstblock) { - blockstart = ofs & (~mtd.eb_size + 1); - firstblock = 0; - if ((badblock = mtd_is_bad(&mtd, fd, ofs / mtd.eb_size)) < 0) { - errmsg("libmtd: mtd_is_bad"); - goto closeall; - } - } - - if (badblock) { - /* skip bad block, increase end_addr */ - if (bb_method == skipbad) { - end_addr += mtd.eb_size; - ofs += mtd.eb_size - bs; - if (end_addr > mtd.size) - end_addr = mtd.size; - continue; - } - memset(readbuf, 0xff, bs); - } else { - /* Read page data and exit on failure */ - if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) { - errmsg("mtd_read"); - 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%08llx\n", - stat2.failed - stat1.failed, ofs); - if (stat1.corrected != stat2.corrected) - fprintf(stderr, "ECC: %d corrected bitflip(s) at" - " offset 0x%08llx\n", - stat2.corrected - stat1.corrected, ofs); - stat1 = stat2; - } - - /* Write out page data */ - if (pretty_print) { - for (i = 0; i < bs; i += PRETTY_ROW_SIZE) { - pretty_dump_to_buffer(readbuf + i, PRETTY_ROW_SIZE, - pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs + i); - write(ofd, pretty_buf, strlen(pretty_buf)); - } - } else - write(ofd, readbuf, bs); - - if (omitoob) - continue; - - if (badblock) { - memset(oobbuf, 0xff, mtd.oob_size); - } else { - /* Read OOB data and exit on failure */ - if (mtd_read_oob(mtd_desc, &mtd, fd, ofs, mtd.oob_size, oobbuf)) { - errmsg("libmtd: mtd_read_oob"); - goto closeall; - } - } - - /* Write out OOB data */ - if (pretty_print) { - for (i = 0; i < mtd.oob_size; i += PRETTY_ROW_SIZE) { - pretty_dump_to_buffer(oobbuf + i, mtd.oob_size - i, - pretty_buf, PRETTY_BUF_LEN, false, canonical, 0); - write(ofd, pretty_buf, strlen(pretty_buf)); - } - } else - write(ofd, oobbuf, mtd.oob_size); - } - - /* Close the output file and MTD device, free memory */ - close(fd); - close(ofd); - free(oobbuf); - free(readbuf); - - /* Exit happy */ - return EXIT_SUCCESS; - -closeall: - close(fd); - close(ofd); - free(oobbuf); - free(readbuf); - exit(EXIT_FAILURE); -} |