Skip to content

docs: PLDM/orchestrator IPC design - #458

Open
chrysh wants to merge 2 commits into
OpenPRoT:mainfrom
9elements:worktree-docs-pldm-ipc
Open

docs: PLDM/orchestrator IPC design#458
chrysh wants to merge 2 commits into
OpenPRoT:mainfrom
9elements:worktree-docs-pldm-ipc

Conversation

@chrysh

@chrysh chrysh commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • PLDM/orchestrator IPC design as an interactive sequence diagram
  • Two kernel channels (notify + intake), both initiated by PLDM
  • Firmware bytes stay out of IPC (direct to flash)
  • Verified: USER signal latches (level-triggered), MCTP server buffers 4 messages, poll_stage bounded by flash erase time

Related project board items (OpenPRoT PFR):

Design decisions (settled):

  • Activate is on the wire (ActivateFirmware), 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)
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

    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 contiguous prefix
        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)
        UA->>PLDM: ActivateFirmware (MCTP, explicit)
        PLDM->>UA: ApplyComplete (MCTP)
    end

    Note over PLDM: FD must know phase completion to initiate these.<br/>Activate is on the wire, not implicit after staging.

    Note over UA, Orch: any time
    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.
Loading

Test plan

  • Review the interactive diagram (download the HTML from the PR comment, open in a browser)
  • Comment on open design questions

Assisted-by: Claude

Sequence diagram covering the two-channel IPC architecture between the
PLDM FirmwareDevice service and the orchestrator. Covers the notify
channel (pre-transfer veto), intake channel (offer/write/complete/poll),
async effect chain with poll_stage, USER signal nudge, and FD-initiated
PLDM commands.

Includes verified findings: USER signal is level-triggered (no lost
wakeups), MCTP server buffers 4 messages independently while PLDM is in
a transact, and poll_stage worst case is bounded by flash erase time.

Assisted-by: Claude
The HTML is a personal interactive version. The mermaid renders natively
on GitHub and is easier for reviewers to comment on inline.

Assisted-by: Claude
@chrysh
chrysh marked this pull request as ready for review September 7, 2026 15:19
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