summaryrefslogtreecommitdiffstats
path: root/erasure_layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'erasure_layout.c')
-rw-r--r--erasure_layout.c198
1 files changed, 107 insertions, 91 deletions
diff --git a/erasure_layout.c b/erasure_layout.c
index 1dd6b6032..ab54c121a 100644
--- a/erasure_layout.c
+++ b/erasure_layout.c
@@ -238,55 +238,14 @@ static void select_erase_functions(struct flashctx *flashctx, const struct erase
}
}
-/*
- * @brief wrapper to use the erase algorithm
- *
- * @param flashctx flash context
- * @param region_start start address of the region
- * @param region_end end address of the region
- * @param curcontents buffer containg the current contents of the flash
- * @param newcontents buffer containg the new contents of the flash
- * @param erase_layout erase layout
- * @param all_skipped pointer to the flag to chec if any block was erased
- */
-int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff_t region_end,
+static int erase_write_helper(struct flashctx *const flashctx, chipoff_t region_start, chipoff_t region_end,
uint8_t *curcontents, uint8_t *newcontents,
struct erase_layout *erase_layout, bool *all_skipped)
{
const size_t erasefn_count = count_usable_erasers(flashctx);
- int ret = 0;
- size_t i;
- chipoff_t old_start = region_start, old_end = region_end;
- align_region(erase_layout, flashctx, &region_start, &region_end);
-
- uint8_t *old_start_buf = NULL, *old_end_buf = NULL;
- old_start_buf = (uint8_t *)malloc(old_start - region_start);
- if (!old_start_buf) {
- msg_cerr("Not enough memory!\n");
- ret = -1;
- goto _end;
- }
- old_end_buf = (uint8_t *)malloc(region_end - old_end);
- if (!old_end_buf) {
- msg_cerr("Not enough memory!\n");
- ret = -1;
- goto _end;
- }
-
- if (old_start - region_start) {
- read_flash(flashctx, curcontents + region_start, region_start, old_start - region_start);
- memcpy(old_start_buf, newcontents + region_start, old_start - region_start);
- memcpy(newcontents + region_start, curcontents + region_start, old_start - region_start);
- }
- if (region_end - old_end) {
- chipoff_t end_offset = old_end + 1;
- read_flash(flashctx, curcontents + end_offset, end_offset, region_end - old_end);
- memcpy(old_end_buf, newcontents + end_offset, region_end - old_end);
- memcpy(newcontents + end_offset, curcontents + end_offset, region_end - old_end);
- }
// select erase functions
- for (i = 0; i < erase_layout[erasefn_count - 1].block_count; i++) {
+ for (size_t i = 0; i < erase_layout[erasefn_count - 1].block_count; i++) {
if (erase_layout[erasefn_count - 1].layout_list[i].start_addr <= region_end &&
region_start <= erase_layout[erasefn_count - 1].layout_list[i].end_addr)
select_erase_functions(flashctx, erase_layout,
@@ -295,55 +254,25 @@ int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff
region_start, region_end);
}
- for (i = 0; i < erasefn_count; i++) {
+ // erase
+ for (size_t i = 0; i < erasefn_count; i++) {
for (size_t j = 0; j < erase_layout[i].block_count; j++) {
- if (!erase_layout[i].layout_list[j].selected) continue;
+ if (!erase_layout[i].layout_list[j].selected)
+ continue;
- // erase
chipoff_t start_addr = erase_layout[i].layout_list[j].start_addr;
unsigned int block_len = erase_layout[i].layout_list[j].end_addr - start_addr + 1;
const uint8_t erased_value = ERASED_VALUE(flashctx);
// execute erase
erasefunc_t *erasefn = lookup_erase_func_ptr(erase_layout[i].eraser);
- if (!flashctx->flags.skip_unwritable_regions) {
- if (check_for_unwritable_regions(flashctx, start_addr, block_len))
- goto _end;
- }
- unsigned int len;
- for (unsigned int addr = start_addr; addr < start_addr + block_len; addr += len) {
- struct flash_region region;
- get_flash_region(flashctx, addr, &region);
-
- len = min(start_addr + block_len, region.end) - 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);
- 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);
- free(region.name);
-
- if (erasefn(flashctx, addr, len)) {
- ret = -1;
- goto _end;
- }
- if (check_erased_range(flashctx, addr, len)) {
- ret = - 1;
- msg_cerr("ERASE FAILED!\n");
- goto _end;
- }
+ if (erasefn(flashctx, start_addr, block_len)) {
+ return -1;
+ }
+ if (check_erased_range(flashctx, start_addr, block_len)) {
+ return -1;
+ msg_cerr("ERASE FAILED!\n");
}
// adjust curcontents
@@ -363,13 +292,12 @@ int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff
erase_len - start_here, &start_here,
flashctx->chip->gran))) {
// execute write
- ret = write_flash(flashctx,
+ int ret = write_flash(flashctx,
newcontents + region_start + start_here,
region_start + start_here, len_here);
if (ret) {
- msg_cerr("Write failed at %#zx, Abort.\n", i);
- ret = -1;
- goto _end;
+ msg_cerr("Write failed at %#x, Abort.\n", region_start + start_here);
+ return -1;
}
// adjust curcontents
@@ -380,12 +308,100 @@ int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff
*all_skipped = false;
}
+ return 0;
+}
+
+
+/*
+ * @brief wrapper to use the erase algorithm
+ *
+ * @param flashctx flash context
+ * @param region_start start address of the region
+ * @param region_end end address of the region
+ * @param curcontents buffer containg the current contents of the flash
+ * @param newcontents buffer containg the new contents of the flash
+ * @param erase_layout erase layout
+ * @param all_skipped pointer to the flag to chec if any block was erased
+ */
+int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff_t region_end,
+ uint8_t *curcontents, uint8_t *newcontents,
+ struct erase_layout *erase_layout, bool *all_skipped)
+{
+ int ret = 0;
+ chipoff_t old_start = region_start, old_end = region_end;
+ align_region(erase_layout, flashctx, &region_start, &region_end);
+
+ if (!flashctx->flags.skip_unwritable_regions) {
+ if (check_for_unwritable_regions(flashctx, region_start, region_end - region_start + 1))
+ return -1;
+ }
+
+ uint8_t *old_start_buf = NULL, *old_end_buf = NULL;
+ const size_t start_buf_len = old_start - region_start;
+ const size_t end_buf_len = region_end - old_end;
+
+ if (start_buf_len) {
+ old_start_buf = (uint8_t *)malloc(start_buf_len);
+ if (!old_start_buf) {
+ msg_cerr("Not enough memory!\n");
+ ret = -1;
+ goto _end;
+ }
+ read_flash(flashctx, curcontents + region_start, region_start, start_buf_len);
+ memcpy(old_start_buf, newcontents + region_start, start_buf_len);
+ memcpy(newcontents + region_start, curcontents + region_start, start_buf_len);
+ }
+ if (end_buf_len) {
+ chipoff_t end_offset = old_end + 1;
+ old_end_buf = (uint8_t *)malloc(end_buf_len);
+ if (!old_end_buf) {
+ msg_cerr("Not enough memory!\n");
+ ret = -1;
+ goto _end;
+ }
+ read_flash(flashctx, curcontents + end_offset, end_offset, end_buf_len);
+ memcpy(old_end_buf, newcontents + end_offset, end_buf_len);
+ memcpy(newcontents + end_offset, curcontents + end_offset, end_buf_len);
+ }
+
+ unsigned int len;
+ for (unsigned int addr = region_start; addr <= region_end; addr += len) {
+ struct flash_region region;
+ get_flash_region(flashctx, addr, &region);
+ len = min(region_end, region.end) - addr + 1;
+
+ 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);
+
+
+ ret = erase_write_helper(flashctx, addr, addr + len - 1, curcontents, newcontents, erase_layout, all_skipped);
+ if (ret)
+ goto _end;
+ }
_end:
- memcpy(newcontents + region_start, old_start_buf, old_start - region_start);
- memcpy(newcontents + old_end, old_end_buf, region_end - old_end);
+ if (old_start_buf) {
+ memcpy(newcontents + region_start, old_start_buf, start_buf_len);
+ free(old_start_buf);
+ }
- free(old_start_buf);
- free(old_end_buf);
+ if (old_end_buf) {
+ memcpy(newcontents + old_end, old_end_buf, end_buf_len);
+ free(old_end_buf);
+ }
msg_cinfo("Erase/write done from %"PRIx32" to %"PRIx32"\n", region_start, region_end);
return ret;