blob: 67e6614c00b9dc55c782418e085033fbb3999744 [file] [view] [edit]
# openprot-pldm-service
Platform-independent PLDM Firmware Device (FD) service, talking PLDM-over-MCTP
directly to a remote Update Agent (UA).
## Overview
This crate bridges [`openprot-mctp-api`](../mctp/api) and
[`pldm-interface`](https://github.com/OpenPRoT/pldm-lib/tree/main/pldm-interface)
so that firmware can run the PLDM firmware-update state machine and exchange
PLDM messages over MCTP without depending on any particular MCTP
implementation or OS.
`FirmwareDevice` owns two [`MctpPldmTransport`] instances and drives both
directions of traffic itself there is no separate responder/requester
process or platform-specific IPC bridge:
```text
┌──────────────────────────┐
│ Application / Firmware │ constructs FirmwareDevice, calls run_terminus()
└───────────┬──────────────┘
┌───────────────────────────────────────────┐
│ openprot-pldm-service │◄── this crate
│ FirmwareDevice<'a, O: FdOps, Cr, Cq> │
│ - cmd_interface: CmdInterface<'a, O> │ PLDM FW-update state machine
│ - responder_transport: inbound UA→FD │
│ - requester_transport: outbound FD→UA │
└───────────┬──────────────┬────────────────┘
│ │ MctpPldmTransport<C: MctpClient>
▼ ▼
┌───────────────────────────────────────────┐
│ openprot-mctp-api │ Stack<C: MctpClient>
└───────────┬───────────────────────────────┘
│ IPC / transport
┌──────────────────────────┐
│ MCTP Server │
└──────────────────────────┘
```
## Key types
| Type | Description |
|------|-------------|
| `FirmwareDevice<'a, O: FdOps, Cr: MctpClient, Cq: MctpClient>` | Owns the `CmdInterface` FW-update state machine plus the responder/requester `MctpPldmTransport`s; `run_terminus()` drives both to completion |
| `MctpPldmTransport<C: MctpClient>` | Wraps a `Stack<C>` and manages the MCTP PLDM framing byte (`0x01`) for sends/receives |
| `PldmServiceError` | Union of MCTP transport errors (`Mctp`), PLDM handler errors (`MsgHandler`), buffer/arithmetic overflow, and IPC errors |
| `PLDM_MSG_TYPE` (`pldm_common::util::mctp_transport::MCTP_PLDM_MSG_TYPE`) | MCTP message-type constant for PLDM (`0x01`) |
## Usage
```rust,ignore
use openprot_pldm_service::firmware_device::FirmwareDevice;
use openprot_pldm_service::MctpPldmTransport;
use pldm_interface::config::PLDM_PROTOCOL_CAPABILITIES;
// `fd_ops` implements `FdOps` (platform-specific flash / component logic).
// `responder_client` / `requester_client` are `MctpClient` implementations
// (they may share the same underlying MCTP endpoint).
let responder_transport = MctpPldmTransport::new(responder_client);
let requester_transport = MctpPldmTransport::new(requester_client);
let mut fd = FirmwareDevice::init(
&fd_ops,
&PLDM_PROTOCOL_CAPABILITIES,
responder_transport,
requester_transport,
);
const UA_EID: u8 = 8;
let mut buf = [0u8; 1024];
// `run_terminus` loops forever, interleaving inbound UA commands with any
// FD-initiated requests (e.g. RequestFirmwareData) once an update begins.
// It returns only on error; a `timeout_millis`/`requester_timeout_millis`
// of `0` blocks indefinitely while idle.
if let Err(e) = fd.run_terminus(UA_EID, &mut buf, 0, 0) {
// handle or log error
}
```
## Buffer layout
All transport methods (`MctpPldmTransport::send_request`,
`recv_and_respond`, `respond_once`) and `FirmwareDevice::run_terminus` use the
same flat-buffer convention:
```text
buf[0] : MCTP message-type byte (0x01) — managed by MctpPldmTransport
buf[1..] : PLDM request / response bytes
```
Size the buffer to accommodate the largest PLDM message your application
expects (typically 1024 bytes; smaller for embedded targets). See
`FD_MAX_MSG` in [`src/firmware_device.rs`](src/firmware_device.rs) for the
scratch-buffer size used internally for FD-initiated requests.
## Build
```
bazel build //services/pldm:pldm_service
```
Run the host-side integration tests:
```
bazel build -c dbg --strip=never //services/pldm:base_host_test
bazel build -c dbg --strip=never //services/pldm:firmware_update_host_test
```
After changing `pldm-common` / `pldm-interface` versions in
`third_party/crates_io/Cargo.toml`, re-pin the lock file. This repo is
bzlmod-only (no `WORKSPACE` file), so use `bazel build` with
`CARGO_BAZEL_REPIN=1`, not `bazel sync` (which errors with "WORKSPACE has to
be enabled"):
```
CARGO_BAZEL_REPIN=1 bazel build //services/pldm:pldm_service
```
## Dependencies
- [`openprot-mctp-api`](../mctp/api) MCTP stack facade and traits
- [`pldm-interface`](https://github.com/OpenPRoT/pldm-lib/tree/main/pldm-interface) — PLDM command dispatcher (`CmdInterface`, `FdOps`, `FirmwareDeviceContext`)
- [`pldm-common`](https://github.com/OpenPRoT/pldm-lib/tree/main/pldm-common) — PLDM protocol types and MCTP transport helpers