From aaa77f94ce6e03d9730f62004347ec2bbf11cfb1 Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Thu, 31 Aug 2023 17:55:03 -0700 Subject: flashcp: Add write last option. This option is useful for power fail resilient bootloader updates, for systems that check only the partition header for validity before attempting to load the bootloader. For example zynq. Postponing the write of a specified amount of bytes at the beginning of a bootloader makes sure a written bootloader slot is not considered valid until all the data is written. Signed-off-by: David Oberhollenzer --- misc-utils/flashcp.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/misc-utils/flashcp.c b/misc-utils/flashcp.c index e1be292..9c48637 100644 --- a/misc-utils/flashcp.c +++ b/misc-utils/flashcp.c @@ -64,6 +64,7 @@ #define FLAG_DEVICE 0x08 #define FLAG_ERASE_ALL 0x10 #define FLAG_PARTITION 0x20 +#define FLAG_WR_LAST 0x40 /* error levels */ #define LOG_NORMAL 1 @@ -104,13 +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" - " -p | --partition Only copy different block from file to device\n" - " -A | --erase-all Erases the whole device regardless of the image size\n" - " -V | --version Show version information and exit\n" - " File which you want to copy to flash\n" - " Flash device node or 'mtd:' to write to (e.g. /dev/mtd0, /dev/mtd1, mtd:data, 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" + " File which you want to copy to flash\n" + " Flash device node or 'mtd:' to write to (e.g. /dev/mtd0, /dev/mtd1, mtd:data, etc.)\n" "\n", PROGRAM_NAME); @@ -219,7 +221,9 @@ int main (int argc,char *argv[]) struct mtd_info_user mtd; struct erase_info_user erase; struct stat filestat; - unsigned char *src,*dest; + unsigned char *src,*dest,*wrlast_buf; + unsigned long long wrlast_len = 0; + int error = 0; /********************* * parse cmd-line @@ -227,12 +231,13 @@ int main (int argc,char *argv[]) for (;;) { int option_index = 0; - static const char *short_options = "hvpAV"; + 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}, }; @@ -260,6 +265,10 @@ int main (int argc,char *argv[]) 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); @@ -288,6 +297,10 @@ int main (int argc,char *argv[]) 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 */ @@ -364,10 +377,40 @@ int main (int argc,char *argv[]) * write the entire file to flash * **********************************/ - log_verbose ("Writing data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size)); size = filestat.st_size; 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 < mtd.erasesize) i = size; @@ -390,6 +433,12 @@ int main (int argc,char *argv[]) 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 * **********************************/ -- cgit v1.2.3