Skip to content

Commit a0e08ff

Browse files
committed
espressif: flash: refactor force aligned write and erase algorithms
Refactor force aligned write and erase algorithms to improve readability. Signed-off-by: Almir Okato <[email protected]>
1 parent 4302112 commit a0e08ff

File tree

1 file changed

+103
-94
lines changed

1 file changed

+103
-94
lines changed

boot/espressif/port/esp_mcuboot.c

Lines changed: 103 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -257,65 +257,66 @@ static bool aligned_flash_write(size_t dest_addr, const void *src, size_t size,
257257

258258
if (flash_encryption_enabled && erase) {
259259
if (bootloader_flash_erase_range(dest_addr, size) != ESP_OK) {
260+
BOOT_LOG_ERR("%s: Flash erase failed at 0x%08x", __func__, (uint32_t)dest_addr);
260261
return false;
261262
}
263+
flush_cache(dest_addr, size);
262264
}
263-
return bootloader_flash_write(dest_addr, (void *)src, size, flash_encryption_enabled) == ESP_OK;
264-
}
265-
BOOT_LOG_DBG("%s: forcing unaligned write dest_addr: 0x%08x src: 0x%08x size: 0x%x erase: %c",
266-
__func__, (uint32_t)dest_addr, (uint32_t)src, size, erase ? 't' : 'f');
267-
268-
const uint32_t aligned_addr = ALIGN_DOWN(dest_addr, alignment);
269-
const uint32_t addr_offset = ALIGN_OFFSET(dest_addr, alignment);
270-
uint32_t bytes_remaining = size;
271-
uint8_t write_data[FLASH_SECTOR_SIZE] __attribute__((aligned(32))) = {0};
272-
273-
/* Perform a read operation considering an offset not aligned to 4-byte boundary */
274265

