Skip to content

driver: Settle the eRoT's last self-update at boot - #509

Merged
chrysh merged 1 commit into
OpenPRoT:ocp-global-demo-wipfrom
9elements:self-update-resume
Oct 4, 2026
Merged

chrysh merged 1 commit into
OpenPRoT:ocp-global-demo-wipfrom
9elements:self-update-resume

Conversation

@chrysh

@chrysh chrysh commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

When the eRoT updates its own firmware, it has to reboot into the new image. Everything it knew in RAM is gone after that, so before the reboot it writes a note to durable storage saying which image it is trying and with which SVN. That note is the session.

The new image goes into the secondary slot and the session is marked pending, so the next reset runs that image once. That trial run is then either confirmed or reverted.

This PR adds settle_self_update, which runs at the start of the next boot. It reads the session plus one more fact, which image actually booted, and says what it found:

  • No session: nothing happened, carry on.
  • The session is pending and the trial image booted: this boot is the trial run. Nothing here judges it. The update agent does that with UpdateSecurityRevision, so the session is left alone.
  • The session is prepared or pending but the confirmed image booted: the update never ran, or its trial failed and the platform fell back. The session is reverted, so the update is done again instead of counting as finished.
  • A trial image is running that no session claims: the session is reverted, which also clears the pending mark, so the confirmed image runs after a reset. The eRoT must not keep running an image nothing vouched for.
  • The session is confirmed and the floor is still below its SVN: the floor advance is what is left, and the update agent asks for it, so this boot does not do it.
  • The session is confirmed and the floor already reads that SVN or higher: the advance landed before a crash, so the session is closed here.

The three answers are Settled, AwaitingUpdateAgent { svn } and UnclaimedImageRunning. Settled means nothing is left to do, so the boot carries on and a new self-update may start. AwaitingUpdateAgent means a session is still being judged, so no new self-update may start: recording one would overwrite the session.

Running it twice lands in the same place, which is what lets a boot that died partway through simply repeat it. A storage fault leaves the session as it is and fails secure rather than guessing, and the failure carries the session's or the floor's own error in a SettleError, which is what the core::error::Error bound on those seams is for.

It is a free function taking the session and the eRoT's own floor, not a board seam. Nothing calls it yet, and a capability joins BoardCapabilities when an executor needs it, so board.rs is untouched.

Not in this PR: the call site, turning the answer into a state machine event, and the 0x22 path that confirms and advances the floor. Those belong with the message plumbing, which this repo does not have yet.

@chrysh
chrysh force-pushed the self-update-resume branch 2 times, most recently from ae4ddd1 to 5b812af Compare September 27, 2026 07:40
@chrysh chrysh closed this Sep 29, 2026
@chrysh
chrysh deleted the self-update-resume branch September 29, 2026 11:10
@chrysh
chrysh restored the self-update-resume branch September 29, 2026 12:27
@chrysh chrysh reopened this Sep 29, 2026
@chrysh
chrysh force-pushed the self-update-resume branch 16 times, most recently from 97410e3 to 4c3f8d5 Compare October 3, 2026 19:49
settle_self_update reads the session and the image this boot is running,
and says what it found. An update writes the new image to the secondary
slot and marks the session pending, so the next reset runs that image
once, and the trial run is then either confirmed or reverted.

A session nothing will confirm is reverted, so the update is done again
rather than counted as finished. A trial that is running is left alone,
the update agent judges it with UpdateSecurityRevision. A confirmed
session is kept until the floor takes its SVN, and closed here when the
floor already reads it, which covers the crash point between the two.

The answer is Settled when nothing is left to do, AwaitingUpdateAgent
while a session is still being judged, or UnclaimedImageRunning when a
trial image is running that no session claims. The last one reverts the
session, which clears the pending mark, so the confirmed image runs after
a reset rather than the one nothing vouched for.

Failures come back as SettleError carrying the session's or the floor's
own error, which is what the core::error::Error bound on those seams is
for. The rest of the driver flattens storage errors into DriverError
because that enum is shared and carries no payload; a free function with
its own generics can keep them.

It is a free function over the session and the floor, not a board seam.
Nothing calls it yet, and a capability joins BoardCapabilities when an
executor needs it.

Assisted-by: Claude
@chrysh
chrysh force-pushed the self-update-resume branch from 4c3f8d5 to 602ec95 Compare October 4, 2026 08:34
@chrysh
chrysh marked this pull request as ready for review October 4, 2026 08:37
@chrysh
chrysh merged commit e04b826 into OpenPRoT:ocp-global-demo-wip Oct 4, 2026
4 checks passed
@chrysh
chrysh deleted the self-update-resume branch October 4, 2026 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant