pureboot: take the emitted loader HEX for --update-loader
The build emits an Intel HEX beside every loader image, but --update-loader could not consume one: load_image() anchors every image at address zero, and a loader HEX links at its base, so it decoded to a 32760-byte blob carrying 504 bytes of loader at the end. staging_content() then refused it as "loader image is 32760 B, the slot holds 512" - an error naming neither the cause nor the raw .bin the tool wanted instead. Drop the blank below the base in the update path. The base comes from the image's own info block rather than the device's, so an image built for another target survives the slice intact and the preflight still reports it as another target rather than failing to find an info block at all. Verified on an ATmega328P: the full self-update flow driven straight from pureboot_timeout-5s.hex, resident slot byte-for-byte against the image afterwards, application preserved; both refusal paths unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -124,7 +124,9 @@ the loader; an erase runs top-down for the same reason.
|
||||
|
||||
`pureboot.py --update-loader new_pureboot.bin` replaces the resident loader
|
||||
with any pureboot build — a re-timed window, a newer protocol — using the
|
||||
loader itself as its own staging loader:
|
||||
loader itself as its own staging loader. The image is the loader's own 512
|
||||
bytes as a raw binary, or the Intel HEX the build emits beside it, which
|
||||
links the loader at its base inside an otherwise blank flash image:
|
||||
|
||||
1. The staging slot `[base−512, base)` is saved to a host-side state file
|
||||
(on the 1 KB tiny13A that is the whole application, vectors included).
|
||||
|
||||
@@ -514,6 +514,20 @@ def image_info(image):
|
||||
return Info(image[at : at + 12]) if 0 <= at <= len(image) - 12 else None
|
||||
|
||||
|
||||
def loader_image(path):
|
||||
"""A loader update image, as the slot's own content. A raw binary is that
|
||||
already; an Intel HEX links the loader at its base inside an otherwise
|
||||
blank flash image, and load_image() anchors every image at zero, so the
|
||||
blank below the base is dropped here. The base comes from the image's own
|
||||
info block rather than the device's, so an image built for somewhere else
|
||||
survives intact and the preflight can say so."""
|
||||
image = load_image(path)
|
||||
embedded = image_info(image)
|
||||
if embedded and len(image) > embedded.base:
|
||||
image = image[embedded.base :]
|
||||
return image
|
||||
|
||||
|
||||
def staging_content(image, info):
|
||||
"""The 512-byte staging-slot content: the image, padding, and — on
|
||||
chips whose hand-over jumps through the word below the resident loader —
|
||||
@@ -643,7 +657,7 @@ def op_update_loader(loader, wait, path, state_path, fuse_bytes):
|
||||
actual flash state, so a re-run after any interruption resumes; the
|
||||
state file carries the bytes the staging slot held."""
|
||||
info = loader.info
|
||||
image = load_image(path)
|
||||
image = loader_image(path)
|
||||
for warning in update_preflight(image, info, fuse_bytes):
|
||||
print(f"note: {warning}")
|
||||
staged = staging_content(image, info)
|
||||
|
||||
Reference in New Issue
Block a user