Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9757f87
Orchestrator spec and reference impl
rusty1968 Jul 17, 2026
28e6b23
fixed ci faulures
rusty1968 Jul 17, 2026
acf2a34
re-walk of the chain explained
rusty1968 Jul 17, 2026
15a75bc
Aligning to the latest CSA
rusty1968 Jul 23, 2026
af598c9
docs: add orchestrator state machine walkthrough and transitions
rusty1968 Jul 24, 2026
663bf48
Add a high level topology without effects
rusty1968 Jul 24, 2026
1e90f42
Update code and docs to the latest CSA
rusty1968 Jul 25, 2026
a4e2f7a
delete redundant docs
rusty1968 Jul 26, 2026
564fe54
Remove misleading pseudostate
rusty1968 Jul 26, 2026
c942aa9
PlatformHalt is a consequence of the Policy::Required
rusty1968 Jul 26, 2026
8d6eeae
orchestrator: document PreSupervision/CorruptionDetected gap as accepted
rusty1968 Jul 26, 2026
f903148
orchestrator/sm: size effect buffer to N+2 via const generic
rusty1968 Jul 26, 2026
aa91c93
orchestrator-sm: durable gate + unified gate_by_policy
rusty1968 Jul 27, 2026
4b0efed
orchestrator-sm: per-device retry budget
rusty1968 Jul 27, 2026
5cdcce2
orchestrator-sm: move tests to sibling tests.rs
rusty1968 Jul 27, 2026
1d47942
orchestrator-sm: validated Chain newtype for construction
rusty1968 Jul 27, 2026
a251304
orchestrator-sm: factor out model types from lib.rs into model.rs
rusty1968 Jul 27, 2026
9df7a78
orchestrator-sm: fail-closed effect-failure channel, panic-free buffe…
rusty1968 Jul 27, 2026
26a95e9
orchestrator-sm: replace statig with hand-written reducer
rusty1968 Jul 27, 2026
5dd3213
orchestrator-sm: fold awaiting/failed into State variants
rusty1968 Jul 27, 2026
3f33bb1
orchestrator-sm: abort effect batch on first actuation failure
rusty1968 Jul 28, 2026
efc6500
orchestrator-sm: clarify Sink::emit partial-batch safety in plain lan…
rusty1968 Jul 28, 2026
04f5ab4
orchestrator-sm: add degraded-mode isolation/recovery-failure reports
rusty1968 Jul 28, 2026
de7dd3d
orchestrator-sm: test degraded-mode reporting
rusty1968 Jul 28, 2026
ff54b7c
orchestrator-sm: add Timeout event and AwaitingReady recovery arm
rusty1968 Jul 28, 2026
aad7432
orchestrator-sm: discard staged image on update preemption; id-check …
rusty1968 Jul 28, 2026
bb5e6cd
orchestrator-sm: fold gated+retries into per-component ComponentStatus
rusty1968 Jul 28, 2026
175328e
orchestrator docs: de-duplicate diagrams, fix stale field names, comp…
rusty1968 Jul 28, 2026
b35dc0c
orchestrator-sm: reword ComponentStatus doc comments to present-tense
rusty1968 Jul 28, 2026
603f52d
docs: drop TOC entries for deleted orchestrator walkthrough/transitio…
rusty1968 Jul 28, 2026
02e27f0
orchestrator/sm: test transitive cascade and mid-recovery corruption …
rusty1968 Jul 28, 2026
ab584d7
orchestrator/sm: commit SVN floor on proven boot, not activation
rusty1968 Jul 28, 2026
745dc32
orchestrator/sm: device-agnostic boot-progress watchdog
rusty1968 Jul 28, 2026
3a5ce14
orchestrator sm: report deferred and aborted updates
rusty1968 Jul 29, 2026
50989bd
third_party: restore crate_universe lock to origin/main pins
rusty1968 Jul 29, 2026
c47b868
orchestrator docs: add consolidated invariant catalogue
rusty1968 Jul 30, 2026
91b14e8
orchestrator docs: define 'rejected' per CSA at first use
rusty1968 Jul 30, 2026
e9cf424
orchestrator docs: rename shell to platform driver; trim redundant IN…
rusty1968 Jul 30, 2026
42eac7e
orchestrator docs: drop inaccurate 'three orthogonal axes' claim
rusty1968 Jul 30, 2026
6ec0be0
docs(orchestrator): add core/platform separation-of-concerns section
rusty1968 Jul 30, 2026
223025b
docs(orchestrator): note the core is policy-free and drops out-of-cha…
rusty1968 Jul 30, 2026
1084ecc
orchestrator/sm: drop out-of-chain ids at the dispatch boundary
rusty1968 Jul 30, 2026
8144f89
docs(orchestrator): recovery-is-a-reboot, INV8 catalogue, shell→platform
rusty1968 Jul 31, 2026
bf06603
orchestrator/sm: recovery re-boots; guard out-of-turn verification ve…
rusty1968 Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@
* [Design](./design/README.md)
* [Pigweed Integration Overview](./design/pigweed-overview.md)
* [pw_kernel IPC](./design/pw-kernel-ipc.md)
* [Orchestrator](./design/orchestrator/orchestrator-overview.md)
* [Verification Model](./design/orchestrator/orchestrator-model.md)
* [State Machine](./design/orchestrator/orchestrator-machine.md)
4 changes: 4 additions & 0 deletions docs/src/design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ of the project.
- [**pw_kernel IPC**](./pw-kernel-ipc.md): How to declare and use channel
objects to communicate between two `pw_kernel` userspace processes.
Worked example lives at `target/veer/ipc/`.
- [**Orchestrator**](./orchestrator/orchestrator-overview.md): The eRoT boot-sequence state
machine (`services/orchestrator/sm`). Covers the two-tier firmware
verification model (`ComponentAttrs`, eRoT gate, iRoT gate), the
verification boundary, and the full state/transition table.
379 changes: 379 additions & 0 deletions docs/src/design/orchestrator/orchestrator-machine.md

