diff options
Diffstat (limited to 'ubi-utils/sort-me-out/bin2nand.c')
-rw-r--r-- | ubi-utils/sort-me-out/bin2nand.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/ubi-utils/sort-me-out/bin2nand.c b/ubi-utils/sort-me-out/bin2nand.c new file mode 100644 index 0000000..83f50cc --- /dev/null +++ b/ubi-utils/sort-me-out/bin2nand.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) International Business Machines Corp., 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Oliver Lohmann + */ + +/* + * Create a flashable NAND image from a binary image + * + * History: + * 1.0 Initial release (tglx) + * 1.1 Understands hex and dec input parameters (tglx) + * 1.2 Generates separated OOB data, if needed. (oloh) + * 1.3 Padds data/oob to a given size. (oloh) + * 1.4 Removed argp because we want to use uClibc. + * 1.5 Minor cleanup + * 1.6 Written variable not initialized (-j did not work) (haver) + * 1.7 Made NAND ECC layout configurable (haver) + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <getopt.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +#include "error.h" +#include "config.h" +#include "nandecc.h" +#include "ecclayouts.h" + +#define PROGRAM_VERSION "1.7" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define CHECK_ENDP(option, endp) do { \ + if (*endp) { \ + fprintf(stderr, \ + "Parse error option \'%s\'. " \ + "No correct numeric value.\n" \ + , option); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +typedef enum action_t { + ACT_NORMAL = 0x00000001, +} action_t; + +#define PAGESIZE 2048 +#define PADDING 0 /* 0 means, do not adjust anything */ +#define BUFSIZE 4096 + +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" + "bin2nand - a tool for adding OOB information to a " + "binary input file.\n"; + +static const char *optionsstr = +" -c, --copyright Print copyright informatoin.\n" +" -j, --padding=<num> Padding in Byte/Mi/ki. Default = no padding\n" +" -l, --ecc-placement=<MTD,IBM> OOB placement scheme (default is IBM).\n" +" -p, --pagesize=<num> Pagesize in Byte/Mi/ki. Default = 2048\n" +" -o, --output=<fname> Output filename. Interleaved Data/OOB if\n" +" output-oob not specified.\n" +" -q, --output-oob=<fname> Write OOB data in separate file.\n" +" -?, --help Give this help list\n" +" --usage Give a short usage message\n" +" -V, --version Print program version\n"; + +static const char *usage = +"Usage: bin2nand [-c?V] [-j <num>] [-p <num>] [-o <fname>] [-q <fname>]\n" +" [--copyright] [--padding=<num>] [--pagesize=<num>]\n" +" [--output=<fname>] [--output-oob=<fname>] [--help] [--usage]\n" +" [--version]\n"; + +struct option long_options[] = { + { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, + { .name = "padding", .has_arg = 1, .flag = NULL, .val = 'j' }, + { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, + { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, + { .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' }, + { .name = "ecc-layout", .has_arg = 1, .flag = NULL, .val = 'l' }, + { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, + { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, + { NULL, 0, NULL, 0} +}; + +#define __unused __attribute__((unused)) +static const char copyright [] __unused = "Copyright IBM Corp. 2007"; + +struct args { + action_t action; + + size_t pagesize; + size_t oobsize; + size_t padding; + + FILE* fp_in; + const char *file_out_data; /* Either: Data and OOB interleaved + or plain data */ + const char *file_out_oob; /* OOB Data only. */ + struct nand_ecclayout *nand_oob; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +}; + + +static int ustrtoull(const char *cp, char **endp, unsigned int base) +{ + unsigned long long res = strtoull(cp, endp, base); + + switch (**endp) { + case 'G': + res *= 1024; + case 'M': + res *= 1024; + case 'k': + case 'K': + res *= 1024; + /* "Ki", "ki", "Mi" or "Gi" are to be used. */ + if ((*endp)[1] == 'i') + (*endp) += 2; + } + return res; +} + +static int +parse_opt(int argc, char **argv, struct args *args) +{ + const char *ecc_layout = NULL; + unsigned int i, oob_idx = 0; + char* endp; + + while (1) { + int key; + + key = getopt_long(argc, argv, "cj:l:p:o:q:?V", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'p': /* pagesize */ + args->pagesize = (size_t) + ustrtoull(optarg, &endp, 0); + CHECK_ENDP("p", endp); + break; + case 'j': /* padding */ + args->padding = (size_t) + ustrtoull(optarg, &endp, 0); + CHECK_ENDP("j", endp); + break; + case 'o': /* output */ + args->file_out_data = optarg; + break; + case 'q': /* output oob */ + args->file_out_oob = optarg; + break; + case 'l': /* --ecc-layout=<...> */ + ecc_layout = optarg; + break; + case '?': /* help */ + printf("%s%s", doc, optionsstr); + exit(0); + break; + case 'V': + printf("%s\n", PROGRAM_VERSION); + exit(0); + break; + case 'c': + printf("%s\n", copyright); + exit(0); + default: + printf("%s", usage); + exit(-1); + } + } + + if (optind < argc) { + args->fp_in = fopen(argv[optind++], "rb"); + if ((args->fp_in) == NULL) { + err_quit("Cannot open file %s for input\n", + argv[optind++]); + } + } + + switch (args->pagesize) { + case 512: args->oobsize = 16; oob_idx = 0; break; + case 2048: args->oobsize = 64; oob_idx = 1; break; + default: + err_msg("Unsupported page size: %d\n", args->pagesize); + return -EINVAL; + } + + /* Figure out correct oob layout if it differs from default */ + if (ecc_layout) { + for (i = 0; i < ARRAY_SIZE(oob_placement); i++) + if (strcmp(ecc_layout, oob_placement[i].name) == 0) + args->nand_oob = + oob_placement[i].nand_oob[oob_idx]; + } + return 0; +} + +static int +process_page(struct args *args, uint8_t *buf, FILE *fp_data, FILE *fp_oob, + size_t *written) +{ + int eccpoi; + size_t i; + uint8_t oobbuf[64]; + uint8_t ecc_code[3] = { 0, }; /* temp */ + + /* Calculate ECC for each subpage of 256 bytes */ + memset(oobbuf, 0xff, sizeof(oobbuf)); + for (eccpoi = 0, i = 0; i < args->pagesize; i += 256, eccpoi += 3) { + int j; + nand_calculate_ecc(&buf[i], ecc_code); + for (j = 0; j < 3; j++) + oobbuf[args->nand_oob->eccpos[eccpoi + j]] = ecc_code[j]; + } + + /* write data */ + *written += fwrite(buf, 1, args->pagesize, fp_data); + + /* either separate oob or interleave with data */ + if (fp_oob) { + i = fwrite(oobbuf, 1, args->oobsize, fp_oob); + if (ferror(fp_oob)) { + err_msg("IO error\n"); + return -EIO; + } + } + else { + i = fwrite(oobbuf, 1, args->oobsize, fp_data); + if (ferror(fp_data)) { + err_msg("IO error\n"); + return -EIO; + } + } + + return 0; +} + +int main (int argc, char** argv) +{ + int rc = -1; + int res = 0; + size_t written = 0, read; + struct args args = { + .action = ACT_NORMAL, + .pagesize = PAGESIZE, + .padding = PADDING, + .fp_in = NULL, + .file_out_data = NULL, + .file_out_oob = NULL, + .nand_oob = &ibm_nand_oob_64, + }; + + FILE* fp_out_data = stdout; + FILE* fp_out_oob = NULL; + + parse_opt(argc, argv, &args); + + uint8_t* buf = calloc(1, BUFSIZE); + if (!buf) { + err_quit("Cannot allocate page buffer.\n"); + } + + if (!args.fp_in) { + err_msg("No input image specified!\n"); + goto err; + } + + if (args.file_out_data) { + fp_out_data = fopen(args.file_out_data, "wb"); + if (fp_out_data == NULL) { + err_sys("Cannot open file %s for output\n", + args.file_out_data); + goto err; + } + } + + if (args.file_out_oob) { + fp_out_oob = fopen(args.file_out_oob, "wb"); + if (fp_out_oob == NULL) { + err_sys("Cannot open file %s for output\n", + args.file_out_oob); + goto err; + } + } + + + while(1) { + read = fread(buf, 1, args.pagesize, args.fp_in); + if (feof(args.fp_in) && read == 0) + break; + + if (read < args.pagesize) { + err_msg("Image not page aligned\n"); + goto err; + } + + if (ferror(args.fp_in)) { + err_msg("Read error\n"); + goto err; + } + + res = process_page(&args, buf, fp_out_data, fp_out_oob, + &written); + if (res != 0) + goto err; + } + + while (written < args.padding) { + memset(buf, 0xff, args.pagesize); + res = process_page(&args, buf, fp_out_data, fp_out_oob, + &written); + if (res != 0) + goto err; + } + + rc = 0; +err: + free(buf); + + if (args.fp_in) + fclose(args.fp_in); + + if (fp_out_oob) + fclose(fp_out_oob); + + if (fp_out_data && fp_out_data != stdout) + fclose(fp_out_data); + + if (rc != 0) { + err_msg("Error during conversion. rc: %d\n", rc); + if (args.file_out_data) + remove(args.file_out_data); + if (args.file_out_oob) + remove(args.file_out_oob); + } + return rc; +} |