xref: /openbmc/phosphor-ipmi-blobs/README.md (revision 9260be38)
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 [openbmc oen](https://github.com/openbmc/phosphor-host-ipmid/blob/194375f2676715a0e0697bab63234a4efe39fb96/include/ipmid/iana.hpp#L12)
43 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
208data, which
209would 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
346of bytes to write is the size of the command body less the OEN and sub-command
347(4 bytes) 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