275-
uint32_t bytes = MIN(bytes_remaining + addr_offset, sizeof(write_data));
276-
if (bootloader_flash_read(aligned_addr, write_data, ALIGN_UP(bytes, alignment), true) != ESP_OK) {
277-
return false;
278-
}
279-
280-
if (flash_encryption_enabled && erase) {
281-
if (bootloader_flash_erase_range(aligned_addr, ALIGN_UP(bytes, FLASH_SECTOR_SIZE)) != ESP_OK) {
266+
if (bootloader_flash_write(dest_addr, (void *)src, size, flash_encryption_enabled) == ESP_OK) {
267+
flush_cache(dest_addr, size);
268+
return true;
269+
} else {
270+
BOOT_LOG_ERR("%s: Flash write failed at 0x%08x", __func__, (uint32_t)dest_addr);
282271
return false;
283272
}
284273
}
285-
uint32_t bytes_written = bytes - addr_offset;
286-
memcpy(&write_data[addr_offset], src, bytes_written);
287-
288-
if (bootloader_flash_write(aligned_addr, write_data, ALIGN_UP(bytes, alignment), flash_encryption_enabled) != ESP_OK) {
289-
return false;
290-
}
274+
BOOT_LOG_DBG("%s: forcing unaligned write dest_addr: 0x%08x src: 0x%08x size: 0x%x erase: %c",
275+
__func__, (uint32_t)dest_addr, (uint32_t)src, size, erase ? 't' : 'f');
291276

292-
bytes_remaining -= bytes_written;
277+
uint8_t write_aux_buf[FLASH_SECTOR_SIZE] __attribute__((aligned(32))) = {0};
293278

294-
/* Write remaining data to Flash if any */
279+
size_t write_addr = dest_addr;
280+
size_t bytes_remaining = size;
281+
size_t src_offset = 0;
295282

296-
uint32_t offset = bytes;
283+
while (bytes_remaining > 0) {
284+
size_t aligned_curr_addr = ALIGN_DOWN(write_addr, alignment);
285+
size_t curr_buf_off = write_addr - aligned_curr_addr;
286+
size_t chunk_len = MIN(bytes_remaining, FLASH_SECTOR_SIZE - curr_buf_off);
297287

298-
while (bytes_remaining != 0) {
299-
bytes = MIN(bytes_remaining, sizeof(write_data));
300-
if (bootloader_flash_read(aligned_addr + offset, write_data, ALIGN_UP(bytes, alignment), true) != ESP_OK) {
288+
/* Read data before modifying */
289+
if (bootloader_flash_read(aligned_curr_addr, write_aux_buf,
290+
ALIGN_UP(chunk_len, alignment), true) != ESP_OK) {
291+
BOOT_LOG_ERR("%s: Flash read failed at 0x%08x", __func__, (uint32_t)aligned_curr_addr);
301292
return false;
302293
}
303294

295+
/* Erase if needed */
304296
if (flash_encryption_enabled && erase) {
305-
if (bootloader_flash_erase_range(aligned_addr + offset, ALIGN_UP(bytes, FLASH_SECTOR_SIZE)) != ESP_OK) {
297+
if (bootloader_flash_erase_range(aligned_curr_addr,
298+
ALIGN_UP(chunk_len, FLASH_SECTOR_SIZE)) != ESP_OK) {
299+
BOOT_LOG_ERR("%s: Flash erase failed at 0x%08x", __func__, (uint32_t)aligned_curr_addr);
306300
return false;
307301
}
302+
flush_cache(aligned_curr_addr, ALIGN_UP(chunk_len, FLASH_SECTOR_SIZE));
308303
}
309304

310-
memcpy(write_data, &((uint8_t *)src)[bytes_written], bytes);
305+
/* Merge data into buffer */
306+
memcpy(&write_aux_buf[curr_buf_off], &((uint8_t *)src)[src_offset], chunk_len);
311307

312-
if (bootloader_flash_write(aligned_addr + offset, write_data, ALIGN_UP(bytes, alignment), flash_encryption_enabled) != ESP_OK) {
308+
/* Write back aligned chunk */
309+
if (bootloader_flash_write(aligned_curr_addr, write_aux_buf,
310+
ALIGN_UP(chunk_len, alignment),
311+
flash_encryption_enabled) != ESP_OK) {
312+
BOOT_LOG_ERR("%s: Flash write failed at 0x%08x", __func__, (uint32_t)aligned_curr_addr);
313313
return false;
314314
}
315+
flush_cache(aligned_curr_addr, ALIGN_UP(chunk_len, alignment));
315316

316-
offset += bytes;
317-
bytes_written += bytes;
318-
bytes_remaining -= bytes;
317+
write_addr += chunk_len;
318+
src_offset += chunk_len;
319+
bytes_remaining -= chunk_len;
319320
}
320321

321322
return true;
@@ -326,68 +327,82 @@ static bool aligned_flash_erase(size_t addr, size_t size)
326327
if (IS_ALIGNED(addr, FLASH_SECTOR_SIZE) && IS_ALIGNED(size, FLASH_SECTOR_SIZE)) {
327328
/* A single erase operation is enough when all parameters are aligned */
328329

329-
return bootloader_flash_erase_range(addr, size) == ESP_OK;
330-
}
331-
BOOT_LOG_DBG("%s: forcing unaligned erase on sector Offset: 0x%x Length: 0x%x",
332-
__func__, (int)addr, (int)size);
333-
334-
const uint32_t aligned_addr = ALIGN_DOWN(addr, FLASH_SECTOR_SIZE);
335-
const uint32_t addr_offset = ALIGN_OFFSET(addr, FLASH_SECTOR_SIZE);
336-
uint32_t bytes_remaining = size;
337-
uint8_t write_data[FLASH_SECTOR_SIZE] __attribute__((aligned(32))) = {0};
338-
339-
/* Perform a read operation considering an offset not aligned */
340-
341-
uint32_t bytes = MIN(bytes_remaining + addr_offset, sizeof(write_data));
342-
343-
if (bootloader_flash_read(aligned_addr, write_data, ALIGN_UP(bytes, FLASH_SECTOR_SIZE), true) != ESP_OK) {
344-
return false;
345-
}
346-
347-
if (bootloader_flash_erase_range(aligned_addr, ALIGN_UP(bytes, FLASH_SECTOR_SIZE)) != ESP_OK) {
348-
return false;
349-
}
350-
351-
uint32_t bytes_written = bytes - addr_offset;
352-
353-
/* Write first part of non-erased data */
354-
if(addr_offset > 0) {
355-
if (!aligned_flash_write(aligned_addr, write_data, addr_offset, false)) {
356-
return false;
357-
}
358-
}
359-
360-
if(bytes < sizeof(write_data)) {
361-
if (!aligned_flash_write(aligned_addr + bytes, write_data + bytes, sizeof(write_data) - bytes, false)) {
330+
if (bootloader_flash_erase_range(addr, size) == ESP_OK) {
331+
flush_cache(addr, size);
332+
return true;
333+
} else {
334+
BOOT_LOG_ERR("%s: Flash erase failed at 0x%08x", __func__, (uint32_t)addr);
362335
return false;
363336
}
364337
}
365338

366-
bytes_remaining -= bytes_written;
367-
368-
/* Write remaining data to Flash if any */
339+
const size_t sector_size = FLASH_SECTOR_SIZE;
340+
const size_t start_addr = ALIGN_DOWN(addr, sector_size);
341+
const size_t end_addr = ALIGN_UP(addr + size, sector_size);
342+
const size_t total_len = end_addr - start_addr;
343+
344+
BOOT_LOG_DBG("%s: forcing unaligned erase on sector Offset: 0x%08x Length: 0x%x total_len: 0x%x",
345+
__func__, (uint32_t)addr, (int)size, total_len);
346+
347+
uint8_t erase_aux_buf[FLASH_SECTOR_SIZE] __attribute__((aligned(32))) = {0};
348+
size_t current_addr = start_addr;
349+
while (current_addr < end_addr) {
350+
bool preserve_head = (addr > current_addr);
351+
bool preserve_tail = ((addr + size) < (current_addr + sector_size));
352+
353+
if (preserve_head || preserve_tail) {
354+
/* Read full sector before erasing */
355+
if (bootloader_flash_read(current_addr, erase_aux_buf, sector_size, true) != ESP_OK) {
356+
BOOT_LOG_ERR("%s: Flash read failed at 0x%08x", __func__, (uint32_t)current_addr);
357+
return false;
358+
}
369359

370-
uint32_t offset = bytes;
360+
/* Calculate the range of the erase: data between erase_start and erase_end
361+
* will not be written back
362+
*/
363+
size_t erase_start = (addr > current_addr) ? (addr - current_addr) : 0;
364+
size_t erase_end = MIN(current_addr + sector_size, addr + size) - current_addr;
371365

372-
while (bytes_remaining != 0) {
373-
bytes = MIN(bytes_remaining, sizeof(write_data));
374-
if (bootloader_flash_read(aligned_addr + offset, write_data, ALIGN_UP(bytes, FLASH_SECTOR_SIZE), true) != ESP_OK) {
375-
return false;
376-
}
366+
BOOT_LOG_INF("%s: partial sector erase from: 0x%08x to: 0x%08x Length: 0x%x",
367+
__func__, (uint32_t)(current_addr + erase_start),
368+
(uint32_t)(current_addr + erase_end), erase_end - erase_start);
377369

378-
if (bootloader_flash_erase_range(aligned_addr + offset, ALIGN_UP(bytes, FLASH_SECTOR_SIZE)) != ESP_OK) {
379-
return false;
380-
}
370+
/* Erase full sector */
371+
if (bootloader_flash_erase_range(current_addr, sector_size) != ESP_OK) {
372+
BOOT_LOG_ERR("%s: Flash erase failed at 0x%08x", __func__, (uint32_t)current_addr);
373+
return false;
374+
}
375+
flush_cache(current_addr, sector_size);
376+
377+
if (preserve_head) {
378+
/* Write back preserved head data up to erase_start */
379+
if (!aligned_flash_write(current_addr, erase_aux_buf, erase_start, false)) {
380+
BOOT_LOG_ERR("%s: Flash write failed at 0x%08x", __func__, (uint32_t)current_addr);
381+
return false;
382+
}
383+
}
381384

382-
if(bytes < sizeof(write_data)) {
383-
if (!aligned_flash_write(aligned_addr + offset + bytes, write_data + bytes, sizeof(write_data) - bytes, false)) {
385+
if (preserve_tail) {
386+
/* Write back preserved tail data from erase_end up to sector end */
387+
if (!aligned_flash_write(current_addr + erase_end, &erase_aux_buf[erase_end], sector_size - erase_end, false)) {
388+
BOOT_LOG_ERR("%s: Flash write failed at 0x%08x", __func__, (uint32_t)current_addr + erase_end);
389+
return false;
390+
}
391+
}
392+
current_addr += sector_size;
393+
} else {
394+
/* Full sector erase is safe, erase the next consecutive full sectors */
395+
size_t contiguous_size = ALIGN_DOWN(addr + size, sector_size) - current_addr;
396+
BOOT_LOG_DBG("%s: sectors erased from: 0x%08x length: 0x%x",
397+
__func__, (uint32_t)current_addr, contiguous_size);
398+
if (bootloader_flash_erase_range(current_addr, contiguous_size) != ESP_OK) {
399+
BOOT_LOG_ERR("%s: Flash erase failed at 0x%08x", __func__, (uint32_t)current_addr);
384400
return false;
385401
}
386-
}
402+
flush_cache(current_addr, contiguous_size);
387403

388-
offset += bytes;
389-
bytes_written += bytes;
390-
bytes_remaining -= bytes;
404+
current_addr += contiguous_size;
405+
}
391406
}
392407

393408
return true;
@@ -424,8 +439,6 @@ int flash_area_write(const struct flash_area *fa, uint32_t off, const void *src,
424439
return -1;
425440
}
426441

427-
flush_cache(start_addr, len);
428-
429442
return 0;
430443
}
431444

@@ -438,13 +451,11 @@ int flash_area_erase(const struct flash_area *fa, uint32_t off, uint32_t len)
438451
const uint32_t start_addr = fa->fa_off + off;
439452
BOOT_LOG_DBG("%s: Addr: 0x%08x Length: %d (0x%x)", __func__, (int)start_addr, (int)len, (int)len);
440453

441-
if(!aligned_flash_erase(start_addr, len)) {
454+
if (!aligned_flash_erase(start_addr, len)) {
442455
BOOT_LOG_ERR("%s: Flash erase failed", __func__);
443456
return -1;
444457
}
445458

446-
flush_cache(start_addr, len);
447-
448459
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
449460
uint8_t write_data[FLASH_BUFFER_SIZE];
450461
memset(write_data, flash_area_erased_val(fa), sizeof(write_data));
@@ -472,8 +483,6 @@ int flash_area_erase(const struct flash_area *fa, uint32_t off, uint32_t len)
472483
bytes_remaining -= bytes_written;
473484
}
474485
}
475-
476-
flush_cache(start_addr, len);
477486
#endif
478487

479488
#if VALIDATE_PROGRAM_OP && !defined(CONFIG_SECURE_FLASH_ENC_ENABLED)

0 commit comments

Comments
 (0)