pureboot: a version number for the loader, not for the protocol

The info block's third byte was a protocol version that never moved in the
loader's lifetime. It is the pureboot version now, and this change is
version 2: the one number that says what a deployed loader is. Every loader
already in the field answers 1.

The protocol keeps no number of its own — a pureboot version implies it, and
the host tool is what holds that map. pureboot.py states the loader-version
window it speaks (OLDEST_LOADER/NEWEST_LOADER; a version that changes the
protocol becomes the new floor there), so a loader newer than the tool is
refused by name rather than decoded on the assumption nothing moved, while an
older one is read, identified and installed like any other. The tool carries
its own version, free to drift from the loader's: --version prints it and the
window, --info leads with the device's, --update-loader names the version it
installs.

Tests: the planner unit pins the window — every version in it decodes, one
above it is refused, an older loader's image is still found — and the live
suite pins the built loader against the tool beside it, so a bump that reaches
only one of them fails. The image is byte-identical to the previous build but
for that byte.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 17:19:27 +02:00
parent a39a3c7f46
commit 6f3eb06233
5 changed files with 95 additions and 22 deletions

View File

@@ -61,7 +61,7 @@ def main():
wire_base = base // 2 if word_flash else base
flags = (1 if patch else 0) | (2 if word_flash else 0)
info = pb.Info(
bytes([ord("P"), ord("B"), 1, 0, 0, 0, page & 0xFF])
bytes([ord("P"), ord("B"), pb.NEWEST_LOADER, 0, 0, 0, page & 0xFF])
+ bytes([wire_base & 0xFF, wire_base >> 8, eeprom_size & 0xFF, eeprom_size >> 8])
+ bytes([flags])
)
@@ -71,7 +71,7 @@ def main():
# Session 1: knock from reset, identify, program everything, stay.
out = pbsim.run_tool(tool, device.pty, baud, "--info", "--fuses", "--flash", app_bin,
"--eeprom", ee_path, "--stay")
for needed in ("signature", "fuses", "verify:", "stays"):
for needed in ("version", "signature", "fuses", "verify:", "stays"):
if needed not in out:
fail(f"session 1 output lacks {needed!r}")
@@ -101,7 +101,12 @@ def main():
port = pb.Port(device.pty, baud)
try:
loader = pb.Loader(port)
loader.connect(15)
live = loader.connect(15)
# The loader built from this tree and the tool beside it must
# agree on where the version numbering stands: a bump the tool
# was never told about is a loader it would refuse to speak to.
if live.version != pb.NEWEST_LOADER:
fail(f"loader reports pureboot {live.version}, the tool's newest is {pb.NEWEST_LOADER}")
loader.run_application()
banner = port.read_exact(3, 5.0)
if banner != b"APP":