flashrom only checks for very few chips if the erase worked. And even when it checks if the erase worked, the result of that check is often ignored.
Fix the majority of these problems. More to come, but I'd like to get this reviewed first.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-check_erase_range/flash.h =================================================================== --- flashrom-check_erase_range/flash.h (Revision 584) +++ flashrom-check_erase_range/flash.h (Arbeitskopie) @@ -721,6 +721,10 @@ #define printf_debug(x...) { if (verbose) printf(x); } void map_flash_registers(struct flashchip *flash); int read_memmapped(struct flashchip *flash, uint8_t *buf); +int min(int a, int b); +int max(int a, int b); +int check_erased_range(struct flashchip *flash, int start, int len); +int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message); extern char *pcidev_bdf;
/* layout.c */ Index: flashrom-check_erase_range/en29f002a.c =================================================================== --- flashrom-check_erase_range/en29f002a.c (Revision 584) +++ flashrom-check_erase_range/en29f002a.c (Arbeitskopie) @@ -98,7 +98,10 @@
//chip_writeb(0xF0, bios); programmer_delay(10); - erase_chip_jedec(flash); + if (erase_chip_jedec(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + }
printf("Programming page: "); for (i = 0; i < total_size; i++) { Index: flashrom-check_erase_range/sharplhf00l04.c =================================================================== --- flashrom-check_erase_range/sharplhf00l04.c (Revision 584) +++ flashrom-check_erase_range/sharplhf00l04.c (Arbeitskopie) @@ -124,6 +124,10 @@ print_lhf00l04_status(status); printf("DONE BLOCK 0x%x\n", offset);
+ if (check_erased_range(flash, offset, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } return 0; }
@@ -135,7 +139,10 @@ printf("total_size is %d; flash->page_size is %d\n", total_size, flash->page_size); for (i = 0; i < total_size; i += flash->page_size) - erase_lhf00l04_block(flash, i); + if (erase_lhf00l04_block(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } printf("DONE ERASE\n");
return 0; @@ -161,9 +168,8 @@ int page_size = flash->page_size; chipaddr bios = flash->virtual_memory;
- erase_lhf00l04(flash); - if (chip_readb(bios) != 0xff) { - printf("ERASE FAILED!\n"); + if (erase_lhf00l04(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); return -1; } printf("Programming page: "); Index: flashrom-check_erase_range/w39v040c.c =================================================================== --- flashrom-check_erase_range/w39v040c.c (Revision 584) +++ flashrom-check_erase_range/w39v040c.c (Arbeitskopie) @@ -60,16 +60,13 @@ { int i; unsigned int total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory;
- for (i = 0; i < total_size; i += flash->page_size) - erase_sector_jedec(flash->virtual_memory, i); - - for (i = 0; i < total_size; i++) - if (0xff != chip_readb(bios + i)) { - printf("ERASE FAILED at 0x%08x! Expected=0xff, Read=0x%02x\n", i, chip_readb(bios + i)); + for (i = 0; i < total_size; i += flash->page_size) { + if (erase_sector_jedec(flash->virtual_memory, i)) { + fprintf(stderr, "ERASE FAILED!\n"); return -1; } + }
return 0; } @@ -81,8 +78,10 @@ int page_size = flash->page_size; chipaddr bios = flash->virtual_memory;
- if (flash->erase(flash)) + if (flash->erase(flash)) { + fprintf(stderr, "ERASE FAILED!\n"); return -1; + }
printf("Programming page: "); for (i = 0; i < total_size / page_size; i++) { Index: flashrom-check_erase_range/stm50flw0x0x.c =================================================================== --- flashrom-check_erase_range/stm50flw0x0x.c (Revision 584) +++ flashrom-check_erase_range/stm50flw0x0x.c (Arbeitskopie) @@ -163,7 +163,6 @@ int erase_block_stm50flw0x0x(struct flashchip *flash, int offset) { chipaddr bios = flash->virtual_memory + offset; - int j;
// clear status register chip_writeb(0x50, bios); @@ -175,13 +174,10 @@
wait_stm50flw0x0x(flash->virtual_memory);
- for (j = 0; j < flash->page_size; j++) { - if (chip_readb(bios + j) != 0xFF) { - printf("Erase failed at 0x%x\n", offset + j); - return -1; - } + if (check_erased_range(flash, offset, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; } - printf("DONE BLOCK 0x%x\n", offset);
return 0; @@ -230,24 +226,29 @@ */ int erase_stm50flw0x0x(struct flashchip *flash) { - int i, rc = 0; + int i; int total_size = flash->total_size * 1024; int page_size = flash->page_size; chipaddr bios = flash->virtual_memory;
printf("Erasing page:\n"); - for (i = 0; (i < total_size / page_size) && (rc == 0); i++) { + for (i = 0; i < total_size / page_size; i++) { printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf("%04d at address: 0x%08x ", i, i * page_size); - rc = unlock_block_stm50flw0x0x(flash, i * page_size); - if (!rc) - rc = erase_block_stm50flw0x0x(flash, i * page_size); + if (unlock_block_stm50flw0x0x(flash, i * page_size)) { + fprintf(stderr, "UNLOCK FAILED!\n"); + return -1; + } + if (erase_block_stm50flw0x0x(flash, i * page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } } printf("\n"); protect_stm50flw0x0x(bios);
- return rc; + return 0; }
int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf) Index: flashrom-check_erase_range/am29f040b.c =================================================================== --- flashrom-check_erase_range/am29f040b.c (Revision 584) +++ flashrom-check_erase_range/am29f040b.c (Arbeitskopie) @@ -20,8 +20,11 @@
#include "flash.h"
-static int erase_sector_29f040b(chipaddr bios, unsigned long address) +static int erase_sector_29f040b(struct flashchip *flash, unsigned long address) { + int page_size = flash->page_size; + chipaddr bios = flash->virtual_memory; + chip_writeb(0xAA, bios + 0x555); chip_writeb(0x55, bios + 0x2AA); chip_writeb(0x80, bios + 0x555); @@ -34,6 +37,10 @@ /* wait for Toggle bit ready */ toggle_ready_jedec(bios + address);
+ if (check_erased_range(flash, address, page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } return 0; }
@@ -86,6 +93,7 @@
int erase_29f040b(struct flashchip *flash) { + int total_size = flash->total_size * 1024; chipaddr bios = flash->virtual_memory;
chip_writeb(0xAA, bios + 0x555); @@ -98,6 +106,10 @@ programmer_delay(10); toggle_ready_jedec(bios);
+ if (check_erased_range(flash, 0, total_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } return 0; }
@@ -111,7 +123,10 @@ printf("Programming page "); for (i = 0; i < total_size / page_size; i++) { /* erase the page before programming */ - erase_sector_29f040b(bios, i * page_size); + if (erase_sector_29f040b(flash, i * page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + }
/* write to the sector */ printf("%04d at address: ", i); Index: flashrom-check_erase_range/sst_fwhub.c =================================================================== --- flashrom-check_erase_range/sst_fwhub.c (Revision 584) +++ flashrom-check_erase_range/sst_fwhub.c (Arbeitskopie) @@ -104,7 +104,10 @@ return 1; }
- erase_block_jedec(flash->virtual_memory, offset); + if (erase_block_jedec(flash->virtual_memory, offset)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } toggle_ready_jedec(flash->virtual_memory);
return 0; @@ -114,15 +117,10 @@ { int i; unsigned int total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory;
- for (i = 0; i < total_size; i += flash->page_size) - erase_sst_fwhub_block(flash, i); - - // dumb check if erase was successful. - for (i = 0; i < total_size; i++) { - if (chip_readb(bios + i) != 0xff) { - printf("ERASE FAILED!\n"); + for (i = 0; i < total_size; i += flash->page_size) { + if (erase_sst_fwhub_block(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); return -1; } } Index: flashrom-check_erase_range/w39v080fa.c =================================================================== --- flashrom-check_erase_range/w39v080fa.c (Revision 584) +++ flashrom-check_erase_range/w39v080fa.c (Arbeitskopie) @@ -142,9 +142,10 @@ return 0; }
-static int erase_sector_winbond_fwhub(chipaddr bios, +static int erase_sector_winbond_fwhub(struct flashchip *flash, unsigned int sector) { + chipaddr bios = flash->virtual_memory; /* Remember: too much sleep can waste your day. */
printf("0x%08x\b\b\b\b\b\b\b\b\b\b", sector); @@ -161,30 +162,30 @@ /* wait for Toggle bit ready */ toggle_ready_jedec(bios);
+ if (check_erased_range(flash, sector, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } return 0; }
int erase_winbond_fwhub(struct flashchip *flash) { int i, total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory;
unlock_winbond_fwhub(flash);
printf("Erasing: ");
- for (i = 0; i < total_size; i += flash->page_size) - erase_sector_winbond_fwhub(bios, i); - - printf("\n"); - - for (i = 0; i < total_size; i++) { - if (chip_readb(bios + i) != 0xff) { - fprintf(stderr, "Error: Flash chip erase failed at 0x%08x(0x%02x)\n", i, chip_readb(bios + i)); + for (i = 0; i < total_size; i += flash->page_size) { + if (erase_sector_winbond_fwhub(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); return -1; } }
+ printf("\n"); + return 0; }
Index: flashrom-check_erase_range/flashrom.c =================================================================== --- flashrom-check_erase_range/flashrom.c (Revision 584) +++ flashrom-check_erase_range/flashrom.c (Arbeitskopie) @@ -200,6 +200,16 @@ return 0; }
+int min(int a, int b) +{ + return (a < b) ? a : b; +} + +int max(int a, int b) +{ + return (a > b) ? a : b; +} + char *strcat_realloc(char *dest, const char *src) { dest = realloc(dest, strlen(dest) + strlen(src) + 1); @@ -240,6 +250,72 @@ return ret; }
+/* start is an offset to the base address of the flash chip */ +int check_erased_range(struct flashchip *flash, int start, int len) +{ + int page_size = flash->page_size; + uint8_t *cmpbuf = malloc(page_size); + + if (!cmpbuf) { + fprintf(stderr, "Could not allocate memory!\n"); + exit(1); + } + memset(cmpbuf, 0xff, len); + return verify_range(flash, cmpbuf, start, len, "ERASE"); +} + +/* start is an offset to the base address of the flash chip */ +int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message) +{ + int i, j, starthere, lenhere; + chipaddr bios = flash->virtual_memory; + int page_size = flash->page_size; + uint8_t *readbuf = malloc(page_size); + + if (!readbuf) { + fprintf(stderr, "Could not allocate memory!\n"); + exit(1); + } + if (start + len > flash->total_size * 1024) { + fprintf(stderr, "Error: %s called with start 0x%x + len 0x%x >" + " total_size 0x%x\n", __func__, start, len, + flash->total_size * 1024); + return -1; + } + if (!len) + return 0; + if (!message) + message = "VERIFY"; + + /* Warning: This loop has a very unusual condition and body. + * The loop needs to go through each page with at least one affected + * byte. The lowest page number is (start / page_size) since that + * division rounds down. The highest page number we want is the page + * where the last byte of the range lives. That last byte has the + * address (start + len - 1), thus the highest page number is + * (start + len - 1) / page_size. Since we want to include that last + * page as well, the loop condition uses <=. + */ + for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { + /* Byte position of the first byte in the range in this page. */ + starthere = max(start, i * page_size); + /* Length of bytes in the range in this page. */ + lenhere = min(start + len, (i + 1) * page_size) - starthere; + /* starthere is an offset to the base address of the chip. */ + chip_readn(readbuf, bios + starthere, lenhere); + for (j = 0; j < lenhere; j++) { + if (cmpbuf[starthere + j] != readbuf[j]) { + fprintf(stderr, "%s FAILED at 0x%08x! " + "Expected=0x%02x, Read=0x%02x\n", + message, starthere + j, + cmpbuf[starthere + j], readbuf[j]); + return -1; + } + } + } + return 0; +} + struct flashchip *probe_flash(struct flashchip *first_flash, int force) { struct flashchip *flash; Index: flashrom-check_erase_range/82802ab.c =================================================================== --- flashrom-check_erase_range/82802ab.c (Revision 584) +++ flashrom-check_erase_range/82802ab.c (Arbeitskopie) @@ -110,7 +110,6 @@ { chipaddr bios = flash->virtual_memory + offset; chipaddr wrprotect = flash->virtual_registers + offset + 2; - int j; uint8_t status;
// clear status register @@ -129,11 +128,9 @@ // now let's see what the register is status = wait_82802ab(flash->virtual_memory); //print_82802ab_status(status); - for (j = 0; j < flash->page_size; j++) { - if (chip_readb(bios + j) != 0xFF) { - printf("BLOCK ERASE failed at 0x%x\n", offset); - return -1; - } + if (check_erased_range(flash, offset, flash->page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; } printf("DONE BLOCK 0x%x\n", offset);
@@ -148,7 +145,10 @@ printf("total_size is %d; flash->page_size is %d\n", total_size, flash->page_size); for (i = 0; i < total_size; i += flash->page_size) - erase_82802ab_block(flash, i); + if (erase_82802ab_block(flash, i)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } printf("DONE ERASE\n");
return 0; @@ -199,7 +199,10 @@ }
/* erase block by block and write block by block; this is the most secure way */ - erase_82802ab_block(flash, i * page_size); + if (erase_82802ab_block(flash, i * page_size)) { + fprintf(stderr, "ERASE FAILED!\n"); + return -1; + } write_page_82802ab(bios, buf + i * page_size, bios + i * page_size, page_size); }