Skip to content

bootloader_support: bootloader_flash_write lacks cache invalidation, causing silent failures with flash encryption (IDFGH-15895) #16819

@FacepalmMute

Description

@FacepalmMute

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

v5.1.5

Espressif SoC revision.

ESP32-S3

Operating System used.

Linux

How did you build your project?

Command line with CMake

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-S3-WROOM-1

Power Supply used.

USB

What is the expected behavior?

When bootloader_flash_write() is called with flash encryption enabled, it returns ESP_OK, but the data is not correctly written or readable immediately after the operation.

A subsequent call to bootloader_flash_read() for the same address returns stale data (e.g., the erased 0xFF state) instead of the data that was just passed to the write function.

This leads to silent data corruption, which can cause severe issues in the calling application.

What is the actual behavior?

After bootloader_flash_write() returns ESP_OK, a subsequent call to bootloader_flash_read() for the same address and size should return a buffer containing the exact data that was just written.

The bootloader_flash_write function should handle all necessary hardware interactions, including cache coherency, to ensure that the memory state is consistent from the caller's perspective after the function completes.

Steps to reproduce.

  1. Target Hardware: ESP32-S3
  2. Configuration: Enable Flash Encryption via efuses.
  3. Context: Execute code from within a bootloader context (i used the mcuboot espressif port).
  4. Action: Call bootloader_flash_write() to write a known data pattern (e.g., {0x01, 0x02, 0x03, 0x04}) to an address in flash.
  5. Verification: Immediately after the bootloader_flash_write() call returns ESP_OK, call bootloader_flash_read() for the same address and size.
  6. Observe: Compare the buffer that was written with the buffer that was read back. The read-back buffer will contain stale data (e.g., {0xFF, 0xFF, 0xFF, 0xFF}) instead of the written pattern.

Debug Logs.


Diagnostic report archive.

No response

More Information.

Proposed Solution

My current fix is to wrap the ROM write call inside bootloader_flash_write with the appropriate cache management calls, mirroring the logic used in bootloader_flash_read.

esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
{
    esp_err_t err;
    // ... alignment checks and unlock ...

#if CONFIG_IDF_TARGET_ESP32
    Cache_Read_Disable(0);
    Cache_Flush(0);
#else
    cache_hal_disable(CACHE_TYPE_ALL);
#endif

    if (write_encrypted && !ENCRYPTION_IS_VIRTUAL) {
        err = spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size));
    } else {
        err = spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size));
    }

#if CONFIG_IDF_TARGET_ESP32
    Cache_Read_Enable(0);
#else
    cache_hal_enable(CACHE_TYPE_ALL);
#endif

    return err;
}

I'm currently not sure if this problem can also theoretically occur on systems where flash encryption is disabled.
Maybe it would be better to only disable the cache for the encrypted writes?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions