1# Phosphor Blob Transfer Interface 2 3This document describes the commands implementing a generic blob transfer 4interface. This document does not specify how blobs are stored; that is left up 5to blob-specific implementations. Introduction This mechanism supports reading 6and writing from a generic blob store. This mechanism can be leveraged to 7support firmware upgrades, 8 9The interface defined in this document supports: 10 11- Enumerating blobs 12- Opening a blob for reading or writing 13- Writing blob content 14- Committing a blob 15- Polling until the blob has been committed 16- Closing a blob 17- Reading blob content 18- Deleting a blob 19 20Some blobs will only support a subset of these operations. For example, firmware 21cannot generally be read, as the firmware file is not persisted on the BMC after 22it has been activated. 23 24This specification supports IPMI as a transport layer. This can be quite slow, 25however; IPMI transport speeds range from 23 kbps to 256 kbps. LPC/P2A ("PCI to 26Aspeed") MMIO bridges are currently unsupported. Blob Identifiers Blobs are 27identified by NULL-terminated C strings. This protocol supports 28implementation-specific blob identifiers; some blobs may have single well-known 29names, while others may be defined only by a prefix, with the client specifying 30the rest of the blob name. For example, "/g/bmc_firmware" may represent a single 31well-known blob that supports BMC firmware updates, whereas "/g/skm/[N]" may 32represent an arbitrary number of SKM keys, with the index specified on the host 33when opening the blob. 34 35Blob identifiers are limited based on the maximum size of the IPMI packet. This 36maximum size is platform-dependent; theoretically a packet could be up to 256 37bytes, but some hardware only supports packets up to 64 bytes. 38 39If an identifier is malformed, e.g. does not have a trailing NUL-byte or is 40otherwise unrecognizable by the BMC, an error is returned. 41 42The OEM Number to use with these commands is 43[openbmc oen](https://github.com/openbmc/phosphor-host-ipmid/blob/194375f2676715a0e0697bab63234a4efe39fb96/include/ipmid/iana.hpp#L12) 49871. 44 45## Commands 46 47The following details each subcommand in the blob spec. In the following, any 48reference to the command body starts after the 3 bytes of OEM header, the 1-byte 49subcommand code, and (in the cases where the command body is non-empty) a 50two-byte CRC over all data that follows in the body. 51 52All non-empty responses should lead with a two-byte CRC. The CRC algorithm is 53CRC-16-CCITT (poly 0x1021). 54 55All multi-byte values are encoded as little-endian. All structs are assumed 56packed. Success codes are returned via the "completion code" field from the IPMI 57spec. 58 59### BmcBlobGetCount (0) 60 61The `BmcBlobGetCount` command expects to receive an empty body. The BMC will 62return the number of enumerable blobs: 63 64``` 65struct BmcBlobCountRx { 66 uint16_t crc16; 67 uint32_t blob_count; 68}; 69``` 70 71### BmcBlobEnumerate (1) 72 73The `BmcBlobEnumerate` command expects to receive a body of: 74 75``` 76struct BmcBlobEnumerateTx { 77 uint16_t crc16; 78 uint32_t blob_idx; /* 0-based index of blob to retrieve. */ 79}; 80``` 81 82The BMC will return the corresponding blob identifier: 83 84``` 85struct BmcBlobEnumerateRx { 86 uint16_t crc16; 87 char blob_id[]; 88}; 89``` 90 91Note that the index for a given blob ID is not expected to be stable across a 92long term. Callers are expected to call `BmcBlobGetCount`, followed by N calls 93to `BmcBlobEnumerate`, to collect all blob IDs. Callers can then call 94`BmcBlobStat` with each blob ID. If this process is interleaved with Open or 95Delete calls that modify the number of enumerable blobs, this operation will be 96subject to concurrent modification issues. 97 98### BmcBlobOpen (2) 99 100The BmcBlobOpen command expects to receive a body of: 101 102``` 103struct BmcBlobOpenTx { 104 uint16_t crc16; 105 uint16_t flags; 106 char blob_id[]; /* Must correspond to a valid blob. */ 107}; 108``` 109 110The flags field allows the caller to specify whether the blob is being opened 111for reading or writing: 112 113``` 114enum BmcBlobOpenFlagBits { 115 READ = 0, 116 WRITE = 1, 117 <bits 2-7 reserved> 118 <bits 8-15 given blob-specific definitions> 119}; 120``` 121 122If the `WRITE` flag is specified, the BMC will mark the specified blob as "open 123for writing". Optional blob-specific behavior: if the blob has been open for 124more than one minute without any activity, the existing session will be torn 125down and the open will succeed. Alternatively, blobs may allow multiple write 126sessions to be active at once. 127 128The BMC allocates a unique session identifier, and internally maps it to the 129blob identifier. 130 131``` 132struct BmcBlobOpenRx { 133 uint16_t crc16; 134 uint16_t session_id; 135}; 136``` 137 138### BmcBlobRead (3) 139 140The BmcBlobRead command is used to read blob data. It expects to receive a body 141of: 142 143``` 144struct BmcBlobReadTx { 145 uint16_t crc16; 146 uint16_t session_id; /* Returned from BmcBlobOpen. */ 147 uint32_t offset; /* The byte sequence start, 0-based. */ 148 uint32_t requested_size; /* The number of bytes requested for reading. */ 149}; 150``` 151 152Blob handlers may require the blob’s "state" to equal `OPEN_R` before reading is 153successful. 154 155``` 156struct BmcBlobReadRx { 157 uint16_t crc16; 158 uint8_t data[]; 159}; 160``` 161 162Immediately following this structure are the bytes being read. The number of 163bytes transferred is the size of the response body less the OEN ("OEM number") 164(3 bytes), sub-command (1 byte), and the structure size (4 bytes). If no bytes 165are transferred, the CRC is still sent. 166 167If the BMC cannot return the number of requested bytes, it simply returns the 168number of bytes available for reading. If the host tries to read at an invalid 169offset or if the host tries to read at the end of the blob, an empty successful 170response is returned; e.g., data is empty. 171 172### BmcBlobWrite (4) 173 174The `BmcBlobWrite` command expects to receive a body of: 175 176``` 177struct BmcBlobWriteTx { 178 uint16_t crc16; 179 uint16_t session_id; /* Returned from BmcBlobOpen. */ 180 uint32_t offset; /* The byte sequence start, 0-based. */ 181 uint8_t data[]; 182}; 183``` 184 185Immediately following this structure are the bytes to write. The length of the 186entire packet is variable and handled at a higher level, therefore the number of 187bytes to write is the size of the command body less the OEN and sub-command (4 188bytes) and less the structure size (10 bytes). It is assumed that all writes are 189sequential, and begin at offset zero. 190 191On success it will return a success completion code. 192 193### BmcBlobCommit (5) 194 195The `BmcBlobCommit` command expects to receive a body of: 196 197``` 198struct BmcBlobCommitTx { 199 uint16_t crc16; 200 uint16_t session_id; /* Returned from BmcBlobOpen. */ 201 uint8_t commit_data_len; 202 uint8_t commit_data[]; /* Optional blob-specific commit data. */ 203}; 204``` 205 206Each blob defines its own commit behavior. A BMC firmware blob may be verified 207and saved to the filesystem. Commit operations may require additional data, 208which would be provided following the structure in the IPMI packet. 209 210The commit operation may exceed the IPMI timeout duration of ~5 seconds 211(implementation dependant). Callers are expected to poll on `BmcBlobSessionStat` 212or `BmcBlobStat` (as appropriate) until committing has finished. To address race 213conditions, blobs should not allow concurrent sessions that modify state. 214 215On success, the BMC returns success completion code. 216 217### BmcBlobClose (6) 218 219The `BmcBlobClose` command must be called after commit-polling has finished, 220regardless of the result. It expects to receive a body of: 221 222``` 223struct BmcBlobCloseTx { 224 uint16_t crc16; 225 uint16_t session_id; /* Returned from BmcBlobOpen. */ 226}; 227``` 228 229The BMC marks the specified blob as closed. On success, the BMC returns a 230success completion code. 231 232### BmcBlobDelete (7) 233 234The `BmcBlobDelete` command is used to delete a blob. Not all blobs will support 235deletion. This command expects to receive a body of: 236 237``` 238struct BmcBlobDeleteTx { 239 uint16_t crc16; 240 char blob_id[]; /* Must correspond to a valid blob. */ 241}; 242``` 243 244If the operation is supported, the blob is deleted. On success, the BMC returns 245a success completion code. This command will fail if there are open sessions for 246the blob. 247 248### BmcBlobStat (8) 249 250The `BmcBlobStat` command is used to retrieve statistics about a blob. Not all 251blobs must support this command; this is only useful when blob_id semantics are 252more useful than session IDs. This command expects to receive a body of: 253 254``` 255struct BmcBlobStatTx { 256 uint16_t crc16; 257 char blob_id[]; /* Must correspond to a valid blob. */ 258}; 259``` 260 261The BMC returns the following data: 262 263``` 264struct BmcBlobStatRx { 265 uint16_t crc16; 266 uint16_t blob_state; 267 uint32_t size; /* Size in bytes of the blob. */ 268 uint8_t metadata_len; 269 uint8_t metadata[]; /* Optional blob-specific metadata. */ 270}; 271``` 272 273The blob_state field is a bit field with the following flags: 274 275``` 276enum BmcBlobStateFlagBits { 277 OPEN_R = 0, 278 OPEN_W = 1, 279 COMMITTING = 2, 280 COMMITTED = 3, 281 COMMIT_ERROR = 4, 282 <bits 5-7 reserved> 283 <bits 8-15 given blob-specific definitions> 284}; 285``` 286 287If the state is `COMMITTING`, the blob is not currently available for reading or 288writing. If the state is `COMMITTED`, the blob may be available for reading. 289 290The size field may be zero if the blob does not support reading. 291 292Immediately following this structure are optional blob-specific bytes. The 293number of bytes transferred is the size of the response body less the OEN and 294sub-command and less the structure size. The metadata must fit in a single IPMI 295packet, which has a platform-dependent maximum size. (For reference, Aspeed 296supports 64 bytes max.) 297 298If the blob is open or committed but has been inactive for longer than the 299specified activity timeout, the blob is closed, and blob_status is set to 300`CLOSED` in the response. 301 302### BmcBlobSessionStat (9) 303 304The `BmcBlobSessionStat` command returns the same data as `BmcBlobStat`. 305However, this command operates on sessions, rather than blob IDs. Not all blobs 306must support this command; this is only useful when session semantics are more 307useful than raw blob IDs. 308 309``` 310struct BmcBlobSessionStatTx { 311 uint16_t crc16; 312 uint16_t session_id; /* Returned from BmcBlobOpen. */ 313}; 314``` 315 316``` 317struct BmcBlobSessionStatRx { 318 uint16_t crc16; 319 uint16_t blob_state; 320 uint32_t size; /* Size in bytes of the blob. */ 321 uint8_t metadata_size; 322 uint8_t metadata[]; /* Optional blob-specific metadata. */ 323}; 324``` 325 326### BmcBlobWriteMeta (10) 327 328The `BmcBlobWriteMeta` command behaves like `BmcBlobWrite`. Its purpose is 329blob-specific, and not all blobs must support it. 330 331The `BmcBlobWriteMeta` command expects to receive a body of: 332 333``` 334struct BmcBlobWriteMetaTx 335{ 336 uint16_t crc16; 337 uint16_t session_id; /* Returned from BmcBlobOpen. */ 338 uint32_t offset; /* The byte sequence start, 0-based. */ 339 uint8_t data[]; 340}; 341``` 342 343Immediately following this structure are the bytes to write. The length of the 344entire packet is variable and handled at a higher level, therefore the number of 345bytes to write is the size of the command body less the OEN and sub-command (4 346bytes) and less the structure size. 347 348On success it will return a success completion code. 349 350## Idempotent Commands 351 352The IPMI transport layer is somewhat flaky. Client code must rely on a 353"send-with-retries" strategy to ensure that commands make their way from the 354host to the BMC. Commands can fail if the BMC is busy with other commands. 355 356It is possible that an IPMI command successfully invokes the BMC-side handler, 357but that the response does not successfully make its way back to the host. In 358this case, the host may decide to retry the command. Thus, command handlers 359should be idempotent where possible; duplicate calls should return the same 360value if repeated, while avoiding potentially destructive side-effects. 361 362## Stale Sessions 363 364Each blob type will define an operation for cleansing stale sessions. This could 365involve scrubbing secrets or freeing buffers. A function will be provided that 366will scan over each open session, to determine which if any sessions have been 367open for longer than 10 minutes with no activity. For each session, the 368associated blob type’s cleansing routine will be invoked, and the associated 369session ID will be freed. This function will be invoked from the `BmcBlobOpen` 370command handler, though not more than once every minute. 371 372## Handler Calling Contract 373 374The blob manager provides the following calling contract guarantees: 375 376- The blob manager will only call `open()` on your handler if the handler 377 responds that they can handle the path. 378- The blob manager will only call a session-based command against your handler 379 if that session is already open (e.g. `stat()` or `commit()`). 380 - The caveat is the open command where the session is provided to the handler 381 within the call. 382- The blob manager will only call `delete()` on a blob if there are no open 383 sessions to that blob id. 384