1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-26 22:52:34 +02:00

flashrom.c: Delete legacy erase and write logic

Current code path for erase and write has been enabled in the tree
since May 2023, which is more than 1 year ago (15 months ago),
and legacy path has been disabled since the same time.

Current logic has been officially released in v1.4.0 in July 2024.

Change-Id: I08fd686fecf6a5313eea2d66b368661c664f4800
Signed-off-by: Anastasia Klimchuk <aklm@flashrom.org>
Reviewed-on: https://review.coreboot.org/c/flashrom/+/83846
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aarya <aarya.chaumal@gmail.com>
Reviewed-by: Peter Marheine <pmarheine@chromium.org>
This commit is contained in:
Anastasia Klimchuk 2024-08-09 19:31:11 +10:00
parent 213fdb0f9f
commit 5ddd3b55fc
2 changed files with 1 additions and 369 deletions

View File

@ -151,7 +151,7 @@ int create_erase_layout(struct flashctx *const flashctx, struct erase_layout **e
* @param region_start pointer to start address of the region to align
* @param region_end pointer to end address of the region to align
*
* This function aligns start and end address of the region (in struct walk_info)
* This function aligns start and end address of the region
* to some erase sector boundaries and modify the region start and end addresses
* to match nearest erase sector boundaries. This function will be used in the
* new algorithm for erase function selection.

View File

@ -36,8 +36,6 @@
#include "chipdrivers.h"
#include "erasure_layout.h"
static bool use_legacy_erase_path = false;
const char flashrom_version[] = FLASHROM_VERSION;
static const struct programmer_entry *programmer = NULL;
@ -1329,250 +1327,6 @@ static int selfcheck_eraseblocks(const struct flashchip *chip)
return ret;
}
typedef int (*erasefn_t)(struct flashctx *, unsigned int addr, unsigned int len);
/**
* @private
*
* For read-erase-write, `curcontents` and `newcontents` shall point
* to buffers of the chip's size. Both are supposed to be prefilled
* with at least the included layout regions of the current flash
* contents (`curcontents`) and the data to be written to the flash
* (`newcontents`).
*
* For erase, `curcontents` and `newcontents` shall be NULL-pointers.
*
* The `chipoff_t` values are used internally by `walk_by_layout()`.
*/
struct walk_info {
uint8_t *curcontents;
const uint8_t *newcontents;
chipoff_t region_start;
chipoff_t region_end;
chipoff_t erase_start;
chipoff_t erase_end;
};
/* returns 0 on success, 1 to retry with another erase function, 2 for immediate abort */
typedef int (*per_blockfn_t)(struct flashctx *, const struct walk_info *, erasefn_t, bool *);
static int walk_eraseblocks(struct flashctx *const flashctx,
struct walk_info *const info,
const size_t erasefunction, const per_blockfn_t per_blockfn,
bool *all_skipped)
{
int ret;
size_t i, j;
bool first = true;
struct block_eraser *const eraser = &flashctx->chip->block_erasers[erasefunction];
info->erase_start = 0;
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. */
for (j = 0; j < eraser->eraseblocks[i].count; ++j, info->erase_start = info->erase_end + 1) {
info->erase_end = info->erase_start + eraser->eraseblocks[i].size - 1;
/* Skip any eraseblock that is completely outside the current region. */
if (info->erase_end < info->region_start)
continue;
if (info->region_end < info->erase_start)
break;
/* Print this for every block except the first one. */
if (first)
first = false;
else
msg_cdbg(", ");
msg_cdbg("0x%06"PRIx32"-0x%06"PRIx32":", info->erase_start, info->erase_end);
erasefunc_t *erase_func = lookup_erase_func_ptr(eraser);
ret = per_blockfn(flashctx, info, erase_func, all_skipped);
if (ret)
return ret;
}
if (info->region_end < info->erase_start)
break;
}
msg_cdbg("\n");
return 0;
}
static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *const info,
const per_blockfn_t per_blockfn, bool *all_skipped)
{
const struct flashrom_layout *const layout = get_layout(flashctx);
const struct romentry *entry = NULL;
*all_skipped = true;
msg_cinfo("Erasing and writing flash chip... ");
while ((entry = layout_next_included(layout, entry))) {
const struct flash_region *region = &entry->region;
info->region_start = region->start;
info->region_end = region->end;
size_t j;
int error = 1; /* retry as long as it's 1 */
for (j = 0; j < NUM_ERASEFUNCTIONS; ++j) {
if (j != 0)
msg_cinfo("Looking for another erase function.\n");
msg_cdbg("Trying erase function %zi... ", j);
if (check_block_eraser(flashctx, j, 1))
continue;
error = walk_eraseblocks(flashctx, info, j, per_blockfn, all_skipped);
if (error != 1)
break;
if (info->curcontents) {
msg_cinfo("Reading current flash chip contents... ");
if (read_by_layout(flashctx, info->curcontents)) {
/* 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. */
error = 2;
break;
}
msg_cinfo("done. ");
}
}
if (error == 1)
msg_cinfo("No usable erase functions left.\n");
if (error) {
msg_cerr("FAILED!\n");
return 1;
}
}
if (*all_skipped)
msg_cinfo("\nWarning: Chip content is identical to the requested image.\n");
msg_cinfo("Erase/write done.\n");
return 0;
}
static int erase_block(struct flashctx *const flashctx,
const struct walk_info *const info, const erasefn_t erasefn,
bool *all_skipped)
{
const unsigned int erase_len = info->erase_end + 1 - info->erase_start;
const bool region_unaligned = info->region_start > info->erase_start ||
info->erase_end > info->region_end;
uint8_t *backup_contents = NULL, *erased_contents = NULL;
int ret = 2;
/*
* If the region is not erase-block aligned, merge current flash con-
* tents into a new buffer `backup_contents`.
*/
if (region_unaligned) {
backup_contents = malloc(erase_len);
erased_contents = malloc(erase_len);
if (!backup_contents || !erased_contents) {
msg_cerr("Out of memory!\n");
ret = 1;
goto _free_ret;
}
memset(backup_contents, ERASED_VALUE(flashctx), erase_len);
memset(erased_contents, ERASED_VALUE(flashctx), erase_len);
msg_cdbg("R");
/* Merge data preceding the current region. */
if (info->region_start > info->erase_start) {
const chipoff_t start = info->erase_start;
const chipsize_t len = info->region_start - info->erase_start;
if (read_flash(flashctx, backup_contents, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
}
/* Merge data following the current region. */
if (info->erase_end > info->region_end) {
const chipoff_t start = info->region_end + 1;
const chipoff_t rel_start = start - info->erase_start; /* within this erase block */
const chipsize_t len = info->erase_end - info->region_end;
if (read_flash(flashctx, backup_contents + rel_start, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
}
}
ret = 1;
*all_skipped = false;
msg_cdbg("E");
if (!flashctx->flags.skip_unwritable_regions) {
if (check_for_unwritable_regions(flashctx, info->erase_start, erase_len))
goto _free_ret;
}
unsigned int len;
for (unsigned int addr = info->erase_start; addr < info->erase_start + erase_len; addr += len) {
struct flash_region region;
get_flash_region(flashctx, addr, &region);
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, 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, addr, addr + len - 1);
free(region.name);
if (erasefn(flashctx, addr, len))
goto _free_ret;
if (check_erased_range(flashctx, addr, len)) {
msg_cerr("ERASE FAILED!\n");
goto _free_ret;
}
}
if (region_unaligned) {
unsigned int starthere = 0, lenhere = 0, writecount = 0;
/* get_next_write() sets starthere to a new value after the call. */
while ((lenhere = get_next_write(erased_contents + starthere, backup_contents + starthere,
erase_len - starthere, &starthere, flashctx->chip->gran))) {
if (!writecount++)
msg_cdbg("W");
/* Needs the partial write function signature. */
if (write_flash(flashctx, backup_contents + starthere,
info->erase_start + starthere, lenhere))
goto _free_ret;
starthere += lenhere;
}
}
ret = 0;
_free_ret:
free(erased_contents);
free(backup_contents);
return ret;
}
/**
* @brief Erases the included layout regions.
*
* If there is no layout set in the given flash context, the whole chip will
* be erased.
*
* @param flashctx Flash context to be used.
* @return 0 on success,
* 1 if all available erase functions failed.
*/
static int erase_by_layout_legacy(struct flashctx *const flashctx)
{
struct walk_info info = { 0 };
bool all_skipped = true;
return walk_by_layout(flashctx, &info, &erase_block, &all_skipped);
}
static int erase_by_layout_new(struct flashctx *const flashctx)
{
bool all_skipped = true;
@ -1618,129 +1372,9 @@ _ret:
static int erase_by_layout(struct flashctx *const flashctx)
{
if (use_legacy_erase_path)
return erase_by_layout_legacy(flashctx);
return erase_by_layout_new(flashctx);
}
static int read_erase_write_block(struct flashctx *const flashctx,
const struct walk_info *const info, const erasefn_t erasefn,
bool *all_skipped)
{
const chipsize_t erase_len = info->erase_end + 1 - info->erase_start;
const bool region_unaligned = info->region_start > info->erase_start ||
info->erase_end > info->region_end;
const uint8_t *newcontents = NULL;
int ret = 2;
/*
* If the region is not erase-block aligned, merge current flash con-
* tents into `info->curcontents` and a new buffer `newc`. The former
* is necessary since we have no guarantee that the full erase block
* was already read into `info->curcontents`. For the latter a new
* buffer is used since `info->newcontents` might contain data for
* other unaligned regions that touch this erase block too.
*/
if (region_unaligned) {
msg_cdbg("R");
uint8_t *const newc = malloc(erase_len);
if (!newc) {
msg_cerr("Out of memory!\n");
return 1;
}
memcpy(newc, info->newcontents + info->erase_start, erase_len);
/* Merge data preceding the current region. */
if (info->region_start > info->erase_start) {
const chipoff_t start = info->erase_start;
const chipsize_t len = info->region_start - info->erase_start;
if (read_flash(flashctx, newc, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
memcpy(info->curcontents + start, newc, len);
}
/* Merge data following the current region. */
if (info->erase_end > info->region_end) {
const chipoff_t start = info->region_end + 1;
const chipoff_t rel_start = start - info->erase_start; /* within this erase block */
const chipsize_t len = info->erase_end - info->region_end;
if (read_flash(flashctx, newc + rel_start, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
memcpy(info->curcontents + start, newc + rel_start, len);
}
newcontents = newc;
} else {
newcontents = info->newcontents + info->erase_start;
}
ret = 1;
bool skipped = true;
uint8_t *const curcontents = info->curcontents + info->erase_start;
const uint8_t erased_value = ERASED_VALUE(flashctx);
if (!(flashctx->chip->feature_bits & FEATURE_NO_ERASE) &&
need_erase(curcontents, newcontents, erase_len, flashctx->chip->gran, erased_value)) {
if (erase_block(flashctx, info, erasefn, all_skipped))
goto _free_ret;
/* Erase was successful. Adjust curcontents. */
memset(curcontents, erased_value, erase_len);
skipped = false;
}
unsigned int starthere = 0, lenhere = 0, writecount = 0;
/* get_next_write() sets starthere to a new value after the call. */
while ((lenhere = get_next_write(curcontents + starthere, newcontents + starthere,
erase_len - starthere, &starthere, flashctx->chip->gran))) {
if (!writecount++)
msg_cdbg("W");
/* Needs the partial write function signature. */
if (write_flash(flashctx, newcontents + starthere,
info->erase_start + starthere, lenhere))
goto _free_ret;
starthere += lenhere;
skipped = false;
}
if (skipped)
msg_cdbg("S");
else
*all_skipped = false;
/* Update curcontents, other regions with overlapping erase blocks
might rely on this. */
memcpy(curcontents, newcontents, erase_len);
ret = 0;
_free_ret:
if (region_unaligned)
free((void *)newcontents);
return ret;
}
/**
* @brief Writes the included layout regions from a given image.
*
* If there is no layout set in the given flash context, the whole image
* will be written.
*
* @param flashctx Flash context to be used.
* @param curcontents A buffer of full chip size with current chip contents of included regions.
* @param newcontents The new image to be written.
* @return 0 on success,
* 1 if anything has gone wrong.
*/
static int write_by_layout_legacy(struct flashctx *const flashctx,
void *const curcontents, const void *const newcontents,
bool *all_skipped)
{
struct walk_info info;
info.curcontents = curcontents;
info.newcontents = newcontents;
return walk_by_layout(flashctx, &info, read_erase_write_block, all_skipped);
}
static int write_by_layout_new(struct flashctx *const flashctx,
void *const curcontents, const void *const newcontents,
bool *all_skipped)
@ -1780,8 +1414,6 @@ static int write_by_layout(struct flashctx *const flashctx,
uint8_t *const curcontents, const uint8_t *const newcontents,
bool *all_skipped)
{
if (use_legacy_erase_path)
return write_by_layout_legacy(flashctx, curcontents, newcontents, all_skipped);
return write_by_layout_new(flashctx, curcontents, newcontents, all_skipped);
}