summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ubi-utils/src/nand2bin.c157
1 files changed, 136 insertions, 21 deletions
diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c
index 735fc8b..8db4e77 100644
--- a/ubi-utils/src/nand2bin.c
+++ b/ubi-utils/src/nand2bin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) International Business Machines Corp., 2006, 2007
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,8 @@
* 1.2 Removed argp because we want to use uClibc.
* 1.3 Minor cleanup
* 1.4 Fixed OOB output file
+ * 1.5 Added verbose output and option to set blocksize.
+ * Added split block mode for more convenient analysis.
*/
#include <config.h>
@@ -41,7 +43,7 @@
#include "config.h"
#include "nandecc.h"
-#define PROGRAM_VERSION "1.4"
+#define PROGRAM_VERSION "1.5"
#define MAXPATH 1024
#define MIN(x,y) ((x)<(y)?(x):(y))
@@ -50,6 +52,9 @@ struct args {
const char *oob_file;
const char *output_file;
size_t pagesize;
+ size_t blocksize;
+ int split_blocks;
+ size_t in_len; /* size of input file */
/* special stuff needed to get additional arguments */
char *arg1;
@@ -60,6 +65,9 @@ static struct args myargs = {
.output_file = "data.bin",
.oob_file = "oob.bin",
.pagesize = 2048,
+ .blocksize = 128 * 1024,
+ .in_len = 0,
+ .split_blocks = 0,
.arg1 = NULL,
.options = NULL,
};
@@ -71,6 +79,9 @@ static const char *optionsstr =
" -o, --output=<output> Data output file\n"
" -O, --oob=<oob> OOB output file\n"
" -p, --pagesize=<pagesize> NAND pagesize\n"
+" -b, --blocksize=<blocksize> NAND blocksize\n"
+" -s, --split-blocks generate binaries for each block\n"
+" -v, --verbose verbose output\n"
" -?, --help Give this help list\n"
" --usage Give a short usage message\n";
@@ -79,10 +90,15 @@ static const char *usage =
" [--output=<output>] [--oob=<oob>] [--pagesize=<pagesize>] [--help]\n"
" [--usage] input.mif\n";
+static int verbose = 0;
+
struct option long_options[] = {
{ .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
{ .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' },
{ .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' },
+ { .name = "split-blocks", .has_arg = 0, .flag = NULL, .val = 's' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
{ .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
{ .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
{ NULL, 0, NULL, 0}
@@ -127,7 +143,7 @@ parse_opt(int argc, char **argv, struct args *args)
while (1) {
int key;
- key = getopt_long(argc, argv, "o:O:p:?", long_options, NULL);
+ key = getopt_long(argc, argv, "b:o:O:p:sv?", long_options, NULL);
if (key == -1)
break;
@@ -136,6 +152,18 @@ parse_opt(int argc, char **argv, struct args *args)
args->pagesize = str_to_num(optarg);
break;
+ case 'b': /* --blocksize<blocksize> */
+ args->blocksize = str_to_num(optarg);
+ break;
+
+ case 'v': /* --verbose */
+ verbose++;
+ break;
+
+ case 's': /* --split-blocks */
+ args->split_blocks = 1;
+ break;
+
case 'o': /* --output=<output.bin> */
args->output_file = optarg;
break;
@@ -216,15 +244,24 @@ process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize)
return 0;
}
-static int decompose_image(FILE *in_fp, FILE *bin_fp, FILE *oob_fp,
- size_t pagesize)
+static int bad_marker_offs_in_oob(int pagesize)
+{
+ switch (pagesize) {
+ case 2048: return 0;
+ case 512: return 5;
+ }
+ return -EINVAL;
+}
+
+static int decompose_image(struct args *args, FILE *in_fp,
+ FILE *bin_fp, FILE *oob_fp)
{
int read, rc, page = 0;
- size_t oobsize = calc_oobsize(pagesize);
- uint8_t *buf = malloc(pagesize);
+ size_t oobsize = calc_oobsize(args->pagesize);
+ uint8_t *buf = malloc(args->pagesize);
uint8_t *oob = malloc(oobsize);
uint8_t *calc_oob = malloc(oobsize);
- uint8_t *calc_buf = malloc(pagesize);
+ uint8_t *calc_buf = malloc(args->pagesize);
if (!buf)
exit(EXIT_FAILURE);
@@ -236,12 +273,15 @@ static int decompose_image(FILE *in_fp, FILE *bin_fp, FILE *oob_fp,
exit(EXIT_FAILURE);
while (!feof(in_fp)) {
- read = fread(buf, 1, pagesize, in_fp);
+ read = fread(buf, 1, args->pagesize, in_fp);
if (ferror(in_fp)) {
fprintf(stderr, "I/O Error.");
exit(EXIT_FAILURE);
}
- rc = fwrite(buf, 1, pagesize, bin_fp);
+ if (read != (ssize_t)args->pagesize)
+ break;
+
+ rc = fwrite(buf, 1, args->pagesize, bin_fp);
if (ferror(bin_fp)) {
fprintf(stderr, "I/O Error.");
exit(EXIT_FAILURE);
@@ -256,13 +296,13 @@ static int decompose_image(FILE *in_fp, FILE *bin_fp, FILE *oob_fp,
fprintf(stderr, "I/O Error.");
exit(EXIT_FAILURE);
}
- process_page(buf, calc_oob, pagesize);
- memcpy(calc_buf, buf, pagesize);
+ process_page(buf, calc_oob, args->pagesize);
+ memcpy(calc_buf, buf, args->pagesize);
rc = nand_correct_data(calc_buf, oob);
- if ((rc != -1) || (memcmp(buf, calc_buf, pagesize) != 0)) {
- fprintf(stdout, "Page %d: data does not match!\n",
+ if ((rc != -1) || (memcmp(buf, calc_buf, args->pagesize) != 0)) {
+ fprintf(stdout, "possible ECC error at page %d\n",
page);
}
page++;
@@ -274,10 +314,74 @@ static int decompose_image(FILE *in_fp, FILE *bin_fp, FILE *oob_fp,
return 0;
}
+static int split_blocks(struct args *args, FILE *in_fp)
+{
+ uint8_t *buf;
+ size_t oobsize = calc_oobsize(args->pagesize);
+ int pages_per_block = args->blocksize / args->pagesize;
+ int block_len = pages_per_block * (args->pagesize + oobsize);
+ int blocks = args->in_len / block_len;
+ char bname[256] = { 0, };
+ int badpos = bad_marker_offs_in_oob(args->pagesize);
+ int bad_blocks = 0, i, bad_block = 0;
+ ssize_t rc;
+ FILE *b;
+
+ buf = malloc(block_len);
+ if (!buf) {
+ perror("Not enough memory");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < blocks; i++) {
+ rc = fread(buf, 1, block_len, in_fp);
+ if (rc != block_len) {
+ fprintf(stderr, "cannot read enough data!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* do block analysis */
+ bad_block = 0;
+ if ((buf[args->pagesize + badpos] != 0xff) ||
+ (buf[2 * args->pagesize + oobsize + badpos] != 0xff)) {
+ bad_blocks++;
+ bad_block = 1;
+ }
+ if ((verbose && bad_block) || (verbose > 1)) {
+ printf("-- (block %d oob of page 0 and 1)\n", i);
+ hexdump(stdout, buf + args->pagesize, oobsize);
+ printf("--\n");
+ hexdump(stdout, buf + 2 * args->pagesize +
+ oobsize, oobsize);
+ }
+
+ /* write complete block out */
+ snprintf(bname, sizeof(bname) - 1, "%s.%d", args->arg1, i);
+ b = fopen(bname, "w+");
+ if (!b) {
+ perror("Cannot open file");
+ exit(EXIT_FAILURE);
+ }
+ rc = fwrite(buf, 1, block_len, b);
+ if (rc != block_len) {
+ fprintf(stderr, "could not write all data!\n");
+ exit(EXIT_FAILURE);
+ }
+ fclose(b);
+ }
+
+ free(buf);
+ if (bad_blocks || verbose)
+ fprintf(stderr, "%d blocks, %d bad blocks\n",
+ blocks, bad_blocks);
+ return 0;
+}
+
int
main(int argc, char *argv[])
{
- FILE *in, *bin, *oob;
+ FILE *in, *bin = NULL, *oob = NULL;
+ struct stat file_info;
parse_opt(argc, argv, &myargs);
@@ -286,11 +390,23 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ if (lstat(myargs.arg1, &file_info) != 0) {
+ perror("Cannot fetch file size from input file.\n");
+ exit(EXIT_FAILURE);
+ }
+ myargs.in_len = file_info.st_size;
+
in = fopen(myargs.arg1, "r");
if (!in) {
perror("Cannot open file");
exit(EXIT_FAILURE);
}
+
+ if (myargs.split_blocks) {
+ split_blocks(&myargs, in);
+ goto out;
+ }
+
bin = fopen(myargs.output_file, "w+");
if (!bin) {
perror("Cannot open file");
@@ -301,12 +417,11 @@ main(int argc, char *argv[])
perror("Cannot open file");
exit(EXIT_FAILURE);
}
+ decompose_image(&myargs, in, bin, oob);
- decompose_image(in, bin, oob, myargs.pagesize);
-
- fclose(in);
- fclose(bin);
- fclose(oob);
-
+ out:
+ if (in) fclose(in);
+ if (bin) fclose(bin);
+ if (oob) fclose(oob);
exit(EXIT_SUCCESS);
}