{"id":18368704,"url":"https://github.com/openbmc/phosphor-ipmi-blobs","last_synced_at":"2025-09-25T11:18:11.444Z","repository":{"id":74554768,"uuid":"148496614","full_name":"openbmc/phosphor-ipmi-blobs","owner":"openbmc","description":"OpenBMC IPMI Library (Handler) For OEM IPMI Commands Corresponding to a BLOB protocol.","archived":false,"fork":false,"pushed_at":"2025-02-02T11:41:59.000Z","size":529,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-22T04:02:22.359Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openbmc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-12T14:51:09.000Z","updated_at":"2025-02-02T11:42:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"f6a6505e-868f-4aa3-a878-2247ee725fca","html_url":"https://github.com/openbmc/phosphor-ipmi-blobs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openbmc%2Fphosphor-ipmi-blobs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openbmc%2Fphosphor-ipmi-blobs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openbmc%2Fphosphor-ipmi-blobs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openbmc%2Fphosphor-ipmi-blobs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openbmc","download_url":"https://codeload.github.com/openbmc/phosphor-ipmi-blobs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247522415,"owners_count":20952544,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T23:27:06.682Z","updated_at":"2025-09-25T11:18:11.370Z","avatar_url":"https://github.com/openbmc.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phosphor Blob Transfer Interface\n\nThis document describes the commands implementing a generic blob transfer\ninterface. This document does not specify how blobs are stored; that is left up\nto blob-specific implementations. Introduction This mechanism supports reading\nand writing from a generic blob store. This mechanism can be leveraged to\nsupport firmware upgrades,\n\nThe interface defined in this document supports:\n\n- Enumerating blobs\n- Opening a blob for reading or writing\n- Writing blob content\n- Committing a blob\n- Polling until the blob has been committed\n- Closing a blob\n- Reading blob content\n- Deleting a blob\n\nSome blobs will only support a subset of these operations. For example, firmware\ncannot generally be read, as the firmware file is not persisted on the BMC after\nit has been activated.\n\nThis specification supports IPMI as a transport layer. This can be quite slow,\nhowever; IPMI transport speeds range from 23 kbps to 256 kbps. LPC/P2A (\"PCI to\nAspeed\") MMIO bridges are currently unsupported. Blob Identifiers Blobs are\nidentified by NULL-terminated C strings. This protocol supports\nimplementation-specific blob identifiers; some blobs may have single well-known\nnames, while others may be defined only by a prefix, with the client specifying\nthe rest of the blob name. For example, \"/g/bmc_firmware\" may represent a single\nwell-known blob that supports BMC firmware updates, whereas \"/g/skm/[N]\" may\nrepresent an arbitrary number of SKM keys, with the index specified on the host\nwhen opening the blob.\n\nBlob identifiers are limited based on the maximum size of the IPMI packet. This\nmaximum size is platform-dependent; theoretically a packet could be up to 256\nbytes, but some hardware only supports packets up to 64 bytes.\n\nIf an identifier is malformed, e.g. does not have a trailing NUL-byte or is\notherwise unrecognizable by the BMC, an error is returned.\n\nThe OEM Number to use with these commands is\n[openbmc oen](https://github.com/openbmc/phosphor-host-ipmid/blob/194375f2676715a0e0697bab63234a4efe39fb96/include/ipmid/iana.hpp#L12) 49871.\n\n## Commands\n\nThe following details each subcommand in the blob spec. In the following, any\nreference to the command body starts after the 3 bytes of OEM header, the 1-byte\nsubcommand code, and (in the cases where the command body is non-empty) a\ntwo-byte CRC over all data that follows in the body.\n\nAll non-empty responses should lead with a two-byte CRC. The CRC algorithm is\nCRC-16-CCITT (poly 0x1021).\n\nAll multi-byte values are encoded as little-endian. All structs are assumed\npacked. Success codes are returned via the \"completion code\" field from the IPMI\nspec.\n\n### BmcBlobGetCount (0)\n\nThe `BmcBlobGetCount` command expects to receive an empty body. The BMC will\nreturn the number of enumerable blobs:\n\n```cpp\nstruct BmcBlobCountRx {\n    uint16_t crc16;\n    uint32_t blob_count;\n};\n```\n\n### BmcBlobEnumerate (1)\n\nThe `BmcBlobEnumerate` command expects to receive a body of:\n\n```cpp\nstruct BmcBlobEnumerateTx {\n    uint16_t crc16;\n    uint32_t blob_idx; /* 0-based index of blob to retrieve. */\n};\n```\n\nThe BMC will return the corresponding blob identifier:\n\n```cpp\nstruct BmcBlobEnumerateRx {\n    uint16_t crc16;\n    char     blob_id[];\n};\n```\n\nNote that the index for a given blob ID is not expected to be stable across a\nlong term. Callers are expected to call `BmcBlobGetCount`, followed by N calls\nto `BmcBlobEnumerate`, to collect all blob IDs. Callers can then call\n`BmcBlobStat` with each blob ID. If this process is interleaved with Open or\nDelete calls that modify the number of enumerable blobs, this operation will be\nsubject to concurrent modification issues.\n\n### BmcBlobOpen (2)\n\nThe BmcBlobOpen command expects to receive a body of:\n\n```cpp\nstruct BmcBlobOpenTx {\n    uint16_t crc16;\n    uint16_t flags;\n    char     blob_id[]; /* Must correspond to a valid blob. */\n};\n```\n\nThe flags field allows the caller to specify whether the blob is being opened\nfor reading or writing:\n\n```cpp\nenum BmcBlobOpenFlagBits {\n    READ = 0,\n    WRITE = 1,\n    \u003cbits 2-7 reserved\u003e\n    \u003cbits 8-15 given blob-specific definitions\u003e\n};\n```\n\nIf the `WRITE` flag is specified, the BMC will mark the specified blob as \"open\nfor writing\". Optional blob-specific behavior: if the blob has been open for\nmore than one minute without any activity, the existing session will be torn\ndown and the open will succeed. Alternatively, blobs may allow multiple write\nsessions to be active at once.\n\nThe BMC allocates a unique session identifier, and internally maps it to the\nblob identifier.\n\n```cpp\nstruct BmcBlobOpenRx {\n    uint16_t crc16;\n    uint16_t session_id;\n};\n```\n\n### BmcBlobRead (3)\n\nThe BmcBlobRead command is used to read blob data. It expects to receive a body\nof:\n\n```cpp\nstruct BmcBlobReadTx {\n    uint16_t crc16;\n    uint16_t session_id; /* Returned from BmcBlobOpen. */\n    uint32_t offset; /* The byte sequence start, 0-based. */\n    uint32_t requested_size; /* The number of bytes requested for reading. */\n};\n```\n\nBlob handlers may require the blob’s \"state\" to equal `OPEN_R` before reading is\nsuccessful.\n\n```cpp\nstruct BmcBlobReadRx {\n    uint16_t crc16;\n    uint8_t  data[];\n};\n```\n\nImmediately following this structure are the bytes being read. The number of\nbytes transferred is the size of the response body less the OEN (\"OEM number\")\n(3 bytes), sub-command (1 byte), and the structure size (4 bytes). If no bytes\nare transferred, the CRC is still sent.\n\nIf the BMC cannot return the number of requested bytes, it simply returns the\nnumber of bytes available for reading. If the host tries to read at an invalid\noffset or if the host tries to read at the end of the blob, an empty successful\nresponse is returned; e.g., data is empty.\n\n### BmcBlobWrite (4)\n\nThe `BmcBlobWrite` command expects to receive a body of:\n\n```cpp\nstruct BmcBlobWriteTx {\n    uint16_t crc16;\n    uint16_t session_id; /* Returned from BmcBlobOpen. */\n    uint32_t offset; /* The byte sequence start, 0-based. */\n    uint8_t  data[];\n};\n```\n\nImmediately following this structure are the bytes to write. The length of the\nentire packet is variable and handled at a higher level, therefore the number of\nbytes to write is the size of the command body less the OEN and sub-command (4\nbytes) and less the structure size (10 bytes). It is assumed that all writes are\nsequential, and begin at offset zero.\n\nOn success it will return a success completion code.\n\n### BmcBlobCommit (5)\n\nThe `BmcBlobCommit` command expects to receive a body of:\n\n```cpp\nstruct BmcBlobCommitTx {\n    uint16_t crc16;\n    uint16_t session_id; /* Returned from BmcBlobOpen. */\n    uint8_t  commit_data_len;\n    uint8_t  commit_data[]; /* Optional blob-specific commit data. */\n};\n```\n\nEach blob defines its own commit behavior. A BMC firmware blob may be verified\nand saved to the filesystem. Commit operations may require additional data,\nwhich would be provided following the structure in the IPMI packet.\n\nThe commit operation may exceed the IPMI timeout duration of ~5 seconds\n(implementation dependant). Callers are expected to poll on `BmcBlobSessionStat`\nor `BmcBlobStat` (as appropriate) until committing has finished. To address race\nconditions, blobs should not allow concurrent sessions that modify state.\n\nOn success, the BMC returns success completion code.\n\n### BmcBlobClose (6)\n\nThe `BmcBlobClose` command must be called after commit-polling has finished,\nregardless of the result. It expects to receive a body of:\n\n```cpp\nstruct BmcBlobCloseTx {\n    uint16_t crc16;\n    uint16_t session_id; /* Returned from BmcBlobOpen. */\n};\n```\n\nThe BMC marks the specified blob as closed. On success, the BMC returns a\nsuccess completion code.\n\n### BmcBlobDelete (7)\n\nThe `BmcBlobDelete` command is used to delete a blob. Not all blobs will support\ndeletion. This command expects to receive a body of:\n\n```cpp\nstruct BmcBlobDeleteTx {\n    uint16_t crc16;\n    char     blob_id[]; /* Must correspond to a valid blob. */\n};\n```\n\nIf the operation is supported, the blob is deleted. On success, the BMC returns\na success completion code. This command will fail if there are open sessions for\nthe blob.\n\n### BmcBlobStat (8)\n\nThe `BmcBlobStat` command is used to retrieve statistics about a blob. Not all\nblobs must support this command; this is only useful when blob_id semantics are\nmore useful than session IDs. This command expects to receive a body of:\n\n```cpp\nstruct BmcBlobStatTx {\n    uint16_t crc16;\n    char     blob_id[]; /* Must correspond to a valid blob. */\n};\n```\n\nThe BMC returns the following data:\n\n```cpp\nstruct BmcBlobStatRx {\n    uint16_t crc16;\n    uint16_t blob_state;\n    uint32_t size; /* Size in bytes of the blob. */\n    uint8_t  metadata_len;\n    uint8_t  metadata[]; /* Optional blob-specific metadata. */\n};\n```\n\nThe blob_state field is a bit field with the following flags:\n\n```cpp\nenum BmcBlobStateFlagBits {\n    OPEN_R = 0,\n    OPEN_W = 1,\n    COMMITTING = 2,\n    COMMITTED = 3,\n    COMMIT_ERROR = 4,\n    \u003cbits 5-7 reserved\u003e\n    \u003cbits 8-15 given blob-specific definitions\u003e\n};\n```\n\nIf the state is `COMMITTING`, the blob is not currently available for reading or\nwriting. If the state is `COMMITTED`, the blob may be available for reading.\n\nThe size field may be zero if the blob does not support reading.\n\nImmediately following this structure are optional blob-specific bytes. The\nnumber of bytes transferred is the size of the response body less the OEN and\nsub-command and less the structure size. The metadata must fit in a single IPMI\npacket, which has a platform-dependent maximum size. (For reference, Aspeed\nsupports 64 bytes max.)\n\nIf the blob is open or committed but has been inactive for longer than the\nspecified activity timeout, the blob is closed, and blob_status is set to\n`CLOSED` in the response.\n\n### BmcBlobSessionStat (9)\n\nThe `BmcBlobSessionStat` command returns the same data as `BmcBlobStat`.\nHowever, this command operates on sessions, rather than blob IDs. Not all blobs\nmust support this command; this is only useful when session semantics are more\nuseful than raw blob IDs.\n\n```cpp\nstruct BmcBlobSessionStatTx {\n    uint16_t crc16;\n    uint16_t session_id; /* Returned from BmcBlobOpen. */\n};\n```\n\n```cpp\nstruct BmcBlobSessionStatRx {\n    uint16_t crc16;\n    uint16_t blob_state;\n    uint32_t size; /* Size in bytes of the blob. */\n    uint8_t  metadata_size;\n    uint8_t  metadata[]; /* Optional blob-specific metadata. */\n};\n```\n\n### BmcBlobWriteMeta (10)\n\nThe `BmcBlobWriteMeta` command behaves like `BmcBlobWrite`. Its purpose is\nblob-specific, and not all blobs must support it.\n\nThe `BmcBlobWriteMeta` command expects to receive a body of:\n\n```cpp\nstruct BmcBlobWriteMetaTx\n{\n    uint16_t crc16;\n    uint16_t session_id; /* Returned from BmcBlobOpen. */\n    uint32_t offset; /* The byte sequence start, 0-based. */\n    uint8_t  data[];\n};\n```\n\nImmediately following this structure are the bytes to write. The length of the\nentire packet is variable and handled at a higher level, therefore the number of\nbytes to write is the size of the command body less the OEN and sub-command (4\nbytes) and less the structure size.\n\nOn success it will return a success completion code.\n\n## Idempotent Commands\n\nThe IPMI transport layer is somewhat flaky. Client code must rely on a\n\"send-with-retries\" strategy to ensure that commands make their way from the\nhost to the BMC. Commands can fail if the BMC is busy with other commands.\n\nIt is possible that an IPMI command successfully invokes the BMC-side handler,\nbut that the response does not successfully make its way back to the host. In\nthis case, the host may decide to retry the command. Thus, command handlers\nshould be idempotent where possible; duplicate calls should return the same\nvalue if repeated, while avoiding potentially destructive side-effects.\n\n## Stale Sessions\n\nEach blob type will define an operation for cleansing stale sessions. This could\ninvolve scrubbing secrets or freeing buffers. A function will be provided that\nwill scan over each open session, to determine which if any sessions have been\nopen for longer than 10 minutes with no activity. For each session, the\nassociated blob type’s cleansing routine will be invoked, and the associated\nsession ID will be freed. This function will be invoked from the `BmcBlobOpen`\ncommand handler, though not more than once every minute.\n\n## Handler Calling Contract\n\nThe blob manager provides the following calling contract guarantees:\n\n- The blob manager will only call `open()` on your handler if the handler\n  responds that they can handle the path.\n- The blob manager will only call a session-based command against your handler\n  if that session is already open (e.g. `stat()` or `commit()`).\n  - The caveat is the open command where the session is provided to the handler\n    within the call.\n- The blob manager will only call `delete()` on a blob if there are no open\n  sessions to that blob id.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenbmc%2Fphosphor-ipmi-blobs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenbmc%2Fphosphor-ipmi-blobs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenbmc%2Fphosphor-ipmi-blobs/lists"}