Large diffs are not rendered by default.

430 changes: 430 additions & 0 deletions docs/src/design/orchestrator/orchestrator-model.md

Large diffs are not rendered by default.

99 changes: 99 additions & 0 deletions docs/src/design/orchestrator/orchestrator-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Orchestrator State Machine

The orchestrator is the eRoT's boot-sequence controller. It walks the platform
trust chain — verifying each component's firmware and releasing it from reset in
order — and then governs the operational lifecycle (attestation, firmware update,
corruption recovery).

It lives in `services/orchestrator/sm` as a pure state machine: it never touches
hardware directly. Every action is described as an [`Effect`] value that the
surrounding platform carries out; every piece of outside information arrives as an
[`Event`]. This keeps the core testable without hardware and free of I/O.

## State Topology

The reachable states, the events (with guards) that drive transitions between
them, and the effects each transition emits are all shown in the full state
diagram in [State Machine](./orchestrator-machine.md#state-machine). That diagram
is the single source of truth for the topology; it is not duplicated here to
avoid the two drifting apart.

## Documents

- [**Verification Model**](./orchestrator-model.md): The two-tier firmware
verification model (eRoT gate + optional iRoT gate), the verification
boundary, `ComponentAttrs`, and concrete sequencing examples.
- [**State Machine**](./orchestrator-machine.md): All states, shared storage, entry
actions, transition table, and the `SupervisingPlatform` superstate.

## Design Principles

**Effects, not actions; reads as events.** Handlers only call
`ctx.emit(Effect::…)` to describe what should happen, and receive every piece of
outside information in event payloads — the core never reads flash, drives a
GPIO, opens a channel, or touches a provisioning store. The full core/platform
split is the [Platform Boundary](./orchestrator-model.md#5-the-platform-boundary)
in the Verification Model.

**Feedback as data.** Internal follow-up signals (e.g. the retry-cap lockdown
`RecoveryFailed`) are emitted as `Effect::Emit(event)`. The orchestrator queues
and handles them immediately, making them visible in the effect trace rather than
hiding them as implicit state changes. See the
[`Recovering` state](./orchestrator-machine.md#recovering) for a worked example.

**Board-supplied policy.** The core hard-codes no deployment-specific values.
The platform supplies the trust chain (component ids, kinds, and required/optional
policy) and the recovery-retry cap at startup.

## Relationship to CSA Architecture

The state machine is a direct implementation of the boot sequence described in
the CSA architecture document:

| CSA concept | State machine encoding |
|---|---|
| eRoT holds component in reset until firmware verified | `PreSupervision` emits `ReleaseReset` only on `VerificationPassed` |
| Component with Caliptra iRoT requires two independent checks | `ComponentKind::Active` → `AwaitingReady` until `ComponentReady` |
| Passive component (no iRoT): eRoT check only | `ComponentKind::Passive` → advance immediately after `ReleaseReset` |
| Isolable component: failure skips, not blocks | `FailurePolicy::Isolable` → skip (held in reset); advance without `Recovering`; no cascade |
| Cascading skip: failure also holds dependents | `FailurePolicy::Cascading` + `ComponentAttrs::depends_on` → cascade-skip via `statuses` (`Isolated`) |
| Boot-progress watchdog: component must signal readiness in time | `Timeout(ComponentId)` event → `AwaitingReady` → `Recovering` |
| Recovery scope groups components that restore together | `ComponentAttrs::recovery_region` (`RegionId`) → platform restores full region on `RestoreGoldenImage` |

## Applicability Across Admissible Architectures

The orchestrator is **eRoT-scoped**: one instance runs per discrete eRoT chip
running OpenPRoT firmware. The same crate and binary are used at every such
tier — the only difference between deployments is the chain configuration
supplied at startup. eRoT chips not running OpenPRoT (e.g. a third-party AMC
or a legacy DC-SCM implementation) appear as opaque `ComponentId` entries in
the chain of the nearest OpenPRoT eRoT above them.

**Model 1 — Module** (single PCIe add-in card): a discrete eRoT is optional.
When present, it runs one orchestrator instance with a short chain containing
the card's SoC. When absent, the module relies on the parent node's eRoT
instance to verify and release it as a `ComponentId` in the node's chain.

**Model 2 — Single Node Compute**: the DC-SCM discrete eRoT runs one
orchestrator instance whose chain covers all critical node devices (CPU, BMC,
NIC, storage). This is the canonical single-instance deployment.

**Model 3 — Complex Heterogeneous Compute**: the three-tier hierarchy maps to
independent orchestrator instances at each tier:

- Each **AMC / EAM** (subsystem eRoT) runs one instance whose chain covers the
GPU or AI accelerator devices it manages.
- The **DC-SCM node eRoT** runs one instance whose chain covers CPUs, BMC,
SmartNICs, storage, and the AMC/EAM chips themselves.

The node eRoT treats each AMC/EAM as just another `ComponentId` — `Active` if
the AMC has its own integrated iRoT, `Passive` if not. It has no visibility
into the AMC's internal chain walk; it only observes the AMC's
`VerificationPassed` / `ComponentReady` signals, like any other component.

| Admissible Architecture | Orchestrator instances | Chain scope per instance |
|---|---|---|
| Module (eRoT present) | 1 | Card SoC |
| Module (no eRoT) | 0 | — (verified by parent node eRoT) |
| Single Node Compute | 1 | All node critical devices |
| Complex Heterogeneous Compute | 1 per subsystem eRoT + 1 node eRoT | Subsystem devices / all node devices including subsystem eRoTs |
25 changes: 25 additions & 0 deletions services/orchestrator/sm/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Licensed under the Apache-2.0 license
# SPDX-License-Identifier: Apache-2.0

load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")

rust_library(
name = "orchestrator_sm",
srcs = [
"src/lib.rs",
"src/model.rs",
"src/tests.rs",
],
crate_name = "openprot_orchestrator_sm",
edition = "2024",
visibility = ["//visibility:public"],
deps = [
"@rust_crates//:heapless",
],
)

rust_test(
name = "orchestrator_sm_test",
crate = ":orchestrator_sm",
edition = "2024",
)
55 changes: 55 additions & 0 deletions services/orchestrator/sm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!-- Licensed under the Apache-2.0 license -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

# orchestrator state machine (`openprot_orchestrator_sm`)

Pure-reducer eRoT boot-sequence state machine. Walks the platform trust chain
— verifying each component's firmware and releasing it from reset in order —
then governs the operational lifecycle (attestation, firmware update, corruption
recovery).

**No I/O, no hardware.** Every action is an [`Effect`] the surrounding shell
carries out. Every piece of outside information arrives as an [`Event`].

## Key types

| Type | Role |
|---|---|
| `ComponentId` | Opaque `u8` — the shell maps it to hardware; the core never inspects it. |
Comment thread
leongross marked this conversation as resolved.
| `ComponentKind` | `Active` (eRoT + iRoT gates) or `Passive` (eRoT gate only). |
| `ComponentAttrs` | `kind` + `required`: if `false`, a failed component is skipped (held in reset) rather than triggering recovery. |
| `Orchestrator<N>` | Public handle for the caller's event loop. Call `dispatch` or `dispatch_with` once per event. |
| `Platform` | Implement this to carry out effects (drives reset GPIOs, reads flash, etc.). |

## Usage

```rust
use openprot_orchestrator_sm::{
ComponentAttrs, ComponentId, Orchestrator, Event, PowerOnResult, State,
};

const CAPACITY: usize = 3;
const BMC: ComponentId = ComponentId::new(0);
const HOST: ComponentId = ComponentId::new(1);
const NIC: ComponentId = ComponentId::new(2);

let mut chain = heapless::Vec::<_, CAPACITY>::new();
let _ = chain.push((BMC, ComponentAttrs::active_required()));
let _ = chain.push((HOST, ComponentAttrs::active_required()));
let _ = chain.push((NIC, ComponentAttrs::passive_optional()));

let mut orch = Orchestrator::new(chain, /*max_retry=*/ 3);
let mut board = MyBoard;

orch.dispatch(&mut board, Event::PowerGood(PowerOnResult::Provisioned));
// ...deliver VerificationPassed / ComponentReady events as they arrive...
assert_eq!(orch.state(), State::Ready);
```

## Design docs

Full domain model, verification boundary, and state transition tables are in the
OpenPRoT book:

- `docs/src/design/orchestrator/verification-model.md`
- `docs/src/design/orchestrator/state-machine.md`
Loading
Loading