Skip to content

orchestrator: Add the per-device image layout to the device-table schema - #394

Draft
chrysh wants to merge 1 commit into
OpenPRoT:mainfrom
9elements:slot-layout-schema
Draft

chrysh wants to merge 1 commit into
OpenPRoT:mainfrom
9elements:slot-layout-schema

Conversation

@chrysh

@chrysh chrysh commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Redesigned since the last review round: SlotDesc, RecoveryPolicy and the
per-slot flags are gone, so the earlier comments no longer apply.

Board tables now say where each device's images live. ImageLayout holds the
slots the eRoT writes plus the golden image; a Slot is an id and a Region, a
byte range counted from the start of that device's firmware partition.
ImageLayout::new rejects duplicate slot ids and overlapping regions at build
time.

Golden is its own type, not a flag on a slot, so code that picks a write target
or checks the SVN floor never sees it. The floor has to skip it: a golden
image's security version is fixed when the board is made, so enforcing the floor
would eventually make the last image that still boots unbootable.

The layout is optional. A device that takes its own updates over PLDM and picks
what it boots declares none.

assert_retry_reaches_every_image closes the gap rusty1968 raised: boards call
it from a const fence, so a retry budget too small to boot every image fails the
build. The floor is one more than the image count, because the last restore the
budget allows is never booted.

Part of 9elements#1.

Comment thread services/orchestrator/config/src/lib.rs Outdated
}
if matches!(slots[s].role, Some(SlotRole::Recovery)) {
recovery_slots += 1;
assert!(slots[s].bootable, "a recovery-role slot must be bootable");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent invalid slot definitions with role Recovery and bootable false we could create a simple constructor that prohibits this and throws an error.

type SlotDescError ...

impl SlotDesc {
	pub fn new(id: u8, writebale: bool, bootable: bool, policy: Option<SlotRole>) -> Result<SlotDescError, Self> {
    ...
  }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a constructor is a good idea, done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this implemented @chrysh, I can't seem to find it in this patch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it, now golden has its own role.

Comment thread services/fwmanager/api/src/config.rs Outdated
/// is plain A/B, A/B + golden, or single + golden purely by what the table
/// declares — no layout shape is named anywhere.
#[derive(Debug, Clone, Copy)]
pub struct SlotDesc {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, we should discuss whether a SlotDesc should be mutable or not. If not, we can make validation a method for the SlotDesc and run it on creation to make the API safer for the users, such that the user cannot 'forget' to validate the SlotDesc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A constructor is a good idea, done

@chrysh
chrysh force-pushed the slot-layout-schema branch from 5e323b6 to e7a45b4 Compare August 7, 2026 14:00
Comment thread services/orchestrator/config/src/lib.rs Outdated
/// A layout without rungs — e.g. empty, for a device that owns its
/// boot selection internally (the PLDM archetype) — leaves escalation
/// as the only step.
pub slots: &'static [Slot],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A board can declare more recovery slots than the orchestrator is allowed to try!

How far recovery falls back is set by max_retry (in the orchestrator), but the ladder depth is set here (in the slot table), and nothing checks that they agree.

If max_retry is smaller than the number of slots, the sm locks up before it ever reaches the golden slot — so the last-resort image silently never runs.

Since this is a schema-only PR, either add a build-time check that max_retry covers the deepest ladder or note it as a required follow-up before anything starts using these slots.

Otherwise a board can ship with an unreachable golden slot and no one finds out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have max_retry ? Shouldn't it be dictated by the number of configured slots? The sm just tries the next configured slot until no more slots left to try?

@chrysh

chrysh commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Closed until @FerralCoder returns the config file and gives us more instructions.

@chrysh chrysh closed this Sep 1, 2026
@chrysh chrysh reopened this Sep 16, 2026
@chrysh chrysh changed the title fwmanager: Add per-device slot layout to the device-table schema orchestrator: Add the per-device image layout to the device-table schema Sep 16, 2026
Board tables now say where a device's images live: the slots the eRoT
writes, each a byte range in the device's firmware partition, plus the
golden image recovery falls back to last. ImageLayout::new rejects
duplicate slot ids and overlapping regions at build time.

Golden is its own type instead of a flag on a slot, so code that walks the
slot list to pick a write target, or to check the SVN floor, never sees it.
The floor has to skip it. A golden image's security version is fixed when
the board is made, so once the floor moves past that version, checking the
floor would make the last image that still boots unbootable.

The layout is optional. A device that takes its own updates over PLDM and
picks what it boots declares none, and the eRoT never names a byte range
for it.
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.

Active partition tracking Assumption of hard coded config

3 participants