Skip to content

stream_flash: buffered_write that spans erase unit doesn't work if flash region is not erase-unit aligned #92982

@mjchen0

Description

@mjchen0

Describe the bug

I noticed that DFU in our Nordic nrf5340 cpu_net netboot stopped working (it used to work in 4.0).

The app image written was corrupt and would not boot.

After investigating, it appears to be due to a regression in stream_flash_buffered_write(), which pcd_fw_copy() uses to do the write of the image passed by the cpuapp to the cpunet netboot.

The problem is how stream_flash_buffered_write() handles the case where the starting offset passed in stream_flash_init() is not erase unit aligned. The function doesn't check for this, and erases code it had previously written.

The output shows a few problems:

  1. the last block of the erase unit, at 0x00021000, is written to the next erase unit that hasn't been erased yet
  2. when the erase happens, it erases the block that was just written

This happens at each erase unit boundary.

Regression

  • This is a regression.

Steps to reproduce

Here's a test case I added to the stream_flash unit test that shows the failure:

ZTEST(lib_stream_flash, test_stream_flash_buffered_write_flush)
{
init_target();

rc = stream_flash_init(&ctx, fdev, generic_buf, BUF_LEN, FLASH_BASE + BUF_LEN,
		       FLASH_AVAILABLE - BUF_LEN, stream_flash_callback);
zassert_equal(rc, 0, "expected success");

/* Don't fill up the entire flash but fill more than one buffer */
rc = stream_flash_buffered_write(&ctx, write_buf, TESTBUF_SIZE-10, true);
zassert_equal(rc, 0, "expected success");

VERIFY_WRITTEN(0, TESTBUF_SIZE-10);

}

Relevant log output

START - test_stream_flash_buffered_write_flush
[00:00:00.000,000] <dbg> STREAM_FLASH: stream_flash_erase_to_append: Erasing page at offset 0x00020000
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020200, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020400, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020600, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020800, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020a00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020c00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00020e00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021000, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: stream_flash_erase_to_append: Erasing page at offset 0x00021000
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021200, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021400, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021600, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021800, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021a00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021c00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00021e00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022000, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: stream_flash_erase_to_append: Erasing page at offset 0x00022000
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022200, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022400, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022600, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022800, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022a00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022c00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00022e00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023000, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: stream_flash_erase_to_append: Erasing page at offset 0x00023000
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023200, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023400, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023600, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023800, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023a00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023c00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00023e00, 512 bytes
[00:00:00.000,000] <dbg> STREAM_FLASH: flash_sync: Writing flash at offset 0x00024000, 502 bytes

    Assertion failed at WEST_TOPDIR/zephyr/tests/subsys/storage/stream/stream_flash/src/main.c:191: lib_stream_flash_test_stream_flash_buffered_write_flush: (read_buf not equal to written_pattern)
should equal written_pattern
 FAIL - test_stream_flash_buffered_write_flush in 0.000 seconds
=================================================================

Impact

Functional Limitation – Some features not working as expected, but system usable.

Environment

Latest Zephyr main and SDK as of: 553fc84

Additional Context

No response

Metadata

Metadata

Assignees

Labels

area: FlashbugThe issue is a bug, or the PR is fixing a bugpriority: mediumMedium impact/importance bug

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions