summaryrefslogtreecommitdiffstats
path: root/layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'layout.c')
-rw-r--r--layout.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/layout.c b/layout.c
index a12eb28..0b9f6e5 100644
--- a/layout.c
+++ b/layout.c
@@ -257,7 +257,28 @@ int normalize_romentries(const struct flashctx *flash)
return ret;
}
-int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
+static int copy_old_content(struct flashctx *flash, int oldcontents_valid, uint8_t *oldcontents, uint8_t *newcontents, unsigned int start, unsigned int size)
+{
+ if (!oldcontents_valid) {
+ /* oldcontents is a zero-filled buffer. By reading the current data into oldcontents here, we
+ * avoid a rewrite of identical regions even if an initial full chip read didn't happen. */
+ msg_gdbg2("Read a chunk starting at 0x%06x (len=0x%06x).\n", start, size);
+ int ret = flash->chip->read(flash, oldcontents + start, start, size);
+ if (ret != 0) {
+ msg_gerr("Failed to read chunk 0x%06x-0x%06x.\n", start, start + size - 1);
+ return 1;
+ }
+ }
+ memcpy(newcontents + start, oldcontents + start, size);
+ return 0;
+}
+
+/**
+ * Modify @newcontents so that it contains the data that should be on the chip eventually. In the case the user
+ * wants to update only parts of it, copy the chunks to be preserved from @oldcontents to @newcontents. If
+ * @oldcontents is not valid, we need to fetch the current data from the chip first.
+ */
+int build_new_image(struct flashctx *flash, bool oldcontents_valid, uint8_t *oldcontents, uint8_t *newcontents)
{
unsigned int start = 0;
romentry_t *entry;
@@ -276,14 +297,14 @@ int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t
entry = get_next_included_romentry(start);
/* No more romentries for remaining region? */
if (!entry) {
- memcpy(newcontents + start, oldcontents + start,
- size - start);
+ copy_old_content(flash, oldcontents_valid, oldcontents, newcontents, start,
+ size - start);
break;
}
/* For non-included region, copy from old content. */
if (entry->start > start)
- memcpy(newcontents + start, oldcontents + start,
- entry->start - start);
+ copy_old_content(flash, oldcontents_valid, oldcontents, newcontents, start,
+ entry->start - start);
/* Skip to location after current romentry. */
start = entry->end + 1;
/* Catch overflow. */
OpenPOWER on IntegriCloud