RP2040: avoid XIP hangs during flash operations with scheduler=cores#5411
Open
rdon-key wants to merge 7 commits into
Open
RP2040: avoid XIP hangs during flash operations with scheduler=cores#5411rdon-key wants to merge 7 commits into
rdon-key wants to merge 7 commits into
Conversation
added 7 commits
May 20, 2026 13:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5288
RP2040 flash program / erase / command operations temporarily disable XIP.
With
scheduler=cores, the other core may continue executing instructions from XIP flash during that window, which can cause a system hang.What was done
This change adds an RP2040-specific flash-safe section.
Runtime changes:
scheduler=cores, send a SIO FIFO command to the other core before starting a flash operation.Machine changes:
flash_range_writeflash_erase_blocksflash_do_cmdThese flash operations now run inside
rp2040EnterFlashSafeSection/rp2040ExitFlashSafeSection.Notes
This is intentionally limited to RP2040 flash operations that temporarily disable XIP.
It is not intended to be a general multicore lock.
Other shared peripherals should be protected by their own ownership or locking rules.
RP2350 behavior is intentionally left unchanged.
The RP2350 handler added here is only a build-only stub for shared RP2 runtime code.
If the monitor output becomes corrupted under
scheduler=cores, for example:please also test this reproducer with pull request #5391:
That output corruption appears to be a separate USB CDC multicore output issue, and it can make the flash test result difficult to read.
Reproducer
Warning: Flash memory has a limited number of program/erase cycles. This reproducer repeatedly erases and writes flash, so run it only when needed.
main.go
Test results
Tested on RP2040/Pico.
With
-scheduler=cores(the failing case before this PR)Reproducer: a worker goroutine on core 1 performs continuous random reads
from a 64 KB flash-resident const slice (which defeats the 16 KB XIP cache)
and periodic flash writes to a fixed low offset. Main on core 0 does
100 rounds of erase / write / read-back / verify on the top sectors of the
data region.
Before this PR: hangs at the first
write starton core 0.After this PR:
Evidence:
worker started on core: 1andworker core: 1in every round headerconfirm the test condition (worker is actually running on core 1, not 0).
worker writes: Ngrows from 0 to 156, meaning the worker successfullyperformed 156 flash writes concurrently with main's flash ops. Each of
those is a moment when both cores were contending for the flash-safe
section, exercising the spinlock added in this PR.
any
mismatchorerror, so the cross-core lockout protocol did notcorrupt either core's data.
worker stopped cleanlyconfirms no deadlock at shutdown.With
-scheduler=tasks(non-regression check)Single-core builds go through
runtime_rp2040_flashsafe_single.go, whichis a plain
interrupt.Disable()/interrupt.Restore()pair. 100 roundscomplete with no regression.
worker core: 99is the sentinel valuemeaning the worker goroutine was never started (
NumCPU == 1).Symbol placement (
//go:section .ramfuncs)rp2FlashSafeInterruptHandleris placed at0x20001184(RP2040 SRAM),not in the XIP-mapped flash region. The flash-side symbol is the long-branch
thunk LLVM auto-generates for Cortex-M0; it is fetched while XIP is still
enabled, so it is safe.