pureboot: a loader in the staging slot is the staging copy — leave it there
The update flow's first step wrote the staging content over whatever the staging slot held; with a loader running right there (programmed by hand onto erased flash), that write met the copy's own running-slot guard on the composed through-word and the tool stopped at its verify — although the copy is exactly an installed staging copy, able to stream the new resident like any other. The install is now skipped when the slot holds a complete loader: its info block where every image carries it, matching the device's byte for byte, and the slot unchanged since the update began (the state file's snapshot) — so a resumed half-written install still differs from its snapshot and takes the install path, which completes it. pbrehome gains the staging-slot position (an older build at stage streaming a newer resident in); the README's wrong "cannot re-home from the staging slot" claim is corrected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,14 +120,14 @@ On a boot-sectioned mega a copy at 0 is dead weight (SPM only executes
|
||||
from the boot section, so it cannot even heal itself — reflash the .hex);
|
||||
on the patched-vector chips it *runs* (the image is position-independent
|
||||
and reset enters word 0), reports its canonical geometry, and the ordinary
|
||||
`--update-loader` flow re-homes a build into the top slot — the staging
|
||||
install and the word-0 redirect both execute from copies outside page 0's
|
||||
slot, so the running-slot guard never blocks the flow (`pureboot.rehome`
|
||||
is the acceptance test). Flashing the application afterwards overwrites
|
||||
the stale copy, vector surgery included. The one position that cannot
|
||||
re-home itself is the staging slot: installing the staging copy would hit
|
||||
the running copy's own guard and the update stops at its verify — flash
|
||||
the .hex instead.
|
||||
`--update-loader` flow re-homes a build into the top slot from any
|
||||
position — the staging install and the word-0 redirect execute from
|
||||
copies outside page 0's slot, and a copy sitting in the staging slot
|
||||
itself is recognized as the installed staging copy and left in place (it
|
||||
streams the new resident like any staged copy, so an older build installs
|
||||
a newer one). `pureboot.rehome` is the acceptance test for both
|
||||
positions. Flashing the application afterwards overwrites the stale copy,
|
||||
vector surgery included.
|
||||
|
||||
**Boot-sectioned megas**: program the loader at `flash − slot` with an
|
||||
external programmer. Every such mega has a BOOTSZ step whose boot section
|
||||
@@ -193,7 +193,10 @@ the loader resident) and peels it to the slot content by the embedded base.
|
||||
patched-vector chips the host composes the slot's last word — the same
|
||||
address as the resident's trampoline — as a jump to the resident base,
|
||||
so even an abandoned staging copy times out into a loader, never into
|
||||
garbage.
|
||||
garbage. A loader already sitting whole in the staging slot (its info
|
||||
block in place, the slot unchanged since the update began) is left as
|
||||
the staging copy instead — rewriting it would only meet its own
|
||||
running-slot guard.
|
||||
3. `J` enters the staging copy, which rewrites the resident slot. On the
|
||||
patched-vector chips whose staging slot sits away from page 0 the host
|
||||
first re-aims word 0 at the staging copy, so a power loss mid-rewrite
|
||||
|
||||
@@ -725,15 +725,33 @@ def op_update_loader(loader, wait, path, state_path, fuse_bytes):
|
||||
state = UpdateState(state_path)
|
||||
state.load_or_save(loader)
|
||||
|
||||
# Install the staging copy. On a chip whose staging slot starts at
|
||||
# address 0 (the 1 KB tiny13A), its first page carries the reset vector:
|
||||
# written last, so any earlier interruption still resets into the old
|
||||
# resident, and from then on resets enter the staging copy.
|
||||
order = list(range(0, info.slot, page))
|
||||
if info.stage == 0:
|
||||
order = order[1:] + [0]
|
||||
if write_differing(loader, info.stage, staged, order):
|
||||
print(f"staging copy installed at {info.stage:#06x}")
|
||||
# Install the staging copy — unless a loader already sits whole in the
|
||||
# staging slot (a build programmed there by hand): that copy IS the
|
||||
# installed staging copy, and rewriting it would only trip its own
|
||||
# running-slot guard on the composed through-word. Any pureboot with
|
||||
# the device's own info block serves — the staged copy just streams
|
||||
# pages, so an older build installs a newer resident all the same. Two
|
||||
# checks make "already a loader" mean a *complete* one: the block must
|
||||
# sit where every image carries it (within the slot's first 256 bytes
|
||||
# — the build's position lint), matching the device's block byte for
|
||||
# byte, and the slot must be unchanged since this update began (the
|
||||
# state file's snapshot) — a resumed, half-written install differs
|
||||
# from its snapshot and takes the install path below, which completes
|
||||
# it page by page.
|
||||
current = loader.read_flash(info.stage, info.slot)
|
||||
staged_loader = image_info(current[:268])
|
||||
if staged_loader is not None and staged_loader.raw == info.raw and current == state.staging:
|
||||
print(f"staging slot already holds a loader — left in place")
|
||||
else:
|
||||
# On a chip whose staging slot starts at address 0 (the 1 KB
|
||||
# tiny13s), its first page carries the reset vector: written last,
|
||||
# so any earlier interruption still resets into the old resident,
|
||||
# and from then on resets enter the staging copy.
|
||||
order = list(range(0, info.slot, page))
|
||||
if info.stage == 0:
|
||||
order = order[1:] + [0]
|
||||
if write_differing(loader, info.stage, staged, order):
|
||||
print(f"staging copy installed at {info.stage:#06x}")
|
||||
|
||||
# Enter it and let it rewrite the resident slot. Where a patched reset
|
||||
# vector routes through the resident (a tiny with the staging slot away
|
||||
|
||||
Reference in New Issue
Block a user