diff options
Diffstat (limited to 'misc-utils')
-rw-r--r-- | misc-utils/Makemodule.am | 48 | ||||
-rw-r--r-- | misc-utils/fectest.c | 4 | ||||
-rw-r--r-- | misc-utils/flash_erase.c | 130 | ||||
-rw-r--r-- | misc-utils/flash_otp_dump.c | 2 | ||||
-rw-r--r-- | misc-utils/flash_otp_erase.c | 64 | ||||
-rw-r--r-- | misc-utils/flash_unlock.c | 9 | ||||
-rw-r--r-- | misc-utils/flashcp.c | 367 | ||||
-rw-r--r-- | misc-utils/lsmtd.8 | 2 | ||||
-rw-r--r-- | misc-utils/lsmtd.c | 6 | ||||
-rw-r--r-- | misc-utils/lsmtd_scan.c | 2 | ||||
-rw-r--r-- | misc-utils/mtd_debug.c | 7 | ||||
-rw-r--r-- | misc-utils/mtdpart.c | 9 |
12 files changed, 464 insertions, 186 deletions
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am index 2289252..1ce1a68 100644 --- a/misc-utils/Makemodule.am +++ b/misc-utils/Makemodule.am @@ -1,24 +1,34 @@ -ftl_format_SOURCES = misc-utils/ftl_format.c +ftl_format_SOURCES = misc-utils/ftl_format.c include/mtd_swab.h +ftl_format_SOURCES += include/mtd/ftl-user.h doc_loadbios_SOURCES = misc-utils/doc_loadbios.c -ftl_check_SOURCES = misc-utils/ftl_check.c +ftl_check_SOURCES = misc-utils/ftl_check.c include/mtd_swab.h +ftl_check_SOURCES += include/mtd/ftl-user.h mtd_debug_SOURCES = misc-utils/mtd_debug.c +mtd_debug_LDADD = libmtd.a mtdpart_SOURCES = misc-utils/mtdpart.c +mtdpart_LDADD = libmtd.a -docfdisk_SOURCES = misc-utils/docfdisk.c +docfdisk_SOURCES = misc-utils/docfdisk.c include/mtd_swab.h +docfdisk_SOURCES += include/mtd/inftl-user.h include/mtd/ftl-user.h -serve_image_SOURCES = misc-utils/serve_image.c +serve_image_SOURCES = misc-utils/serve_image.c misc-utils/mcast_image.h serve_image_LDADD = libmtd.a -recv_image_SOURCES = misc-utils/recv_image.c +recv_image_SOURCES = misc-utils/recv_image.c misc-utils/mcast_image.h recv_image_LDADD = libmtd.a +fectest_SOURCES = misc-utils/fectest.c misc-utils/mcast_image.h +fectest_LDADD = libmtd.a + flash_lock_SOURCES = misc-utils/flash_lock.c +flash_lock_LDADD = libmtd.a flash_unlock_SOURCES = misc-utils/flash_unlock.c +flash_unlock_LDADD = libmtd.a flash_otp_info_SOURCES = misc-utils/flash_otp_info.c @@ -26,42 +36,34 @@ flash_otp_dump_SOURCES = misc-utils/flash_otp_dump.c flash_otp_lock_SOURCES = misc-utils/flash_otp_lock.c +flash_otp_erase_SOURCES = misc-utils/flash_otp_erase.c + flash_otp_write_SOURCES = misc-utils/flash_otp_write.c flashcp_SOURCES = misc-utils/flashcp.c +flashcp_LDADD = libmtd.a flash_erase_SOURCES = misc-utils/flash_erase.c flash_erase_LDADD = libmtd.a -MISC_BINS = \ +sbin_PROGRAMS += \ ftl_format doc_loadbios ftl_check mtd_debug docfdisk \ - serve_image recv_image flash_erase flash_lock \ + serve_image recv_image fectest flash_erase flash_lock \ flash_unlock flash_otp_info flash_otp_dump flash_otp_lock \ - flash_otp_write flashcp mtdpart + flash_otp_erase flash_otp_write flashcp mtdpart MISC_SH = \ misc-utils/flash_eraseall -MISC_EXTRA = \ - misc-utils/MAKEDEV - -MISC_HEADER = \ - misc-utils/mcast_image.h \ - misc-utils/lsmtd.h - -MISC_MAN = - if BUILD_LSMTD -lsmtd_SOURCES = misc-utils/lsmtd.c misc-utils/lsmtd_scan.c +lsmtd_SOURCES = misc-utils/lsmtd.c misc-utils/lsmtd_scan.c misc-utils/lsmtd.h lsmtd_LDADD = libmtd.a libubi.a lsmtd_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/misc-utils -MISC_BINS += lsmtd -MISC_MAN += misc-utils/lsmtd.8 +sbin_PROGRAMS += lsmtd +dist_man8_MANS += misc-utils/lsmtd.8 endif -EXTRA_DIST += $(MISC_HEADER) $(MISC_EXTRA) $(MISC_SH) +EXTRA_DIST += misc-utils/MAKEDEV $(MISC_SH) -dist_man8_MANS += $(MISC_MAN) -sbin_PROGRAMS += $(MISC_BINS) sbin_SCRIPTS += $(MISC_SH) diff --git a/misc-utils/fectest.c b/misc-utils/fectest.c index fcba513..f560f2b 100644 --- a/misc-utils/fectest.c +++ b/misc-utils/fectest.c @@ -21,7 +21,7 @@ int main(void) unsigned char buf[NR_PKTS * PKT_SIZE]; unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE]; struct fec_parms *fec; - unsigned char *srcs[NR_PKTS]; + unsigned char *srcs[NR_PKTS + DROPS]; unsigned char *pkt[NR_PKTS + DROPS]; int pktnr[NR_PKTS + DROPS]; struct timeval then, now; @@ -87,6 +87,6 @@ int main(void) exit(1); } - printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec); + printf("Decoded in %ld.%06lds\n", (long)now.tv_sec, (long)now.tv_usec); return 0; } diff --git a/misc-utils/flash_erase.c b/misc-utils/flash_erase.c index a7fc6a6..c6f6f66 100644 --- a/misc-utils/flash_erase.c +++ b/misc-utils/flash_erase.c @@ -2,6 +2,7 @@ Copyright (C) 2000 Arcom Control System Ltd Copyright (C) 2010 Mike Frysinger <vapier@gentoo.org> + Copyright 2021 NXP 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 @@ -50,11 +51,10 @@ static int unlock; /* unlock sectors before erasing */ static struct jffs2_unknown_node cleanmarker; int target_endian = __BYTE_ORDER; -static void show_progress(struct mtd_dev_info *mtd, off_t start, int eb, - int eb_start, int eb_cnt) +static void show_progress(off_t start, int eb, int eb_start, int eb_cnt, int step) { bareverbose(!quiet, "\rErasing %d Kibyte @ %llx -- %2i %% complete ", - mtd->eb_size / 1024, (unsigned long long)start, ((eb - eb_start) * 100) / eb_cnt); + step / 1024, (unsigned long long)start, ((eb - eb_start) * 100) / eb_cnt); fflush(stdout); } @@ -64,13 +64,16 @@ static void display_help (void) "Erase blocks of the specified MTD device.\n" "Specify a count of 0 to erase to end of device.\n" "\n" - " -j, --jffs2 format the device for jffs2\n" - " -N, --noskipbad don't skip bad blocks\n" - " -u, --unlock unlock sectors before erasing\n" - " -q, --quiet do not display progress messages\n" - " --silent same as --quiet\n" - " --help display this help and exit\n" - " --version output version information and exit\n", + " -j, --jffs2 format the device for jffs2\n" + " -c, --cleanmarker=SIZE size of jffs2 cleanmarker (default 12)\n" + " -N, --noskipbad don't skip bad blocks\n" + " -u, --unlock unlock sectors before erasing\n" + " -q, --quiet do not display progress messages\n" + " --silent same as --quiet\n" + " --help display this help and exit\n" + " --version output version information and exit\n", + "\n" + " MTD_DEVICE MTD device node or 'mtd:<name>'\n" PROGRAM_NAME); } @@ -88,14 +91,35 @@ static void display_version (void) PROGRAM_NAME); } +static void clear_marker(libmtd_t mtd_desc, struct mtd_dev_info *mtd, int fd, + unsigned int eb, int cmlen, bool isNAND) +{ + off_t offset = (off_t)eb * mtd->eb_size; + + /* write cleanmarker */ + if (isNAND) { + if (mtd_write(mtd_desc, mtd, fd, eb, 0, NULL, 0, &cleanmarker, cmlen, + MTD_OPS_AUTO_OOB) != 0) { + sys_errmsg("%s: MTD writeoob failure", mtd_device); + return; + } + } else { + if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) { + sys_errmsg("%s: MTD write failure", mtd_device); + return; + } + } + verbose(!quiet, "%llx : Cleanmarker Updated.", (unsigned long long)offset); +} + int main(int argc, char *argv[]) { libmtd_t mtd_desc; struct mtd_dev_info mtd; - int fd, cmlen = 8; + int fd, cmlen = 8, cmsize = sizeof(cleanmarker); unsigned long long start; unsigned int eb, eb_start, eb_cnt; - bool isNAND; + bool isNAND, erase_chip = false; int error = 0; off_t offset = 0; @@ -104,11 +128,12 @@ int main(int argc, char *argv[]) */ for (;;) { int option_index = 0; - static const char *short_options = "jNquVh"; + static const char *short_options = "jc:NquVh"; static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"jffs2", no_argument, 0, 'j'}, + {"cleanmarker", required_argument, 0, 'c'}, {"noskipbad", no_argument, 0, 'N'}, {"quiet", no_argument, 0, 'q'}, {"silent", no_argument, 0, 'q'}, @@ -132,6 +157,9 @@ int main(int argc, char *argv[]) case 'j': jffs2 = 1; break; + case 'c': + cmsize = atoi(optarg); + break; case 'N': noskipbad = 1; break; @@ -148,7 +176,9 @@ int main(int argc, char *argv[]) } switch (argc - optind) { case 3: - mtd_device = argv[optind]; + mtd_device = mtd_find_dev_node(argv[optind]); + if (!mtd_device) + return errmsg("Can't find MTD device %s", argv[optind]); start = simple_strtoull(argv[optind + 1], &error); eb_cnt = simple_strtoul(argv[optind + 2], &error); break; @@ -182,6 +212,10 @@ int main(int argc, char *argv[]) if (jffs2 && mtd.type == MTD_MLCNANDFLASH) return errmsg("JFFS2 cannot support MLC NAND."); + if (jffs2 && cmsize < sizeof(cleanmarker)) + return errmsg("cleanmarker size must be >= 12"); + if (jffs2 && cmsize >= mtd.eb_size) + return errmsg("cleanmarker size must be < eraseblock size"); eb_start = start / mtd.eb_size; @@ -191,7 +225,7 @@ int main(int argc, char *argv[]) cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); if (!isNAND) { - cleanmarker.totlen = cpu_to_je32(sizeof(cleanmarker)); + cleanmarker.totlen = cpu_to_je32(cmsize); } else { cleanmarker.totlen = cpu_to_je32(8); cmlen = min(mtd.oobavail, 8); @@ -205,6 +239,47 @@ int main(int argc, char *argv[]) if (eb_cnt == 0) eb_cnt = (mtd.size / mtd.eb_size) - eb_start; + if (eb_start == 0 && mtd.size == eb_cnt * mtd.eb_size) + erase_chip = true; + + /* If MTD device may have bad eraseblocks, + * erase one by one each sector + */ + if (noskipbad && mtd.bb_allowed) + erase_chip = false; + + if (erase_chip) { + show_progress(0, eb_start, eb_start, eb_cnt, mtd.size); + + if (unlock) { + if (mtd_unlock_multi(&mtd, fd, eb_start, eb_cnt) != 0) { + sys_errmsg("%s: MTD unlock entire chip failure." \ + "Trying one by one each sector.", + mtd_device); + goto erase_each_sector; + } + } + + if (mtd_erase_multi(mtd_desc, &mtd, fd, eb_start, eb_cnt) != 0) { + sys_errmsg("%s: MTD Erase entire chip failure" \ + "Trying one by one each sector.", + mtd_device); + goto erase_each_sector; + } + + show_progress(0, eb_start + eb_cnt, eb_start, + eb_cnt, mtd.size); + + if (!jffs2) + goto out; + + /* write cleanmarker */ + for (eb = eb_start; eb < eb_start + eb_cnt; eb++) + clear_marker(mtd_desc, &mtd, fd, eb, cmlen, isNAND); + goto out; + } + +erase_each_sector: for (eb = eb_start; eb < eb_start + eb_cnt; eb++) { offset = (off_t)eb * mtd.eb_size; @@ -223,7 +298,7 @@ int main(int argc, char *argv[]) } } - show_progress(&mtd, offset, eb, eb_start, eb_cnt); + show_progress(offset, eb, eb_start, eb_cnt, mtd.eb_size); if (unlock) { if (mtd_unlock(&mtd, fd, eb) != 0) { @@ -237,26 +312,11 @@ int main(int argc, char *argv[]) continue; } - /* format for JFFS2 ? */ - if (!jffs2) - continue; - - /* write cleanmarker */ - if (isNAND) { - if (mtd_write(mtd_desc, &mtd, fd, eb, 0, NULL, 0, &cleanmarker, cmlen, - MTD_OPS_AUTO_OOB) != 0) { - sys_errmsg("%s: MTD writeoob failure", mtd_device); - continue; - } - } else { - if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) { - sys_errmsg("%s: MTD write failure", mtd_device); - continue; - } - } - verbose(!quiet, " Cleanmarker Updated."); + if (jffs2) + clear_marker(mtd_desc, &mtd, fd, eb, cmlen, isNAND); } - show_progress(&mtd, offset, eb, eb_start, eb_cnt); + show_progress(offset, eb, eb_start, eb_cnt, mtd.eb_size); +out: bareverbose(!quiet, "\n"); return 0; diff --git a/misc-utils/flash_otp_dump.c b/misc-utils/flash_otp_dump.c index f1e1782..324d856 100644 --- a/misc-utils/flash_otp_dump.c +++ b/misc-utils/flash_otp_dump.c @@ -20,7 +20,7 @@ int main(int argc,char *argv[]) int offset = 0; unsigned char buf[16]; - if (argc <= 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) { + if (argc < 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) { fprintf(stderr,"Usage: %s [ -f | -u ] <device> [<offset>]\n", PROGRAM_NAME); return EINVAL; } diff --git a/misc-utils/flash_otp_erase.c b/misc-utils/flash_otp_erase.c new file mode 100644 index 0000000..771e230 --- /dev/null +++ b/misc-utils/flash_otp_erase.c @@ -0,0 +1,64 @@ +/* + * flash_otp_erase.c -- erase area of One-Time-Program data + */ + +#define PROGRAM_NAME "flash_otp_erase" + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/ioctl.h> + +#include <mtd/mtd-user.h> +#include "common.h" + +int main(int argc,char *argv[]) +{ + int fd, val, ret, offset, size; + struct otp_info info; + char *p; + + if (argc != 5 || strcmp(argv[1], "-u")) { + fprintf(stderr, "Usage: %s -u <device> <offset> <size>\n", PROGRAM_NAME); + fprintf(stderr, "offset and size must match on OTP region boundaries\n"); + return EINVAL; + } + + fd = open(argv[2], O_WRONLY); + if (fd < 0) { + perror(argv[2]); + return errno; + } + + val = MTD_OTP_USER; + ret = ioctl(fd, OTPSELECT, &val); + if (ret < 0) { + perror("OTPSELECT"); + return errno; + } + + offset = strtoul(argv[3], &p, 0); + if (argv[3][0] == 0 || *p != 0) { + fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME); + return ERANGE; + } + + size = strtoul(argv[4], &p, 0); + if (argv[4][0] == 0 || *p != 0) { + fprintf(stderr, "%s: bad size value\n", PROGRAM_NAME); + return ERANGE; + } + + info.start = offset; + info.length = size; + ret = ioctl(fd, OTPERASE, &info); + if (ret < 0) { + perror("OTPERASE"); + return errno; + } + + return 0; +} diff --git a/misc-utils/flash_unlock.c b/misc-utils/flash_unlock.c index fbbfa51..fa5decb 100644 --- a/misc-utils/flash_unlock.c +++ b/misc-utils/flash_unlock.c @@ -51,6 +51,8 @@ static NORETURN void usage(int status) " -l --lock Lock a region of flash\n" " -u --unlock Unlock a region of flash\n" "\n" + " <mtd device> MTD device node or 'mtd:<name>'\n" + "\n" "If offset is not specified, it defaults to 0.\n" "If block count is not specified, it defaults to all blocks.\n" "A block count of -1 means all blocks.\n", @@ -125,7 +127,12 @@ static void process_args(int argc, char *argv[]) } /* First non-option argument */ - dev = argv[arg_idx++]; + dev = mtd_find_dev_node(argv[arg_idx]); + if (!dev) { + errmsg("MTD device not found %s", argv[arg_idx]); + usage(EXIT_FAILURE); + } + arg_idx++; /* Second non-option argument */ if (arg_idx < argc) diff --git a/misc-utils/flashcp.c b/misc-utils/flashcp.c index d7b0a59..9c48637 100644 --- a/misc-utils/flashcp.c +++ b/misc-utils/flashcp.c @@ -48,7 +48,7 @@ /* for debugging purposes only */ #ifdef DEBUG #undef DEBUG -#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); } +#define DEBUG(fmt,args...) { fprintf (stderr,"%d: ",__LINE__); fprintf (stderr,fmt,## args); } #else #undef DEBUG #define DEBUG(fmt,args...) @@ -57,36 +57,47 @@ #define KB(x) ((x) / 1024) #define PERCENTAGE(x,total) (((x) * 100) / (total)) -/* size of read/write buffer */ -#define BUFSIZE (10 * 1024) - /* cmd-line flags */ #define FLAG_NONE 0x00 -#define FLAG_VERBOSE 0x01 #define FLAG_HELP 0x02 #define FLAG_FILENAME 0x04 #define FLAG_DEVICE 0x08 #define FLAG_ERASE_ALL 0x10 +#define FLAG_PARTITION 0x20 +#define FLAG_WR_LAST 0x40 /* error levels */ #define LOG_NORMAL 1 #define LOG_ERROR 2 -static void log_printf (int level,const char *fmt, ...) +static NORETURN void log_failure (const char *fmt, ...) { - FILE *fp = level == LOG_NORMAL ? stdout : stderr; va_list ap; va_start (ap,fmt); - vfprintf (fp,fmt,ap); + vfprintf (stderr,fmt,ap); va_end (ap); - fflush (fp); + fflush (stderr); + + exit (EXIT_FAILURE); } -static NORETURN void showusage(bool error) +static int verbose = 0; +static void log_verbose (const char *fmt, ...) { - int level = error ? LOG_ERROR : LOG_NORMAL; + va_list ap; + + if (!verbose) + return; + + va_start (ap,fmt); + vfprintf (stdout,fmt,ap); + va_end (ap); + fflush (stdout); +} - log_printf (level, +static NORETURN void showusage(bool error) +{ + fprintf (error ? stderr : stdout, "\n" "Flash Copy - Written by Abraham van der Merwe <abraham@2d3d.co.za>\n" "\n" @@ -94,12 +105,14 @@ static NORETURN void showusage(bool error) " %1$s -h | --help\n" " %1$s -V | --version\n" "\n" - " -h | --help Show this help message\n" - " -v | --verbose Show progress reports\n" - " -A | --erase-all Erases the whole device regardless of the image size\n" - " -V | --version Show version information and exit\n" - " <filename> File which you want to copy to flash\n" - " <device> Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n" + " -h | --help Show this help message\n" + " -v | --verbose Show progress reports\n" + " -p | --partition Only copy different block from file to device\n" + " -A | --erase-all Erases the whole device regardless of the image size\n" + " -l | --wr-last=bytes Write the first [bytes] last\n" + " -V | --version Show version information and exit\n" + " <filename> File which you want to copy to flash\n" + " <device> Flash device node or 'mtd:<name>' to write to (e.g. /dev/mtd0, /dev/mtd1, mtd:data, etc.)\n" "\n", PROGRAM_NAME); @@ -108,49 +121,85 @@ static NORETURN void showusage(bool error) static int safe_open (const char *pathname,int flags) { + const char *access = "unknown"; int fd; fd = open (pathname,flags); if (fd < 0) { - log_printf (LOG_ERROR,"While trying to open %s",pathname); if (flags & O_RDWR) - log_printf (LOG_ERROR," for read/write access"); + access = "read/write"; else if (flags & O_RDONLY) - log_printf (LOG_ERROR," for read access"); + access = "read"; else if (flags & O_WRONLY) - log_printf (LOG_ERROR," for write access"); - log_printf (LOG_ERROR,": %m\n"); - exit (EXIT_FAILURE); + access = "write"; + + log_failure ("While trying to open %s for %s access: %m\n",pathname,access); } return (fd); } -static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose) +static void safe_read (int fd,const char *filename,void *buf,size_t count) { ssize_t result; result = read (fd,buf,count); if (count != result) { - if (verbose) log_printf (LOG_NORMAL,"\n"); + log_verbose ("\n"); + if (result < 0) + { + log_failure("While reading data from %s: %m\n",filename); + } + log_failure("Short read count returned while reading from %s\n",filename); + } +} + +static void safe_write (int fd,const void *buf,size_t count,size_t written,unsigned long long to_write,const char *device) +{ + ssize_t result; + + /* write to device */ + result = write (fd,buf,count); + if (count != result) + { + log_verbose ("\n"); if (result < 0) { - log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename); - exit (EXIT_FAILURE); + log_failure("While writing data to 0x%.8lx-0x%.8lx on %s: %m\n", + written,written + count,device); } - log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename); - exit (EXIT_FAILURE); + log_failure("Short write count returned while writing to x%.8zx-0x%.8zx on %s: %zu/%llu bytes written to flash\n", + written,written + count,device,written + result,to_write); } } +static off_t safe_lseek (int fd,off_t offset,int whence,const char *filename) +{ + off_t off; + + off = lseek (fd,offset,whence); + if (off < 0) + { + log_failure("While seeking on %s: %m\n",filename); + } + + return off; +} + static void safe_rewind (int fd,const char *filename) { - if (lseek (fd,0L,SEEK_SET) < 0) + safe_lseek(fd,0L,SEEK_SET,filename); +} + +static void safe_memerase (int fd,const char *device,struct erase_info_user *erase) +{ + if (ioctl (fd,MEMERASE,erase) < 0) { - log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename); - exit (EXIT_FAILURE); + log_verbose ("\n"); + log_failure("While erasing blocks 0x%.8x-0x%.8x on %s: %m\n", + (unsigned int) erase->start,(unsigned int) (erase->start + erase->length),device); } } @@ -168,12 +217,13 @@ int main (int argc,char *argv[]) { const char *filename = NULL,*device = NULL; int i,flags = FLAG_NONE; - ssize_t result; size_t size,written; struct mtd_info_user mtd; struct erase_info_user erase; struct stat filestat; - unsigned char src[BUFSIZE],dest[BUFSIZE]; + unsigned char *src,*dest,*wrlast_buf; + unsigned long long wrlast_len = 0; + int error = 0; /********************* * parse cmd-line @@ -181,11 +231,13 @@ int main (int argc,char *argv[]) for (;;) { int option_index = 0; - static const char *short_options = "hvAV"; + static const char *short_options = "hvpAl:V"; static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, + {"partition", no_argument, 0, 'p'}, {"erase-all", no_argument, 0, 'A'}, + {"wr-last", required_argument, 0, 'l'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; @@ -202,13 +254,21 @@ int main (int argc,char *argv[]) DEBUG("Got FLAG_HELP\n"); break; case 'v': - flags |= FLAG_VERBOSE; + verbose = 1; DEBUG("Got FLAG_VERBOSE\n"); break; + case 'p': + flags |= FLAG_PARTITION; + DEBUG("Got FLAG_PARTITION"); + break; case 'A': flags |= FLAG_ERASE_ALL; DEBUG("Got FLAG_ERASE_ALL\n"); break; + case 'l': + flags |= FLAG_WR_LAST; + wrlast_len = simple_strtoll(optarg, &error); + break; case 'V': common_print_version(); exit(EXIT_SUCCESS); @@ -224,13 +284,23 @@ int main (int argc,char *argv[]) DEBUG("Got filename: %s\n",filename); flags |= FLAG_DEVICE; - device = argv[optind+1]; + device = mtd_find_dev_node(argv[optind+1]); + if (!device) + log_failure("Failed to find device %s\n", argv[optind+1]); + DEBUG("Got device: %s\n",device); } if (flags & FLAG_HELP || device == NULL) showusage(flags != FLAG_HELP); + if (flags & FLAG_PARTITION && flags & FLAG_ERASE_ALL) + log_failure("Option --partition does not support --erase-all\n"); + + if (flags & FLAG_PARTITION && flags & FLAG_WR_LAST) { + log_failure("Option --partition does not support --wr-last\n"); + } + atexit (cleanup); /* get some info about the flash device */ @@ -238,23 +308,30 @@ int main (int argc,char *argv[]) if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0) { DEBUG("ioctl(): %m\n"); - log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n"); - exit (EXIT_FAILURE); + log_failure("This doesn't seem to be a valid MTD flash device!\n"); } /* get some info about the file we want to copy */ fil_fd = safe_open (filename,O_RDONLY); if (fstat (fil_fd,&filestat) < 0) - { - log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename); - exit (EXIT_FAILURE); - } + log_failure("While trying to get the file status of %s: %m\n",filename); /* does it fit into the device/partition? */ if (filestat.st_size > mtd.size) + log_failure("%s won't fit into %s!\n",filename,device); + + src = malloc(mtd.erasesize); + if (!src) + log_failure("Malloc failed"); + + dest = malloc(mtd.erasesize); + if (!dest) + log_failure("Malloc failed"); + + /* diff block flashcp */ + if (flags & FLAG_PARTITION) { - log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device); - exit (EXIT_FAILURE); + goto DIFF_BLOCKS; } /***************************************************** @@ -275,37 +352,24 @@ int main (int argc,char *argv[]) erase.length *= mtd.erasesize; } - if (flags & FLAG_VERBOSE) + if (verbose) { /* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */ int blocks = erase.length / mtd.erasesize; erase.length = mtd.erasesize; - log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks); + log_verbose ("Erasing blocks: 0/%d (0%%)",blocks); for (i = 1; i <= blocks; i++) { - log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks)); - if (ioctl (dev_fd,MEMERASE,&erase) < 0) - { - log_printf (LOG_NORMAL,"\n"); - log_printf (LOG_ERROR, - "While erasing blocks 0x%.8x-0x%.8x on %s: %m\n", - (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); - exit (EXIT_FAILURE); - } + log_verbose ("\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks)); + safe_memerase(dev_fd,device,&erase); erase.start += mtd.erasesize; } - log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks); + log_verbose ("\rErasing blocks: %d/%d (100%%)\n",blocks,blocks); } else { /* if not, erase the whole chunk in one shot */ - if (ioctl (dev_fd,MEMERASE,&erase) < 0) - { - log_printf (LOG_ERROR, - "While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n", - (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); - exit (EXIT_FAILURE); - } + safe_memerase(dev_fd,device,&erase); } DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size); @@ -313,50 +377,68 @@ int main (int argc,char *argv[]) * write the entire file to flash * **********************************/ - if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size)); size = filestat.st_size; - i = BUFSIZE; + i = mtd.erasesize; written = 0; + + if ((flags & FLAG_WR_LAST) && (filestat.st_size > wrlast_len)) { + if (wrlast_len > mtd.erasesize) + log_failure("The wrlast (%lluk) is larger than erasesize (%lluk)\n", KB (wrlast_len), KB ((unsigned long long)mtd.erasesize)); + + if (size < mtd.erasesize) i = size; + + log_verbose ("Reading %lluk of data to write last.\n", KB ((unsigned long long)wrlast_len)); + wrlast_buf = malloc(wrlast_len); + if (!wrlast_buf) + log_failure("Malloc failed"); + safe_read (fil_fd, filename, wrlast_buf, wrlast_len); + safe_lseek(dev_fd, wrlast_len, SEEK_SET, device); + written += wrlast_len; + size -= wrlast_len; + i -= wrlast_len; + + log_verbose ("Writing remaining erase block data: %dk/%lluk (%llu%%)\n", + KB (written + i), + KB ((unsigned long long)filestat.st_size), + PERCENTAGE ((unsigned long long)written + i, (unsigned long long)filestat.st_size)); + safe_read (fil_fd, filename, src, i); + safe_write(dev_fd, src, i, written, (unsigned long long)filestat.st_size, device); + + written += i; + size -= i; + i = mtd.erasesize; + } else { + log_verbose ("Writing data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size)); + } + while (size) { - if (size < BUFSIZE) i = size; - if (flags & FLAG_VERBOSE) - log_printf (LOG_NORMAL,"\rWriting data: %dk/%lluk (%llu%%)", - KB (written + i), - KB ((unsigned long long)filestat.st_size), - PERCENTAGE (written + i,(unsigned long long)filestat.st_size)); + if (size < mtd.erasesize) i = size; + log_verbose ("\rWriting data: %dk/%lluk (%llu%%)", + KB (written + i), + KB ((unsigned long long)filestat.st_size), + PERCENTAGE ((unsigned long long)written + i,(unsigned long long)filestat.st_size)); /* read from filename */ - safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); + safe_read (fil_fd,filename,src,i); /* write to device */ - result = write (dev_fd,src,i); - if (i != result) - { - if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n"); - if (result < 0) - { - log_printf (LOG_ERROR, - "While writing data to 0x%.8lx-0x%.8lx on %s: %m\n", - written,written + i,device); - exit (EXIT_FAILURE); - } - log_printf (LOG_ERROR, - "Short write count returned while writing to x%.8zx-0x%.8zx on %s: %zu/%llu bytes written to flash\n", - written,written + i,device,written + result,(unsigned long long)filestat.st_size); - exit (EXIT_FAILURE); - } + safe_write(dev_fd,src,i,written,(unsigned long long)filestat.st_size,device); written += i; size -= i; } - if (flags & FLAG_VERBOSE) - log_printf (LOG_NORMAL, - "\rWriting data: %lluk/%lluk (100%%)\n", - KB ((unsigned long long)filestat.st_size), - KB ((unsigned long long)filestat.st_size)); + log_verbose ("\rWriting data: %lluk/%lluk (100%%)\n", + KB ((unsigned long long)filestat.st_size), + KB ((unsigned long long)filestat.st_size)); DEBUG("Wrote %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size); + if ((flags & FLAG_WR_LAST) && (filestat.st_size > wrlast_len)) { + log_verbose ("Writing %lluk of the write last data.\n", KB ((unsigned long long)wrlast_len)); + safe_rewind (dev_fd, device); + safe_write(dev_fd, wrlast_buf, wrlast_len, 0, wrlast_len, device); + } + /********************************** * verify that flash == file data * **********************************/ @@ -364,43 +446,96 @@ int main (int argc,char *argv[]) safe_rewind (fil_fd,filename); safe_rewind (dev_fd,device); size = filestat.st_size; - i = BUFSIZE; + i = mtd.erasesize; written = 0; - if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size)); + log_verbose ("Verifying data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size)); while (size) { - if (size < BUFSIZE) i = size; - if (flags & FLAG_VERBOSE) - log_printf (LOG_NORMAL, - "\rVerifying data: %luk/%lluk (%llu%%)", - KB (written + i), - KB ((unsigned long long)filestat.st_size), - PERCENTAGE (written + i,(unsigned long long)filestat.st_size)); + if (size < mtd.erasesize) i = size; + log_verbose ("\rVerifying data: %luk/%lluk (%llu%%)", + KB (written + i), + KB ((unsigned long long)filestat.st_size), + PERCENTAGE ((unsigned long long)written + i,(unsigned long long)filestat.st_size)); /* read from filename */ - safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); + safe_read (fil_fd,filename,src,i); /* read from device */ - safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE); + safe_read (dev_fd,device,dest,i); /* compare buffers */ if (memcmp (src,dest,i)) - { - log_printf (LOG_ERROR, - "File does not seem to match flash data. First mismatch at 0x%.8zx-0x%.8zx\n", + log_failure("File does not seem to match flash data. First mismatch at 0x%.8zx-0x%.8zx\n", written,written + i); - exit (EXIT_FAILURE); - } written += i; size -= i; } - if (flags & FLAG_VERBOSE) - log_printf (LOG_NORMAL, - "\rVerifying data: %lluk/%lluk (100%%)\n", - KB ((unsigned long long)filestat.st_size), - KB ((unsigned long long)filestat.st_size)); + log_verbose ("\rVerifying data: %lluk/%lluk (100%%)\n", + KB ((unsigned long long)filestat.st_size), + KB ((unsigned long long)filestat.st_size)); DEBUG("Verified %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size); exit (EXIT_SUCCESS); + + /********************************************* + * Copy different blocks from file to device * + ********************************************/ +DIFF_BLOCKS: + safe_rewind (fil_fd,filename); + safe_rewind (dev_fd,device); + size = filestat.st_size; + i = mtd.erasesize; + erase.start = 0; + erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize; + erase.length *= mtd.erasesize; + written = 0; + unsigned long current_dev_block = 0; + int diffBlock = 0; + int blocks = erase.length / mtd.erasesize; + erase.length = mtd.erasesize; + + log_verbose ("\rProcessing blocks: 0/%d (%d%%)", blocks, PERCENTAGE (0,blocks)); + for (int s = 1; s <= blocks; s++) + { + if (size < mtd.erasesize) i = size; + log_verbose ("\rProcessing blocks: %d/%d (%d%%)", s, blocks, PERCENTAGE (s,blocks)); + + /* read from filename */ + safe_read (fil_fd,filename,src,i); + + /* read from device */ + current_dev_block = safe_lseek(dev_fd, 0, SEEK_CUR, device); + safe_read (dev_fd,device,dest,i); + + /* compare buffers, if not the same, erase and write the block */ + if (memcmp (src,dest,i)) + { + diffBlock++; + /* erase block */ + safe_lseek(dev_fd, current_dev_block, SEEK_SET, device); + safe_memerase(dev_fd,device,&erase); + + /* write to device */ + safe_lseek(dev_fd, current_dev_block, SEEK_SET, device); + safe_write(dev_fd,src,i,written,(unsigned long long)filestat.st_size,device); + + /* read from device */ + safe_lseek(dev_fd, current_dev_block, SEEK_SET, device); + safe_read (dev_fd,device,dest,i); + + /* compare buffers for write success */ + if (memcmp (src,dest,i)) + log_failure("File does not seem to match flash data. First mismatch at 0x%.8zx-0x%.8zx\n", + written,written + i); + } + + erase.start += i; + written += i; + size -= i; + } + + log_verbose ("\ndiff blocks: %d\n", diffBlock); + + exit (EXIT_SUCCESS); } diff --git a/misc-utils/lsmtd.8 b/misc-utils/lsmtd.8 index 3061c40..198c8a7 100644 --- a/misc-utils/lsmtd.8 +++ b/misc-utils/lsmtd.8 @@ -14,7 +14,7 @@ command reads the .B sysfs filesystem to gather information. Alternatively, the .B procfs -filesystem and ioctl interfaces are used, should the sysfs filesytem not +filesystem and ioctl interfaces are used, should the sysfs filesystem not be available. .PP The command prints all MTD and UBI devices in a pretty-printed list format by diff --git a/misc-utils/lsmtd.c b/misc-utils/lsmtd.c index 24a30ac..b62b69f 100644 --- a/misc-utils/lsmtd.c +++ b/misc-utils/lsmtd.c @@ -72,11 +72,11 @@ static struct column cols[] = { { "SUB-SIZE", "subpage size", COL_SUBSIZE, COL_DT_SIZE, 0 }, { "OOB-SIZE", "out of band data size", COL_OOBSIZE, COL_DT_SIZE, 0 }, { "RO", "read-only device", COL_RO, COL_DT_BOOL, 0 }, - { "CORRUPTED", "wheather an UBI volume is corrupted", + { "CORRUPTED", "whether an UBI volume is corrupted", COL_CORRUPTED, COL_DT_BOOL, 0 }, { "REGIONS", "number of additional erase regions", COL_REGION, COL_DT_NUMBER, 0 }, - { "BB", "wheather the MTD device may have bad eraseblocks", + { "BB", "whether the MTD device may have bad eraseblocks", COL_BB, COL_DT_BOOL, 0 }, { "MAX-EC", "current highest erase counter value on UBI devices", COL_MAXEC, COL_DT_NUMBER, 0 }, @@ -107,7 +107,7 @@ static NORETURN void usage(int status) " -r, --raw Use raw output format\n" " -P, --pairs Use key=\"value\" output format\n" " -J, --json Use JSON output format\n" -" -o, --output <list> Comma seperated list of columns to print\n" +" -o, --output <list> Comma separated list of columns to print\n" " -O, --output-all Print all columns\n" " -x, --sort <column> Sort output by <column>\n" " -m, --no-ubi Do not display information about UBI devices/volumes\n" diff --git a/misc-utils/lsmtd_scan.c b/misc-utils/lsmtd_scan.c index cec7b5c..9331c5b 100644 --- a/misc-utils/lsmtd_scan.c +++ b/misc-utils/lsmtd_scan.c @@ -162,7 +162,7 @@ int scan_ubi(libubi_t lib_ubi) } if (j == num_mtd_devices) { - fprintf(stderr, "Cannot find mtd device %d refered to " + fprintf(stderr, "Cannot find mtd device %d referred to " "by ubi device %d\n", dev_info.mtd_num, dev_info.dev_num); return -1; diff --git a/misc-utils/mtd_debug.c b/misc-utils/mtd_debug.c index c0b7109..abee5e3 100644 --- a/misc-utils/mtd_debug.c +++ b/misc-utils/mtd_debug.c @@ -348,6 +348,7 @@ int main(int argc, char *argv[]) { int err = 0, fd; int open_flag; + char *dev; enum { OPT_INFO, @@ -369,8 +370,12 @@ int main(int argc, char *argv[]) showusage(); /* open device */ + dev = mtd_find_dev_node(argv[2]); + if (!dev) + errmsg_die("Failed to find MTD device %s", argv[2]); + open_flag = (option == OPT_INFO || option == OPT_READ) ? O_RDONLY : O_RDWR; - if ((fd = open(argv[2], O_SYNC | open_flag)) < 0) + if ((fd = open(dev, O_SYNC | open_flag)) < 0) errmsg_die("open()"); switch (option) { diff --git a/misc-utils/mtdpart.c b/misc-utils/mtdpart.c index ba35d87..a341148 100644 --- a/misc-utils/mtdpart.c +++ b/misc-utils/mtdpart.c @@ -36,8 +36,10 @@ static void display_help(int status) " -h, --help Display this help and exit\n" " -V, --version Output version information and exit\n" "\n" +" <MTD_DEVICE> MTD device node or 'mtd:<name>'\n" +"\n" "START location and SIZE of the partition are in bytes. They should align on\n" -"eraseblock size.\n", +"eraseblock size. If SIZE is 0 the partition will go to end of MTD device.\n", PROGRAM_NAME ); exit(status); @@ -106,7 +108,10 @@ static void process_options(int argc, char * const argv[]) display_help(EXIT_FAILURE); const char *s_command = argv[optind++]; - mtddev = argv[optind++]; + mtddev = mtd_find_dev_node(argv[optind]); + if (!mtddev) + errmsg_die("MTD device not found %s", argv[optind]); + optind++; if (strcmp(s_command, "del") == 0 && (argc - optind) == 1) { const char *s_part_no = argv[optind++]; |