fix(flash): merge segments sharing a flash page
Found on the first real-hardware flash (PM3 Easy). The fullimage ELF has two adjacent PT_LOAD segments (seg1 ends at 0x15E5AC, seg2 starts there) that share the 0x15E400 flash page. build_blocks aligned each segment independently, so the shared page was written twice — seg2's 0xFF-padded head, written last, erase-programmed the page and wiped seg1's real bytes there (the SAM7 programs a whole page atomically). That region holds version_information, so the flashed OS booted but reported 'Missing/Invalid version information'. Fix: merge segments whose block-aligned spans touch into one buffer, so every shared page is written once with both segments' real data; 0xFF only fills gaps and aligned outer edges. Re-flash verified on hardware: 3df2ed2e8 -> 303bd5873, valid version, matches_pin true. Bootrom untouched throughout (fullimage-only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,27 @@ def test_build_blocks_aligns_and_pads():
|
||||
assert blocks[1][1][-100:] == b"\xFF" * 100
|
||||
|
||||
|
||||
def test_build_blocks_merges_shared_page():
|
||||
# Two adjacent segments sharing the flash page at 0x102200: seg1 ends at
|
||||
# 0x1022AC, seg2 starts there. The shared page must keep seg1's real tail —
|
||||
# writing it twice (seg2's 0xFF head last) would wipe it (the on-hardware bug).
|
||||
seg1 = (0x102000, b"\x11" * 0x2AC) # ends 0x1022AC (unaligned)
|
||||
seg2 = (0x1022AC, b"\x22" * 0x100) # ends 0x1023AC
|
||||
blocks = dict(build_blocks([seg1, seg2]))
|
||||
shared = blocks[0x102200] # 0x102200..0x102400
|
||||
assert shared[0x00:0xAC] == b"\x11" * 0xAC # seg1 tail preserved, NOT 0xFF
|
||||
assert shared[0xAC:0x100] == b"\x22" * 0x54 # seg2 head
|
||||
# no duplicate block addresses (would mean a double-write of a page)
|
||||
addrs = [a for a, _ in build_blocks([seg1, seg2])]
|
||||
assert len(addrs) == len(set(addrs))
|
||||
|
||||
|
||||
def test_build_blocks_separate_when_far_apart():
|
||||
# A real gap between segments -> separate groups, no giant fill between them.
|
||||
blocks = build_blocks([(0x102000, b"\x11" * 16), (0x120000, b"\x22" * 16)])
|
||||
assert {a for a, _ in blocks} == {0x102000, 0x120000}
|
||||
|
||||
|
||||
def test_build_blocks_pads_low_side():
|
||||
# unaligned start -> leading 0xFF padding down to the block boundary
|
||||
blocks = build_blocks([(0x102010, b"\x22" * 16)])
|
||||
|
||||
Reference in New Issue
Block a user