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