]> www.infradead.org Git - mtd-utils.git/commitdiff
flashcp: Add write last option.
authorPiotr Esden-Tempski <piotr@esden.net>
Fri, 1 Sep 2023 00:55:03 +0000 (17:55 -0700)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Fri, 8 Sep 2023 11:48:52 +0000 (13:48 +0200)
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 <david.oberhollenzer@sigma-star.at>
misc-utils/flashcp.c

index e1be29273dddc6c3d6508eaeab5fa4a1da1f7d68..9c48637fb3f10dd7d82cc32d165505359580e4a1 100644 (file)
@@ -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"
-                       "   <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"
+                       "   -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);
 
@@ -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 *
         **********************************/