aboutsummaryrefslogtreecommitdiff
path: root/nand-utils
diff options
context:
space:
mode:
Diffstat (limited to 'nand-utils')
-rw-r--r--nand-utils/Makemodule.am17
-rw-r--r--nand-utils/nanddump.c39
-rw-r--r--nand-utils/nandflipbits.c7
-rw-r--r--nand-utils/nandtest.c49
-rw-r--r--nand-utils/nandwrite.c13
5 files changed, 90 insertions, 35 deletions
diff --git a/nand-utils/Makemodule.am b/nand-utils/Makemodule.am
index b5a15ac..cee6777 100644
--- a/nand-utils/Makemodule.am
+++ b/nand-utils/Makemodule.am
@@ -7,29 +7,24 @@ nandwrite_LDADD = libmtd.a
nandtest_SOURCES = nand-utils/nandtest.c
nandtest_LDADD = libmtd.a
-nftldump_SOURCES = nand-utils/nftldump.c
+nftldump_SOURCES = nand-utils/nftldump.c include/mtd_swab.h
+nftldump_SOURCES += include/mtd/nftl-user.h include/mtd/ftl-user.h
nftldump_LDADD = libmtd.a
-nftl_format_SOURCES = nand-utils/nftl_format.c
+nftl_format_SOURCES = nand-utils/nftl_format.c include/mtd_swab.h
+nftl_format_SOURCES += include/mtd/nftl-user.h include/mtd/ftl-user.h
nftl_format_LDADD = libmtd.a
nandflipbits_SOURCES = nand-utils/nandflipbits.c
nandflipbits_LDADD = libmtd.a
-NAND_BINS = \
- nanddump nandwrite nandtest nftldump nftl_format nandflipbits
-
NAND_SH = \
nand-utils/load_nandsim.sh
EXTRA_DIST += $(NAND_SH)
-sbin_PROGRAMS += $(NAND_BINS)
+sbin_PROGRAMS += nanddump nandwrite nandtest nftldump nftl_format nandflipbits
if BUILD_TESTS
-if INSTALL_TESTS
-pkglibexec_SCRIPTS += $(NAND_SH)
-else
-noinst_SCRIPTS += $(NAND_SH)
-endif
+test_SCRIPTS += $(NAND_SH)
endif
diff --git a/nand-utils/nanddump.c b/nand-utils/nanddump.c
index d7fc320..b4de05e 100644
--- a/nand-utils/nanddump.c
+++ b/nand-utils/nanddump.c
@@ -54,6 +54,7 @@ static void display_help(int status)
"-s addr --startaddress=addr Start address\n"
" --skip-bad-blocks-to-start\n"
" Skip bad blocks when seeking to the start address\n"
+"-C --continuous Continuous read up to a block of data at a time\n"
"\n"
"--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':\n"
" padbad: dump flash data, substituting 0xFF for any bad blocks\n"
@@ -89,6 +90,7 @@ static bool quiet = false; // suppress diagnostic output
static bool canonical = false; // print nice + ascii
static bool forcebinary = false; // force printing binary to tty
static bool skip_bad_blocks_to_start = false;
+static bool continuous = false; // leverage continuous reads
static enum {
padbad, // dump flash data, substituting 0xFF for any bad blocks
@@ -100,10 +102,11 @@ static void process_options(int argc, char * const argv[])
{
int error = 0;
bool oob_default = true;
+ char *dumpfile_tmp = NULL;
for (;;) {
int option_index = 0;
- static const char short_options[] = "hs:f:l:opqncaV";
+ static const char short_options[] = "hs:f:l:opqncaVC";
static const struct option long_options[] = {
{"version", no_argument, 0, 'V'},
{"bb", required_argument, 0, 0},
@@ -119,6 +122,7 @@ static void process_options(int argc, char * const argv[])
{"length", required_argument, 0, 'l'},
{"noecc", no_argument, 0, 'n'},
{"quiet", no_argument, 0, 'q'},
+ {"continuous", no_argument, 0, 'C'},
{0, 0, 0, 0},
};
@@ -162,8 +166,8 @@ static void process_options(int argc, char * const argv[])
start_addr = simple_strtoll(optarg, &error);
break;
case 'f':
- free(dumpfile);
- dumpfile = xstrdup(optarg);
+ free(dumpfile_tmp);
+ dumpfile = dumpfile_tmp = xstrdup(optarg);
break;
case 'l':
length = simple_strtoll(optarg, &error);
@@ -191,6 +195,9 @@ static void process_options(int argc, char * const argv[])
case 'n':
noecc = true;
break;
+ case 'C':
+ continuous = true;
+ break;
case 'h':
display_help(EXIT_SUCCESS);
break;
@@ -220,6 +227,13 @@ static void process_options(int argc, char * const argv[])
exit(EXIT_FAILURE);
}
+ if (continuous && !omitoob) {
+ fprintf(stderr, "Sequential/continuous reads (when available) will\n"
+ "always skip OOB data, so it is not possible to \n"
+ "request both at the same time.\n");
+ exit(EXIT_FAILURE);
+ }
+
if ((argc - optind) != 1 || error)
display_help(EXIT_FAILURE);
@@ -332,7 +346,7 @@ static int ofd_write(int ofd, const void *buf, size_t nbyte)
*/
int main(int argc, char * const argv[])
{
- long long ofs, end_addr = 0;
+ long long ofs, end_addr = 0, readbuf_sz;
long long blockstart = 1;
int i, fd, ofd = 0, bs, badblock = 0;
struct mtd_dev_info mtd;
@@ -362,8 +376,9 @@ int main(int argc, char * const argv[])
return errmsg("mtd_get_dev_info failed");
/* Allocate buffers */
+ readbuf_sz = mtd.eb_size;
oobbuf = xmalloc(mtd.oob_size);
- readbuf = xmalloc(mtd.min_io_size);
+ readbuf = xmalloc(readbuf_sz);
if (noecc) {
if (ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW) != 0) {
@@ -427,8 +442,6 @@ int main(int argc, char * const argv[])
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",
@@ -440,6 +453,8 @@ int main(int argc, char * const argv[])
/* Dump the flash contents */
for (ofs = start_addr; ofs < end_addr; ofs += bs) {
+ long long size_left = end_addr - ofs;
+
/* Check for bad block */
if (bb_method == dumpbad) {
badblock = 0;
@@ -453,16 +468,21 @@ int main(int argc, char * const argv[])
}
}
+ if (continuous)
+ bs = MIN(size_left, mtd.eb_size);
+ else
+ bs = mtd.min_io_size;
+
if (badblock) {
/* skip bad block, increase end_addr */
if (bb_method == skipbad) {
end_addr += mtd.eb_size;
- ofs += mtd.eb_size - bs;
+ ofs += mtd.eb_size - mtd.min_io_size;
if (end_addr > mtd.size)
end_addr = mtd.size;
continue;
}
- memset(readbuf, 0xff, bs);
+ memset(readbuf, 0xff, readbuf_sz);
} else {
/* Read page data and exit on failure */
if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
@@ -499,7 +519,6 @@ int main(int argc, char * const argv[])
}
} else {
/* Write requested length if oob is omitted */
- size_t size_left = end_addr - ofs;
if (omitoob && (size_left < bs))
err = ofd_write(ofd, readbuf, size_left);
else
diff --git a/nand-utils/nandflipbits.c b/nand-utils/nandflipbits.c
index aa6850f..a417189 100644
--- a/nand-utils/nandflipbits.c
+++ b/nand-utils/nandflipbits.c
@@ -203,7 +203,8 @@ int main(int argc, char **argv)
int page;
if (bits_to_flip[i].offset >= mtdlen) {
- fprintf(stderr, "Invalid byte offset %lld (max %lld)\n",
+ fprintf(stderr, "Invalid byte offset %" PRId64
+ " (max %" PRId64 ")\n",
bits_to_flip[i].offset, mtdlen);
ret = EXIT_FAILURE;
goto free_buf;
@@ -249,7 +250,9 @@ int main(int argc, char **argv)
bufoffs += mtd.min_io_size;
- ret = mtd_read_oob(mtd_desc, &mtd, fd, blkoffs,
+ ret = mtd_read_oob(mtd_desc, &mtd, fd,
+ (unsigned long long)bit_to_flip->block * mtd.eb_size +
+ blkoffs,
mtd.oob_size, buffer + bufoffs);
if (ret) {
fprintf(stderr, "MTD OOB read failure\n");
diff --git a/nand-utils/nandtest.c b/nand-utils/nandtest.c
index 06dec25..cac0dde 100644
--- a/nand-utils/nandtest.c
+++ b/nand-utils/nandtest.c
@@ -8,6 +8,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -144,6 +145,26 @@ static int erase_and_write(loff_t ofs, unsigned char *data, unsigned char *rbuf,
return 0;
}
+static uint64_t get_mem_size(const char* device)
+{
+ const char* p = strrchr(device, '/');
+ char path[PATH_MAX];
+ int fd;
+
+ snprintf(path, sizeof(path), "/sys/class/mtd/%s/size", p);
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ char buffer[32];
+ ssize_t n = read(fd, buffer, sizeof(buffer));
+ close(fd);
+ if (n > 0) {
+ return strtoull(buffer, NULL, 0);
+ }
+ }
+
+ fprintf(stderr, "Can't read size from %s\n", path);
+ exit(1);
+}
/*
* Main program
@@ -156,8 +177,9 @@ int main(int argc, char **argv)
int nr_passes = 1;
int nr_reads = 4;
int keep_contents = 0;
- uint32_t offset = 0;
- uint32_t length = -1;
+ uint64_t offset = 0;
+ uint64_t length = -1;
+ uint64_t mem_size = 0;
int error = 0;
seed = time(NULL);
@@ -212,11 +234,11 @@ int main(int argc, char **argv)
break;
case 'o':
- offset = simple_strtoul(optarg, &error);
+ offset = simple_strtoull(optarg, &error);
break;
case 'l':
- length = simple_strtoul(optarg, &error);
+ length = simple_strtoull(optarg, &error);
break;
}
@@ -238,29 +260,34 @@ int main(int argc, char **argv)
exit(1);
}
+ mem_size = get_mem_size(argv[optind]);
+
if (length == -1)
- length = meminfo.size;
+ length = mem_size;
if (offset % meminfo.erasesize) {
- fprintf(stderr, "Offset %x not multiple of erase size %x\n",
+ fprintf(stderr, "Offset %" PRIx64
+ " not multiple of erase size %x\n",
offset, meminfo.erasesize);
exit(1);
}
if (length % meminfo.erasesize) {
- fprintf(stderr, "Length %x not multiple of erase size %x\n",
+ fprintf(stderr, "Length %" PRIx64
+ " not multiple of erase size %x\n",
length, meminfo.erasesize);
exit(1);
}
- if (length + offset > meminfo.size) {
- fprintf(stderr, "Length %x + offset %x exceeds device size %x\n",
- length, offset, meminfo.size);
+ if (length + offset > mem_size) {
+ fprintf(stderr, "Length %" PRIx64 " + offset %" PRIx64
+ " exceeds device size %" PRIx64 "\n",
+ length, offset, mem_size);
exit(1);
}
wbuf = malloc(meminfo.erasesize * 3);
if (!wbuf) {
fprintf(stderr, "Could not allocate %d bytes for buffer\n",
- meminfo.erasesize * 2);
+ meminfo.erasesize * 3);
exit(1);
}
rbuf = wbuf + meminfo.erasesize;
diff --git a/nand-utils/nandwrite.c b/nand-utils/nandwrite.c
index e8a210c..cd53a17 100644
--- a/nand-utils/nandwrite.c
+++ b/nand-utils/nandwrite.c
@@ -280,6 +280,7 @@ int main(int argc, char * const argv[])
libmtd_t mtd_desc;
int ebsize_aligned;
uint8_t write_mode;
+ size_t all_ffs_cnt = 0;
process_options(argc, argv);
@@ -417,6 +418,8 @@ int main(int argc, char * const argv[])
*/
while ((imglen > 0 || writebuf < filebuf + filebuf_len)
&& mtdoffset < mtd.size) {
+ bool allffs;
+
/*
* New eraseblock, check for bad block(s)
* Stay in the loop to be sure that, if mtdoffset changes because
@@ -555,7 +558,8 @@ int main(int argc, char * const argv[])
}
ret = 0;
- if (!skipallffs || !buffer_check_pattern(writebuf, mtd.min_io_size, 0xff)) {
+ allffs = buffer_check_pattern(writebuf, mtd.min_io_size, 0xff);
+ if (!allffs || !skipallffs) {
/* Write out data */
ret = mtd_write(mtd_desc, &mtd, fd, mtdoffset / mtd.eb_size,
mtdoffset % mtd.eb_size,
@@ -564,6 +568,8 @@ int main(int argc, char * const argv[])
writeoob ? oobbuf : NULL,
writeoob ? mtd.oob_size : 0,
write_mode);
+ if (!ret && allffs)
+ all_ffs_cnt++;
}
if (ret) {
@@ -615,6 +621,11 @@ closeall:
|| (writebuf < filebuf + filebuf_len))
sys_errmsg_die("Data was only partially written due to error");
+ if (all_ffs_cnt) {
+ fprintf(stderr, "Written %zu blocks containing only 0xff bytes\n", all_ffs_cnt);
+ fprintf(stderr, "Those block may be incorrectly treated as empty!\n");
+ }
+
/* Return happy */
return EXIT_SUCCESS;
}