No words can describe this feeling.

Signed-off-by: Nico Huber <[email protected]>
---
 cli_classic.c |  24 ++--
 flash.h       |   5 +-
 flashrom.c    | 393 +++++++++++-----------------------------------------------
 3 files changed, 90 insertions(+), 332 deletions(-)

diff --git a/cli_classic.c b/cli_classic.c
index ac4c6f8..d7e17f7 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -530,24 +530,28 @@ int main(int argc, char *argv[])
                goto out_shutdown;
        }
 
-       /* Always verify write operations unless -n is used. */
-       if (write_it && !dont_verify_it)
-               verify_it = 1;
+       if (layoutfile)
+               fl_layout_set(fill_flash, get_global_layout());
 
-       /* Map the selected flash chip again. */
-       if (map_flash(fill_flash) != 0) {
-               ret = 1;
-               goto out_shutdown;
-       }
+       fl_flag_set(fill_flash, FL_FLAG_FORCE, !!force);
+       fl_flag_set(fill_flash, FL_FLAG_FORCE_BOARDMISMATCH, 
!!force_boardmismatch);
+       fl_flag_set(fill_flash, FL_FLAG_VERIFY_AFTER_WRITE, !dont_verify_it);
+       fl_flag_set(fill_flash, FL_FLAG_VERIFY_WHOLE_CHIP, true);
 
        /* FIXME: We should issue an unconditional chip reset here. This can be
         * done once we have a .reset function in struct flashchip.
         * Give the chip time to settle.
         */
        programmer_delay(100000);
-       ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, 
verify_it);
+       if (read_it)
+               ret = do_read(fill_flash, filename);
+       else if (erase_it)
+               ret = do_erase(fill_flash);
+       else if (write_it)
+               ret = do_write(fill_flash, filename);
+       else if (verify_it)
+               ret = do_verify(fill_flash, filename);
 
-       unmap_flash(fill_flash);
 out_shutdown:
        programmer_shutdown();
 out:
diff --git a/flash.h b/flash.h
index 3afa846..fc024ac 100644
--- a/flash.h
+++ b/flash.h
@@ -283,9 +283,12 @@ void print_buildinfo(void);
 void print_banner(void);
 void list_programmers_linebreak(int startcol, int cols, int paren);
 int selfcheck(void);
-int doit(struct flashctx *flash, int force, const char *filename, int read_it, 
int write_it, int erase_it, int verify_it);
 int read_buf_from_file(unsigned char *buf, unsigned long size, const char 
*filename);
 int write_buf_to_file(const unsigned char *buf, unsigned long size, const char 
*filename);
+int do_read(struct flashctx *, const char *filename);
+int do_erase(struct flashctx *);
+int do_write(struct flashctx *, const char *const filename);
+int do_verify(struct flashctx *, const char *const filename);
 
 /* Something happened that shouldn't happen, but we can go on. */
 #define ERROR_NONFATAL 0x100
diff --git a/flashrom.c b/flashrom.c
index b580f0e..0bc8e6f 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1365,6 +1365,7 @@ out:
 #endif
 }
 
+static int read_by_layout(struct flashctx *, void *);
 int read_flash_to_file(struct flashctx *flash, const char *filename)
 {
        unsigned long size = flash->chip->total_size * 1024;
@@ -1382,7 +1383,7 @@ int read_flash_to_file(struct flashctx *flash, const char 
*filename)
                ret = 1;
                goto out_free;
        }
