diff options
Diffstat (limited to 'erasure_layout.c')
-rw-r--r-- | erasure_layout.c | 198 |
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, ®ion_start, ®ion_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, ®ion); - - 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, ®ion_start, ®ion_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, ®ion); + 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; |