summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Huber <nico.huber@secunet.com>2019-01-23 17:07:49 +0100
committerNico Huber <nico.h@gmx.de>2019-03-04 15:04:00 +0000
commita3db7ed513f2ec3c9d34a22d7c5c829d3d410dc2 (patch)
tree8f655b24952d70b724173ee45a2eb8ac2fd42342
parent69f96f60295d82ac9525fbd20aa94a3d86c2904c (diff)
downloadflashrom-1.0.1-rc2.tar.gz
flashrom-1.0.1-rc2.tar.bz2
flashrom-1.0.1-rc2.zip
Fix erasing of unaligned regionsv1.0.1-rc2v1.0.1
The erase (-E) feature is somehow a brute force method, but still, if we are given a region to erase, we should make sure to restore surrounding data if the erase block expands beyond the region. Slight alteration from `master` commit: Guard free() from NULL pointers to be regression safe even in case of broken libc. Change-Id: I5fc35310f0b090f218cd1d660e27fb39dd05c3c5 Signed-off-by: Nico Huber <nico.huber@secunet.com> Reviewed-on: https://review.coreboot.org/c/31069 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de>
-rw-r--r--flashrom.c71
1 files changed, 68 insertions, 3 deletions
diff --git a/flashrom.c b/flashrom.c
index 1a7dfb10b..51f97214f 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1690,17 +1690,82 @@ static int erase_block(struct flashctx *const flashctx,
const struct walk_info *const info, const erasefn_t erasefn)
{
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, 0xff, erase_len);
+ memset(erased_contents, 0xff, 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 (flashctx->chip->read(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 (flashctx->chip->read(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 (erasefn(flashctx, info->erase_start, erase_len))
- return 1;
+ goto _free_ret;
if (check_erased_range(flashctx, info->erase_start, erase_len)) {
msg_cerr("ERASE FAILED!\n");
- return 1;
+ goto _free_ret;
}
- return 0;
+
+ 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 (flashctx->chip->write(flashctx, backup_contents + starthere,
+ info->erase_start + starthere, lenhere))
+ goto _free_ret;
+ starthere += lenhere;
+ }
+ }
+
+ ret = 0;
+
+_free_ret:
+ if (erased_contents != NULL)
+ free(erased_contents);
+ if (backup_contents != NULL)
+ free(backup_contents);
+ return ret;
}
/**