Skip to content
Open
Changes from all commits
Commits
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
109 changes: 109 additions & 0 deletions docs/src/design/orchestrator/pldm-orchestrator-ipc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# PLDM/Orchestrator IPC

How the PLDM FirmwareDevice service and the orchestrator communicate during a
firmware update. Two Pigweed kernel channels, both initiated by PLDM: a notify
channel for pre-transfer veto, and an intake channel for the data transfer and
async effect chain. Firmware bytes go direct to flash, never through IPC.

Design decisions:

- Activate is on the wire (ActivateFirmware from the UA), not implicit after
staging.
- Flash seam is async: poll_stage calls start_erase/start_program, returns,
checks is_busy on the next call. Uses FlashDriver's split API, not
BlockingFlash.
- USER signal is level-triggered (verified from Pigweed kernel source): OR'd
into the peer's active_signals bitfield, persists until lowered. No lost
wakeups.
- MCTP server (separate process) buffers 4 messages while PLDM is in a
transact. Overflow drops silently, no backpressure to the bus.

```mermaid
sequenceDiagram
participant UA as UA (BMC)<br/>remote, over MCTP
participant PLDM as PLDM FirmwareDevice<br/>single thread: run_terminus
participant Orch as Orchestrator<br/>single thread: object_wait loop
participant Flash as Shared Storage<br/>ext. SPI flash

Note over UA, Orch: NOTIFY CHANNEL (pre-transfer veto)

UA->>PLDM: RequestUpdate (MCTP)
activate PLDM
PLDM->>Orch: channel_transact: Request::UpdateRequested
Note right of Orch: check state, policy
Orch-->>PLDM: Response::Accepted | Rejected
deactivate PLDM
PLDM-->>UA: RequestUpdate response (accept/reject)

Note over UA, Orch: if Accepted: INTAKE CHANNEL

activate PLDM
PLDM->>Orch: Offer { target: TargetId, total: u64 }
Note right of Orch: validate target + length,<br/>reserve staging
Orch-->>PLDM: IntakeStatus::Receiving { written: 0, total }
deactivate PLDM

loop FD pulls chunks from UA via RequestFirmwareData
PLDM->>UA: RequestFirmwareData (MCTP)
UA-->>PLDM: firmware chunk response
PLDM-->>Flash: write firmware bytes (direct, no IPC)
activate PLDM
PLDM->>Orch: Write { offset: u64, len: u16 }
Note right of Orch: track write progress
Orch-->>PLDM: IntakeStatus::Receiving { written, total }
deactivate PLDM
opt status poll
activate PLDM
PLDM->>Orch: Poll
Orch-->>PLDM: IntakeStatus
deactivate PLDM
end
end

activate PLDM
PLDM->>Orch: Complete
Note right of Orch: check coverage,<br/>queue Pending::UpdateRequest
Orch-->>PLDM: IntakeStatus
deactivate PLDM

Note over UA, Flash: async: orchestrator event loop drains pending

PLDM->>UA: TransferComplete (MCTP)

Note over PLDM: PLDM FREE:<br/>services UA on MCTP<br/>MCTP responsive

Note over Orch, Flash: EFFECT CHAIN (non-blocking steps)<br/>1. poll_pending<br/>2. SM: Ready -> Updating<br/>3. poll_stage (one step)<br/>4. return to object_wait<br/>repeat 3-4 until phase done<br/>IPC responsive between steps

Orch-->>Flash: PayloadSource::read_at
Flash-->>Orch: payload bytes

Orch->>PLDM: object_set_peer_user_signal<br/>(dataless nudge, wakes WaitGroup)

loop wake on USER signal, poll status, send *Complete to UA
activate PLDM
PLDM->>Orch: Poll
Note right of Orch: read latched IntakeStatus
Orch-->>PLDM: Authenticating | Staging | Activated | Failed
deactivate PLDM
Note over PLDM, UA: when phase done:
PLDM->>UA: VerifyComplete (MCTP)
PLDM->>UA: ApplyComplete (MCTP)
end

Note over PLDM: FD must know phase completion to initiate these.

UA->>PLDM: ActivateFirmware (MCTP, explicit)
activate PLDM
PLDM->>Orch: Activate
Orch-->>PLDM: IntakeStatus
deactivate PLDM
Note right of Orch: activation effect:<br/>bump SVN in OTP (irreversible)

Note over UA, Orch: between Offer and Activate
activate PLDM
PLDM->>Orch: Abort
Orch-->>PLDM: IntakeStatus::Idle
deactivate PLDM

Note over UA, Flash: Blocking direction: always PLDM -> Orchestrator, never the reverse.<br/>Every IPC response is immediate. Effects run async via poll_stage (one step, return, repeat).<br/>PLDM stays free to service UA on MCTP. USER signal nudge replaces blind polling.<br/>FD initiates TransferComplete, VerifyComplete, ApplyComplete. UA initiates ActivateFirmware.
```