Skip to content

extflash_program: page-alignment not handled in NOR flash write loop #7576

Description

@pfeerick

Summary

The extflash_program() function in every board's extflash_driver.cpp does not account for a non-page-aligned starting address on the first write. The loop always uses min(len, QSPI_NOR_PAGE_SIZE) as the write size, but if address % QSPI_NOR_PAGE_SIZE != 0, the first program command can cross a NOR page boundary, which causes the hardware to silently wrap and overwrite data at the start of the same page rather than continuing into the next page.

Affected files

The same logic (and therefore the same gap) is present in all of these:

  • radio/src/boards/helloradio-h750/extflash_driver.cpp
  • radio/src/boards/jumper-h750/extflash_driver.cpp
  • radio/src/boards/rm-h750/extflash_driver.cpp
  • radio/src/targets/c14/extflash_driver.cpp
  • radio/src/targets/st16/extflash_driver.cpp

Current code (identical in all affected files)

static int extflash_program(uint32_t address, void* data, uint32_t len)
{
  address -= QSPI_BASE;

  int ret = 0;
  while (len > 0) {
    uint32_t size = (len > QSPI_NOR_PAGE_SIZE) ? QSPI_NOR_PAGE_SIZE : len;
    ret = stm32_qspi_nor_program(address, data, size);
    if (ret != 0) break;
    len -= size;
    address += size;
    data = (uint8_t*)data + size;
  }

  return ret;
}

Proposed fix

Limit the first write to the remaining bytes in the current NOR page:

static int extflash_program(uint32_t address, void* data, uint32_t len)
{
  address -= QSPI_BASE;

  int ret = 0;
  uint32_t page_offset = address % QSPI_NOR_PAGE_SIZE;
  while (len > 0) {
    uint32_t size = (len > QSPI_NOR_PAGE_SIZE - page_offset) ? QSPI_NOR_PAGE_SIZE - page_offset : len;
    ret = stm32_qspi_nor_program(address, data, size);
    if (ret != 0) break;
    len -= size;
    address += size;
    data = (uint8_t*)data + size;
    page_offset = 0;  // subsequent iterations are always page-aligned
  }

  return ret;
}

Alternatively, the fix could be applied once in stm32_qspi_nor_program() / stm32_xspi_nor_program() so all callers benefit automatically.

Impact / Severity

In practice the normal firmware update path erases 64 KB sectors and writes sequentially from a sector start, so all addresses are currently page-aligned (256-byte boundary) and the bug is latent rather than active. However, any future caller that passes a non-page-aligned address would encounter silent data corruption.

Notes

  • stm32_qspi_nor_program() and stm32_xspi_nor_program() (the lower-level HAL wrappers) also do not perform any alignment correction — the fix needs to live either here or in each board's extflash_program().
  • This issue is not specific to any one board; fixing it in only one place would create inconsistency. A coordinated fix across all affected files (or in the shared lower-level driver) is recommended.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions