flashrom.c: Integrate new erase-function selection
This requires almost a rewrite of walk_eraseblocks(): Instead of walking
all blocks for a given function, we walk the presented erase layout.
However, the overall structure stays the same.
walk_by_layout() now runs the new erase-function selection per region
to present walk_eraseblocks() the new erase layout.
Change-Id: I2535f211c49d050d21983cadb4df5005fa2e5659
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/72562
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/flashrom.c b/flashrom.c
index a2d0e90..1301f04 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1009,8 +1009,7 @@
* of the flash chip. This helps to optimally select the erase functions for
* erase/write operations.
*/
-int create_erase_layout(struct flashctx *const flashctx, struct erase_layout **e_layout);
-int create_erase_layout(struct flashctx *const flashctx, struct erase_layout **e_layout)
+static int create_erase_layout(struct flashctx *const flashctx, struct erase_layout **e_layout)
{
const struct flashchip *chip = flashctx->chip;
const size_t erasefn_count = count_usable_erasers(flashctx);
@@ -1117,9 +1116,7 @@
}
}
-void select_erase_functions(const struct flashctx *flashctx, const struct erase_layout *layout,
- size_t erasefn_count, const struct walk_info *info);
-void select_erase_functions(const struct flashctx *flashctx, const struct erase_layout *layout,
+static void select_erase_functions(const struct flashctx *flashctx, const struct erase_layout *layout,
size_t erasefn_count, const struct walk_info *info)
{
size_t block_num;
@@ -1154,51 +1151,45 @@
typedef int (*per_blockfn_t)(struct flashctx *, const struct walk_info *, erasefn_t);
static int walk_eraseblocks(struct flashctx *const flashctx,
+ struct erase_layout *const layouts,
+ const size_t layout_count,
struct walk_info *const info,
- const size_t erasefunction, const per_blockfn_t per_blockfn)
+ const per_blockfn_t per_blockfn)
{
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;
+ for (i = 0; i < layout_count; ++i) {
+ const struct erase_layout *const layout = &layouts[i];
- /* 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)
+ for (j = 0; j < layout->block_count; ++j) {
+ struct eraseblock_data *const eb = &layout->layout_list[j];
+
+ if (eb->start_addr > info->region_end)
break;
-
- /* Check if we want to erase this block. */
- if (!explicit_erase(info)) {
- const chipoff_t write_start = MAX(info->region_start, info->erase_start);
- const chipoff_t write_end = MIN(info->region_end, info->erase_end);
- const chipsize_t write_len = write_end + 1 - write_start;
- if (!need_erase(info->curcontents + write_start,
- info->newcontents + write_start,
- write_len, flashctx->chip->gran, ERASED_VALUE(flashctx)))
- continue;
- }
+ if (eb->end_addr < info->region_start)
+ continue;
+ if (!eb->selected)
+ continue;
/* Print this for every block except the first one. */
if (first)
first = false;
else
msg_cdbg(", ");
- msg_cdbg("0x%06x-0x%06x:", info->erase_start, info->erase_end);
+ msg_cdbg("0x%06x-0x%06x:", eb->start_addr, eb->end_addr);
- ret = per_blockfn(flashctx, info, eraser->block_erase);
+ info->erase_start = eb->start_addr;
+ info->erase_end = eb->end_addr;
+ ret = per_blockfn(flashctx, info, layout->eraser->block_erase);
if (ret)
return ret;
+
+ /* Clean the erase layout up for future use on other
+ regions. `.selected` is the only field we alter. */
+ eb->selected = false;
}
- if (info->region_end < info->erase_start)
- break;
}
msg_cdbg("\n");
return 0;
@@ -1207,46 +1198,44 @@
static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *const info,
const per_blockfn_t per_blockfn)
{
+ const bool do_erase = explicit_erase(info) || !(flashctx->chip->feature_bits & FEATURE_NO_ERASE);
const struct flashrom_layout *const layout = get_layout(flashctx);
+ struct erase_layout *erase_layouts = NULL;
const struct romentry *entry = NULL;
+ int ret = 0, layout_count = 0;
all_skipped = true;
msg_cinfo("Erasing and writing flash chip... ");
+ if (do_erase) {
+ layout_count = create_erase_layout(flashctx, &erase_layouts);
+ if (layout_count <= 0)
+ return 1;
+ }
+
while ((entry = layout_next_included(layout, entry))) {
info->region_start = entry->start;
info->region_end = entry->end;
- if (!(flashctx->chip->feature_bits & FEATURE_NO_ERASE) || explicit_erase(info)) {
- size_t j;
- 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))
- break;
- }
-
- if (j == NUM_ERASEFUNCTIONS) {
- msg_cinfo("No usable erase function found.\n");
- return 1;
- }
-
- if (walk_eraseblocks(flashctx, info, j, per_blockfn)) {
+ if (do_erase) {
+ select_erase_functions(flashctx, erase_layouts, layout_count, info);
+ ret = walk_eraseblocks(flashctx, erase_layouts, layout_count, info, per_blockfn);
+ if (ret) {
msg_cerr("FAILED!\n");
- return 1;
+ goto free_ret;
}
}
if (info->newcontents) {
bool skipped = true;
msg_cdbg("0x%06x-0x%06x:", info->region_start, info->region_end);
- if (write_range(flashctx, info->region_start,
- info->curcontents + info->region_start,
- info->newcontents + info->region_start,
- info->region_end + 1 - info->region_start, &skipped)) {
+ ret = write_range(flashctx, info->region_start,
+ info->curcontents + info->region_start,
+ info->newcontents + info->region_start,
+ info->region_end + 1 - info->region_start, &skipped);
+ if (ret) {
msg_cerr("FAILED!\n");
- return 1;
+ goto free_ret;
}
if (skipped) {
msg_cdbg("S\n");
@@ -1259,7 +1248,10 @@
if (all_skipped)
msg_cinfo("\nWarning: Chip content is identical to the requested image.\n");
msg_cinfo("Erase/write done.\n");
- return 0;
+
+free_ret:
+ free_erase_layout(erase_layouts, layout_count);
+ return ret;
}
static int erase_block(struct flashctx *const flashctx,