-       if (flash->chip->read(flash, buf, 0, size)) {
+       if (read_by_layout(flash, buf)) {
                msg_cerr("Read operation failed!\n");
                ret = 1;
                goto out_free;
@@ -1461,97 +1462,6 @@ static int selfcheck_eraseblocks(const struct flashchip 
*chip)
        return ret;
 }
 
-static int erase_and_write_block_helper(struct flashctx *flash,
-                                       unsigned int start, unsigned int len,
-                                       uint8_t *curcontents,
-                                       uint8_t *newcontents,
-                                       int (*erasefn) (struct flashctx *flash,
-                                                       unsigned int addr,
-                                                       unsigned int len))
-{
-       unsigned int starthere = 0, lenhere = 0;
-       int ret = 0, skip = 1, writecount = 0;
-       enum write_granularity gran = flash->chip->gran;
-
-       /* curcontents and newcontents are opaque to walk_eraseregions, and
-        * need to be adjusted here to keep the impression of proper abstraction
-        */
-       curcontents += start;
-       newcontents += start;
-       msg_cdbg(":");
-       if (need_erase(curcontents, newcontents, len, gran)) {
-               msg_cdbg("E");
-               ret = erasefn(flash, start, len);
-               if (ret)
-                       return ret;
-               if (check_erased_range(flash, start, len)) {
-                       msg_cerr("ERASE FAILED!\n");
-                       return -1;
-               }
-               /* Erase was successful. Adjust curcontents. */
-               memset(curcontents, 0xff, len);
-               skip = 0;
-       }
-       /* get_next_write() sets starthere to a new value after the call. */
-       while ((lenhere = get_next_write(curcontents + starthere,
-                                        newcontents + starthere,
-                                        len - starthere, &starthere, gran))) {
-               if (!writecount++)
-                       msg_cdbg("W");
-               /* Needs the partial write function signature. */
-               ret = flash->chip->write(flash, newcontents + starthere,
-                                  start + starthere, lenhere);
-               if (ret)
-                       return ret;
-               starthere += lenhere;
-               skip = 0;
-       }
-       if (skip)
-               msg_cdbg("S");
-       else
-               all_skipped = false;
-       return ret;
-}
-
-static int walk_eraseregions(struct flashctx *flash, int erasefunction,
-                            int (*do_something) (struct flashctx *flash,
-                                                 unsigned int addr,
-                                                 unsigned int len,
-                                                 uint8_t *param1,
-                                                 uint8_t *param2,
-                                                 int (*erasefn) (
-                                                       struct flashctx *flash,
-                                                       unsigned int addr,
-                                                       unsigned int len)),
-                            void *param1, void *param2)
-{
-       int i, j;
-       unsigned int start = 0;
-       unsigned int len;
-       struct block_eraser eraser = flash->chip->block_erasers[erasefunction];
-
-       for (i = 0; i < NUM_ERASEREGIONS; i++) {
-               /* count==0 for all automatically initialized array
-                * members so the loop below won't be executed for them.
-                */
-               len = eraser.eraseblocks[i].size;
-               for (j = 0; j < eraser.eraseblocks[i].count; j++) {
-                       /* Print this for every block except the first one. */
-                       if (i || j)
-                               msg_cdbg(", ");
-                       msg_cdbg("0x%06x-0x%06x", start,
-                                    start + len - 1);
-                       if (do_something(flash, start, len, param1, param2,
-                                        eraser.block_erase)) {
-                               return 1;
-                       }
-                       start += len;
-               }
-       }
-       msg_cdbg("\n");
-       return 0;
-}
-
 static int check_block_eraser(const struct flashctx *flash, int k, int log)
 {
        struct block_eraser eraser = flash->chip->block_erasers[k];
@@ -1577,71 +1487,6 @@ static int check_block_eraser(const struct flashctx 
*flash, int k, int log)
        return 0;
 }
 
-int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents, 
uint8_t *newcontents)
-{
-       int k, ret = 1;
-       uint8_t *curcontents;
-       unsigned long size = flash->chip->total_size * 1024;
-       unsigned int usable_erasefunctions = count_usable_erasers(flash);
-
-       msg_cinfo("Erasing and writing flash chip... ");
-       curcontents = malloc(size);
-       if (!curcontents) {
-               msg_gerr("Out of memory!\n");
-               exit(1);
-       }
-       /* Copy oldcontents to curcontents to avoid clobbering oldcontents. */
-       memcpy(curcontents, oldcontents, size);
-
-       for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
-               if (k != 0)
-                       msg_cinfo("Looking for another erase function.\n");
-               if (!usable_erasefunctions) {
-                       msg_cinfo("No usable erase functions left.\n");
-                       break;
-               }
-               msg_cdbg("Trying erase function %i... ", k);
-               if (check_block_eraser(flash, k, 1))
-                       continue;
-               usable_erasefunctions--;
-               ret = walk_eraseregions(flash, k, &erase_and_write_block_helper,
-                                       curcontents, newcontents);
-               /* If everything is OK, don't try another erase function. */
-               if (!ret)
-                       break;
-               /* Write/erase failed, so try to find out what the current chip
-                * contents are. If no usable erase functions remain, we can
-                * skip this: the next iteration will break immediately anyway.
-                */
-               if (!usable_erasefunctions)
-                       continue;
-               /* Reading the whole chip may take a while, inform the user even
-                * in non-verbose mode.
-                */
-               msg_cinfo("Reading current flash chip contents... ");
-               if (flash->chip->read(flash, curcontents, 0, size)) {
-                       /* Now we are truly screwed. Read failed as well. */
-                       msg_cerr("Can't read anymore! Aborting.\n");
-                       /* We have no idea about the flash chip contents, so
-                        * retrying with another erase function is pointless.
-                        */
-                       break;
-               }
-               msg_cinfo("done. ");
-       }
-       /* Free the scratchpad. */
-       free(curcontents);
-
-       if (ret) {
-               msg_cerr("FAILED!\n");
-       } else {
-               if (all_skipped)
-                       msg_cinfo("\nWarning: Chip content is identical to the 
requested image.\n");
-               msg_cinfo("Erase/write done.\n");
-       }
-       return ret;
-}
-
 /** @private */
 static const struct fl_layout *get_layout(const struct flashctx *const 
flashctx,
                                          struct fl_layout_single *const 
fallback)
@@ -2298,170 +2143,6 @@ int chip_safety_check(const struct flashctx *flash, int 
force, int read_it, int
        return 0;
 }
 
