diff options
Diffstat (limited to 'flashrom.c')
-rw-r--r-- | flashrom.c | 86 |
1 files changed, 63 insertions, 23 deletions
diff --git a/flashrom.c b/flashrom.c index 630c69db8..dbf06cf47 100644 --- a/flashrom.c +++ b/flashrom.c @@ -379,7 +379,7 @@ void get_flash_region(const struct flashctx *flash, int addr, struct flash_regio } else { region->name = strdup(""); region->start = 0; - region->end = flashrom_flash_getsize(flash); + region->end = flashrom_flash_getsize(flash) - 1; region->read_prot = false; region->write_prot = false; } @@ -388,12 +388,12 @@ void get_flash_region(const struct flashctx *flash, int addr, struct flash_regio int check_for_unwritable_regions(const struct flashctx *flash, unsigned int start, unsigned int len) { struct flash_region region; - for (unsigned int addr = start; addr < start + len; addr = region.end) { + for (unsigned int addr = start; addr < start + len; addr = region.end + 1) { get_flash_region(flash, addr, ®ion); if (region.write_prot) { msg_gerr("%s: cannot write/erase inside %s region (%#08"PRIx32"..%#08"PRIx32").\n", - __func__, region.name, region.start, region.end - 1); + __func__, region.name, region.start, region.end); free(region.name); return -1; } @@ -402,8 +402,10 @@ int check_for_unwritable_regions(const struct flashctx *flash, unsigned int star return 0; } -/* special unit-test hook */ -erasefunc_t *g_test_erase_injector; +#ifdef FLASHROM_TEST +/* special unit-test hooks */ +erasefunc_t *g_test_erase_injector[NUM_TEST_ERASE_INJECTORS]; +#endif erasefunc_t *lookup_erase_func_ptr(const struct block_eraser *const eraser) { @@ -442,7 +444,14 @@ erasefunc_t *lookup_erase_func_ptr(const struct block_eraser *const eraser) case ERASE_SECTOR_49LFXXXC: return &erase_sector_49lfxxxc; case STM50_SECTOR_ERASE: return &erase_sector_stm50; // TODO rename to &stm50_sector_erase; case EDI_CHIP_BLOCK_ERASE: return &edi_chip_block_erase; - case TEST_ERASE_INJECTOR: return g_test_erase_injector; +#ifdef FLASHROM_TEST + case TEST_ERASE_INJECTOR_1: + case TEST_ERASE_INJECTOR_2: + case TEST_ERASE_INJECTOR_3: + case TEST_ERASE_INJECTOR_4: + case TEST_ERASE_INJECTOR_5: + return g_test_erase_injector[eraser->block_erase - TEST_ERASE_INJECTOR_1]; +#endif /* default: total function, 0 indicates no erase function set. * We explicitly do not want a default catch-all case in the switch * to ensure unhandled enum's are compiler warnings. @@ -540,8 +549,10 @@ int check_erased_range(struct flashctx *flash, unsigned int start, unsigned int return ret; } +#ifdef FLASHROM_TEST /* special unit-test hook */ read_func_t *g_test_read_injector; +#endif static read_func_t *lookup_read_func_ptr(const struct flashchip *chip) { @@ -552,7 +563,9 @@ static read_func_t *lookup_read_func_ptr(const struct flashchip *chip) case EDI_CHIP_READ: return &edi_chip_read; case SPI_READ_AT45DB: return spi_read_at45db; case SPI_READ_AT45DB_E8: return spi_read_at45db_e8; +#ifdef FLASHROM_TEST case TEST_READ_INJECTOR: return g_test_read_injector; +#endif /* default: total function, 0 indicates no read function set. * We explicitly do not want a default catch-all case in the switch * to ensure unhandled enum's are compiler warnings. @@ -583,14 +596,14 @@ int read_flash(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigne struct flash_region region; get_flash_region(flash, addr, ®ion); - read_len = min(start + len, region.end) - addr; + read_len = min(start + len, region.end + 1) - addr; uint8_t *rbuf = buf + addr - start; if (region.read_prot) { if (flash->flags.skip_unreadable_regions) { msg_gdbg("%s: cannot read inside %s region (%#08"PRIx32"..%#08"PRIx32"), " "filling (%#08x..%#08x) with erased value instead.\n", - __func__, region.name, region.start, region.end - 1, + __func__, region.name, region.start, region.end, addr, addr + read_len - 1); free(region.name); @@ -599,12 +612,12 @@ int read_flash(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigne } msg_gerr("%s: cannot read inside %s region (%#08"PRIx32"..%#08"PRIx32").\n", - __func__, region.name, region.start, region.end - 1); + __func__, region.name, region.start, region.end); free(region.name); return -1; } msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is readable, reading range (%#08x..%#08x).\n", - __func__, region.name, region.start, region.end - 1, addr, addr + read_len - 1); + __func__, region.name, region.start, region.end, addr, addr + read_len - 1); free(region.name); read_func_t *read_func = lookup_read_func_ptr(flash->chip); @@ -652,25 +665,25 @@ int verify_range(struct flashctx *flash, const uint8_t *cmpbuf, unsigned int sta for (size_t addr = start; addr < start + len; addr += read_len) { struct flash_region region; get_flash_region(flash, addr, ®ion); - read_len = min(start + len, region.end) - addr; + read_len = min(start + len, region.end + 1) - addr; if ((region.write_prot && flash->flags.skip_unwritable_regions) || (region.read_prot && flash->flags.skip_unreadable_regions)) { msg_gdbg("%s: Skipping verification of %s region (%#08"PRIx32"..%#08"PRIx32")\n", - __func__, region.name, region.start, region.end - 1); + __func__, region.name, region.start, region.end); free(region.name); continue; } if (region.read_prot) { msg_gerr("%s: Verification imposible because %s region (%#08"PRIx32"..%#08"PRIx32") is unreadable.\n", - __func__, region.name, region.start, region.end - 1); + __func__, region.name, region.start, region.end); free(region.name); goto out_free; } msg_gdbg("%s: Verifying %s region (%#08"PRIx32"..%#08"PRIx32")\n", - __func__, region.name, region.start, region.end - 1); + __func__, region.name, region.start, region.end); free(region.name); ret = read_flash(flash, readbuf, addr, read_len); @@ -976,7 +989,9 @@ static int init_default_layout(struct flashctx *flash) } /* special unit-test hook */ +#ifdef FLASHROM_TEST write_func_t *g_test_write_injector; +#endif static write_func_t *lookup_write_func_ptr(const struct flashchip *chip) { @@ -992,7 +1007,9 @@ static write_func_t *lookup_write_func_ptr(const struct flashchip *chip) case WRITE_82802AB: return &write_82802ab; case WRITE_EN29LV640B: return &write_en29lv640b; case EDI_CHIP_WRITE: return &edi_chip_write; +#ifdef FLASHROM_TEST case TEST_WRITE_INJECTOR: return g_test_write_injector; +#endif /* default: total function, 0 indicates no write function set. * We explicitly do not want a default catch-all case in the switch * to ensure unhandled enum's are compiler warnings. @@ -1029,18 +1046,18 @@ int write_flash(struct flashctx *flash, const uint8_t *buf, struct flash_region region; get_flash_region(flash, addr, ®ion); - write_len = min(start + len, region.end) - addr; + write_len = min(start + len, region.end + 1) - addr; const uint8_t *rbuf = buf + addr - start; if (region.write_prot) { msg_gdbg("%s: cannot write inside %s region (%#08"PRIx32"..%#08"PRIx32"), skipping (%#08x..%#08x).\n", - __func__, region.name, region.start, region.end - 1, addr, addr + write_len - 1); + __func__, region.name, region.start, region.end, addr, addr + write_len - 1); free(region.name); continue; } msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is writable, writing range (%#08x..%#08x).\n", - __func__, region.name, region.start, region.end - 1, addr, addr + write_len - 1); + __func__, region.name, region.start, region.end, addr, addr + write_len - 1); write_func_t *write_func = lookup_write_func_ptr(flash->chip); int ret = write_func(flash, rbuf, addr, write_len); @@ -1494,17 +1511,17 @@ static int erase_block(struct flashctx *const flashctx, struct flash_region region; get_flash_region(flashctx, addr, ®ion); - len = min(info->erase_start + erase_len, region.end) - addr; + len = min(info->erase_start + erase_len, region.end + 1) - addr; if (region.write_prot) { msg_gdbg("%s: cannot erase inside %s region (%#08"PRIx32"..%#08"PRIx32"), skipping range (%#08x..%#08x).\n", - __func__, region.name, region.start, region.end - 1, addr, addr + len - 1); + __func__, region.name, region.start, region.end, addr, addr + len - 1); free(region.name); continue; } msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is writable, erasing range (%#08x..%#08x).\n", - __func__, region.name, region.start, region.end - 1, addr, addr + len - 1); + __func__, region.name, region.start, region.end, addr, addr + len - 1); free(region.name); if (erasefn(flashctx, addr, len)) @@ -2092,7 +2109,7 @@ static int unlock_flash_wp(struct flashctx *const flash, warn_out: if (ret) - msg_cerr("Failed to unlock flash status reg with wp support.\n"); + msg_cwarn("Failed to unlock flash status reg with wp support.\n"); return ret; } @@ -2330,8 +2347,31 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co if (verify && !all_skipped) { msg_cinfo("Verifying flash... "); - /* Work around chips which need some time to calm down. */ - programmer_delay(flashctx, 1000*1000); + /* + * Work around chips which "need some time to calm down." + * + * Frankly, it's not 100% clear why this delay is here at all, + * except for a terse message from 2009 of "a few reports where + * verify directly after erase had unpleasant side effects like + * corrupting flash or at least getting incorrect verify + * results". Ideally, if there were a few known problematic + * chips or programmers, we could add quirks flags for those + * specific implementations without penalizing all other + * flashrom users. But alas, we don't know which systems + * experienced those issues. + * + * Out of an extreme abundance of caution, we retain this + * delay, but only for a few non-SPI bus types that were the + * likely prevalent targets at the time. This is a complete + * guess, which conveniently avoids wasting time on common + * BUS_SPI and BUS_PROG systems. + * + * Background thread: + * Subject: RFC: removing 1 second verification delay + * https://mail.coreboot.org/hyperkitty/list/flashrom@flashrom.org/thread/SFV3OJBVVMDKRLI3FQA3DDDGEXJ7W4ED/ + */ + if (flashctx->chip->bustype & (BUS_PARALLEL | BUS_LPC | BUS_FWH)) + programmer_delay(flashctx, 1000*1000); if (verify_all) combine_image_by_layout(flashctx, newcontents, oldcontents); |