If flashrom encounters an erase or write error, it will complain loudly and tell the user that the flash chip is in an unknown state. Most of the time the erase/write failed completely, and this case can be detected by always reading the full chip before any write action and comparing the new contents against the old contents after any failed erase/write.
This should spit out a much more harmless warning if write/erase failed, but the flash chip is completely unmodified.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-always_read_no_scary_warning/flash.h =================================================================== --- flashrom-always_read_no_scary_warning/flash.h (Revision 1023) +++ flashrom-always_read_no_scary_warning/flash.h (Arbeitskopie) @@ -562,7 +562,7 @@ int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len); int erase_flash(struct flashchip *flash); struct flashchip *probe_flash(struct flashchip *first_flash, int force); -int read_flash(struct flashchip *flash, char *filename); +int read_flash_write_file(struct flashchip *flash, char *filename); void check_chip_supported(struct flashchip *flash); int check_max_decode(enum chipbustype buses, uint32_t size); int min(int a, int b); Index: flashrom-always_read_no_scary_warning/cli_classic.c =================================================================== --- flashrom-always_read_no_scary_warning/cli_classic.c (Revision 1023) +++ flashrom-always_read_no_scary_warning/cli_classic.c (Arbeitskopie) @@ -419,7 +419,7 @@ exit(1); } printf("Please note that forced reads most likely contain garbage.\n"); - return read_flash(flashes[0], filename); + return read_flash_write_file(flashes[0], filename); } // FIXME: flash writes stay enabled! programmer_shutdown(); Index: flashrom-always_read_no_scary_warning/flashrom.c =================================================================== --- flashrom-always_read_no_scary_warning/flashrom.c (Revision 1023) +++ flashrom-always_read_no_scary_warning/flashrom.c (Arbeitskopie) @@ -1003,12 +1003,10 @@ return ret; }
-int read_flash(struct flashchip *flash, char *filename) +int write_buf_to_file(unsigned char *buf, unsigned long size, char *filename) { unsigned long numbytes; FILE *image; - unsigned long size = flash->total_size * 1024; - unsigned char *buf = calloc(size, sizeof(char));
if (!filename) { msg_gerr("Error: No filename specified.\n"); @@ -1018,23 +1016,32 @@ perror(filename); exit(1); } - msg_cinfo("Reading flash... "); - if (!flash->read) { - msg_cinfo("FAILED!\n"); - msg_cerr("ERROR: flashrom has no read function for this flash chip.\n"); - return 1; - } else - flash->read(flash, buf, 0, size);
numbytes = fwrite(buf, 1, size, image); fclose(image); - free(buf); msg_cinfo("%s.\n", numbytes == size ? "done" : "FAILED"); if (numbytes != size) return 1; return 0; }
+int read_flash_write_file(struct flashchip *flash, char *filename) +{ + unsigned long size = flash->total_size * 1024; + unsigned char *buf = calloc(size, sizeof(char)); + + msg_cinfo("Reading flash... "); + if (!flash->read) { + msg_cinfo("FAILED!\n"); + msg_cerr("ERROR: flashrom has no read function for this flash chip.\n"); + return 1; + } + if (flash->read(flash, buf, 0, size)) + return 1; + + return write_buf_to_file(buf, flash->total_size * 1024, filename); +} + /* This function shares a lot of its structure with erase_flash(). * Even if an error is found, the function will keep going and check the rest. */ @@ -1169,6 +1176,19 @@ return ret; }
+void nonfatal_help_message(void) +{ + msg_gerr("Writing to the flash chip apparently didn't do anything.\n" + "This means we have to add special support for your board, " + "programmer or flash chip.\n" + "Please report this on IRC at irc.freenode.net (channel " + "#flashrom) or\n" + "mail flashrom@flashrom.org!\n" + "-------------------------------------------------------------" + "------------------\n" + "You may now reboot or simply leave the machine running.\n"); +} + void emergency_help_message(void) { msg_gerr("Your flash chip is in an unknown state.\n" @@ -1330,7 +1350,7 @@ */ int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it) { - uint8_t *buf; + uint8_t *buf, *oldflashcontents; unsigned long numbytes; FILE *image; int ret = 0; @@ -1338,7 +1358,31 @@
size = flash->total_size * 1024; buf = (uint8_t *) calloc(size, sizeof(char)); + oldflashcontents = (uint8_t *) calloc(size, sizeof(char));
+ /* FIXME: This ignores --noverify. */ + if (read_it || write_it || erase_it) { + /* Useful for chips with read lock. */ + if (flash->unlock) + flash->unlock(flash); + + msg_cinfo("Reading flash... "); + if (!flash->read) { + msg_cinfo("FAILED!\n"); + msg_cerr("ERROR: flashrom has no read function for " + "this flash chip.\n"); + msg_cerr("Aborting.\n"); + programmer_shutdown(); + return 1; + } + if (flash->read(flash, oldflashcontents, 0, size)) { + msg_cinfo("FAILED!\n"); + msg_cerr("Aborting.\n"); + programmer_shutdown(); + return 1; + } + } + if (erase_it) { if (flash->tested & TEST_BAD_ERASE) { msg_cerr("Erase is not working on this chip. "); @@ -1354,18 +1398,26 @@ flash->unlock(flash);
if (erase_flash(flash)) { + msg_cerr("Uh oh. Erase failed. Checking if anything " + "changed.\n"); + if (!flash->read(flash, buf, 0, size)) { + if (!memcmp(oldflashcontents, buf, size)) { + msg_cinfo("Good. It seems nothing was " + "changed.\n"); + nonfatal_help_message(); + programmer_shutdown(); + return 1; + } + } emergency_help_message(); programmer_shutdown(); return 1; } } else if (read_it) { - if (flash->unlock) - flash->unlock(flash); + ret = write_buf_to_file(buf, flash->total_size * 1024, filename);
- if (read_flash(flash, filename)) { - programmer_shutdown(); - return 1; - } + programmer_shutdown(); + return ret; } else { struct stat image_stat;
@@ -1421,8 +1473,7 @@ } }
- // This should be moved into each flash part's code to do it - // cleanly. This does the job. + /* FIXME: handle_romentries should reuse oldflashcontents. */ handle_romentries(buf, flash);
// //////////////////////////////////////////////////////////// @@ -1436,7 +1487,18 @@ } ret = flash->write(flash, buf); if (ret) { - msg_cerr("FAILED!\n"); + msg_cerr("Uh oh. Write failed. Checking if anything " + "changed.\n"); + /* FIXME: Should we really reuse buf here? */ + if (!flash->read(flash, buf, 0, size)) { + if (!memcmp(oldflashcontents, buf, size)) { + msg_cinfo("Good. It seems nothing was " + "changed.\n"); + nonfatal_help_message(); + programmer_shutdown(); + return 1; + } + } emergency_help_message(); programmer_shutdown(); return 1;