-/* This function signature is horrible. We need to design a better interface,
- * but right now it allows us to split off the CLI code.
- * Besides that, the function itself is a textbook example of abysmal code 
flow.
- */
-int doit(struct flashctx *flash, int force, const char *filename, int read_it,
-        int write_it, int erase_it, int verify_it)
-{
-       uint8_t *oldcontents;
-       uint8_t *newcontents;
-       int ret = 0;
-       unsigned long size = flash->chip->total_size * 1024;
-       int read_all_first = 1; /* FIXME: Make this configurable. */
-
-       if (chip_safety_check(flash, force, read_it, write_it, erase_it, 
verify_it)) {
-               msg_cerr("Aborting.\n");
-               return 1;
-       }
-
-       if (normalize_romentries(flash)) {
-               msg_cerr("Requested regions can not be handled. Aborting.\n");
-               return 1;
-       }
-
-       /* Given the existence of read locks, we want to unlock for read,
-        * erase and write.
-        */
-       if (flash->chip->unlock)
-               flash->chip->unlock(flash);
-
-       if (read_it) {
-               return read_flash_to_file(flash, filename);
-       }
-
-       oldcontents = malloc(size);
-       if (!oldcontents) {
-               msg_gerr("Out of memory!\n");
-               exit(1);
-       }
-       /* Assume worst case: All bits are 0. */
-       memset(oldcontents, 0x00, size);
-       newcontents = malloc(size);
-       if (!newcontents) {
-               msg_gerr("Out of memory!\n");
-               exit(1);
-       }
-       /* Assume best case: All bits should be 1. */
-       memset(newcontents, 0xff, size);
-       /* Side effect of the assumptions above: Default write action is erase
-        * because newcontents looks like a completely erased chip, and
-        * oldcontents being completely 0x00 means we have to erase everything
-        * before we can write.
-        */
-
-       if (erase_it) {
-               /* FIXME: Do we really want the scary warning if erase failed?
-                * After all, after erase the chip is either blank or partially
-                * blank or it has the old contents. A blank chip won't boot,
-                * so if the user wanted erase and reboots afterwards, the user
-                * knows very well that booting won't work.
-                */
-               if (erase_and_write_flash(flash, oldcontents, newcontents)) {
-                       emergency_help_message();
-                       ret = 1;
-               }
-               goto out;
-       }
-
-       if (write_it || verify_it) {
-               if (read_buf_from_file(newcontents, size, filename)) {
-                       ret = 1;
-                       goto out;
-               }
-
-#if CONFIG_INTERNAL == 1
-               if (programmer == PROGRAMMER_INTERNAL && 
cb_check_image(newcontents, size) < 0) {
-                       if (force_boardmismatch) {
-                               msg_pinfo("Proceeding anyway because user 
forced us to.\n");
-                       } else {
-                               msg_perr("Aborting. You can override this with "
-                                        "-p internal:boardmismatch=force.\n");
-                               ret = 1;
-                               goto out;
-                       }
-               }
-#endif
-       }
-
-       /* Read the whole chip to be able to check whether regions need to be
-        * erased and to give better diagnostics in case write fails.
-        * The alternative is to read only the regions which are to be
-        * preserved, but in that case we might perform unneeded erase which
-        * takes time as well.
-        */
-       if (read_all_first) {
-               msg_cinfo("Reading old flash chip contents... ");
-               if (flash->chip->read(flash, oldcontents, 0, size)) {
-                       ret = 1;
-                       msg_cinfo("FAILED.\n");
-                       goto out;
-               }
-       }
-       msg_cinfo("done.\n");
-
-       /* Build a new image taking the given layout into account. */
-       if (build_new_image(flash, read_all_first, oldcontents, newcontents)) {
-               msg_gerr("Could not prepare the data to be written, 
aborting.\n");
-               ret = 1;
-               goto out;
-       }
-
-       // ////////////////////////////////////////////////////////////
-
-       if (write_it && erase_and_write_flash(flash, oldcontents, newcontents)) 
{
-               msg_cerr("Uh oh. Erase/write failed. ");
-               if (read_all_first) {
-                       msg_cerr("Checking if anything has changed.\n");
-                       msg_cinfo("Reading current flash chip contents... ");
-                       if (!flash->chip->read(flash, newcontents, 0, size)) {
-                               msg_cinfo("done.\n");
-                               if (!memcmp(oldcontents, newcontents, size)) {
-                                       nonfatal_help_message();
-                                       ret = 1;
-                                       goto out;
-                               }
-                               msg_cerr("Apparently at least some data has 
changed.\n");
-                       } else
-                               msg_cerr("Can't even read anymore!\n");
-                       emergency_help_message();
-                       ret = 1;
-                       goto out;
-               } else
-                       msg_cerr("\n");
-               emergency_help_message();
-               ret = 1;
-               goto out;
-       }
-
-       /* Verify only if we either did not try to write (verify operation) or 
actually changed something. */
-       if (verify_it && (!write_it || !all_skipped)) {
-               msg_cinfo("Verifying flash... ");
-
-               if (write_it) {
-                       /* Work around chips which need some time to calm down. 
*/
-                       programmer_delay(1000*1000);
-                       ret = verify_range(flash, newcontents, 0, size);
-                       /* If we tried to write, and verification now fails, we
-                        * might have an emergency situation.
-                        */
-                       if (ret)
-                               emergency_help_message();
-               } else {
-                       ret = compare_range(newcontents, oldcontents, 0, size);
-               }
-               if (!ret)
-                       msg_cinfo("VERIFIED.\n");
-       }
-
-out:
-       free(oldcontents);
-       free(newcontents);
-       return ret;
-}
-
-/** @private */
 static int prepare_flash_access(struct flashctx *const flash,
                                const bool read_it, const bool write_it,
                                const bool erase_it, const bool verify_it)
@@ -2753,3 +2434,73 @@ _free_ret:
 }
 
 /** @} */ /* end fl-ops */
+
+int do_read(struct flashctx *const flash, const char *const filename)
+{
+       if (prepare_flash_access(flash, true, false, false, false))
+               return 1;
+
+       const int ret = read_flash_to_file(flash, filename);
+
+       unmap_flash(flash);
+
+       return ret;
+}
+
+int do_erase(struct flashctx *const flash)
+{
+       const int ret = fl_flash_erase(flash);
+
+       /* FIXME: Do we really want the scary warning if erase failed?
+        * After all, after erase the chip is either blank or partially
+        * blank or it has the old contents. A blank chip won't boot,
+        * so if the user wanted erase and reboots afterwards, the user
+        * knows very well that booting won't work.
+        */
+       if (ret)
+               emergency_help_message();
+
+       return ret;
+}
+
+int do_write(struct flashctx *const flash, const char *const filename)
+{
+       const size_t flash_size = flash->chip->total_size * 1024;
+       int ret = 1;
+
+       uint8_t *const newcontents = malloc(flash_size);
+       if (!newcontents) {
+               msg_gerr("Out of memory!\n");
+               goto _free_ret;
+       }
+
+       if (read_buf_from_file(newcontents, flash_size, filename))
+               goto _free_ret;
+
+       ret = fl_image_write(flash, newcontents, flash_size);
+
+_free_ret:
+       free(newcontents);
+       return ret;
+}
+
+int do_verify(struct flashctx *const flash, const char *const filename)
+{
+       const size_t flash_size = flash->chip->total_size * 1024;
+       int ret = 1;
+
+       uint8_t *const newcontents = malloc(flash_size);
+       if (!newcontents) {
+               msg_gerr("Out of memory!\n");
+               goto _free_ret;
+       }
+
+       if (read_buf_from_file(newcontents, flash_size, filename))
+               goto _free_ret;
+
+       ret = fl_image_verify(flash, newcontents, flash_size);
+
+_free_ret:
+       free(newcontents);
+       return ret;
+}
-- 
2.7.0


_______________________________________________
flashrom mailing list
[email protected]
https://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to