fw update: pldm package parser
The code is taken from 'pldm' repo, but there is an ongoing effort to
make it part of libpldm [1].
The intent of this patch is to provide a few high-level functions to
parse a PLDM fw update package.
If/when the package parser is available in libpldm, this code can be
dropped.
References:
- [1] https://gerrit.openbmc.org/c/openbmc/libpldm/+/77095
Tested: next patch in series
Change-Id: I8212d88702e59d9d78965baf4e8c2243b8035b42
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/common/pldm/package_parser.hpp b/common/pldm/package_parser.hpp
new file mode 100644
index 0000000..67f9b95
--- /dev/null
+++ b/common/pldm/package_parser.hpp
@@ -0,0 +1,192 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <libpldm/firmware_update.h>
+
+#include <array>
+#include <cstdint>
+#include <memory>
+#include <tuple>
+#include <vector>
+
+// NOLINTBEGIN
+
+namespace pldm
+{
+
+namespace fw_update
+{
+
+/** @class PackageParser
+ *
+ * PackageParser is the abstract base class for parsing the PLDM firmware
+ * update package. The PLDM firmware update contains two major sections; the
+ * firmware package header, and the firmware package payload. Each package
+ * header version will have a concrete implementation of the PackageParser.
+ * The concrete implementation understands the format of the package header and
+ * will implement the parse API.
+ */
+class PackageParser
+{
+ public:
+ PackageParser() = delete;
+ PackageParser(const PackageParser&) = delete;
+ PackageParser(PackageParser&&) = default;
+ PackageParser& operator=(const PackageParser&) = delete;
+ PackageParser& operator=(PackageParser&&) = delete;
+ virtual ~PackageParser() = default;
+
+ /** @brief Constructor
+ *
+ * @param[in] pkgHeaderSize - Size of package header section
+ * @param[in] pkgVersion - Package version
+ * @param[in] componentBitmapBitLength - The number of bits used to
+ * represent the bitmap in the
+ * ApplicableComponents field for a
+ * matching device.
+ */
+ explicit PackageParser(PackageHeaderSize pkgHeaderSize,
+ const PackageVersion& pkgVersion,
+ ComponentBitmapBitLength componentBitmapBitLength) :
+ pkgHeaderSize(pkgHeaderSize), pkgVersion(pkgVersion),
+ componentBitmapBitLength(componentBitmapBitLength)
+ {}
+
+ /** @brief Parse the firmware update package header
+ *
+ * @param[in] pkgHdr - Package header
+ * @param[in] pkgSize - Size of the firmware update package
+ *
+ * @note Throws exception is parsing fails
+ */
+ virtual void parse(const std::vector<uint8_t>& pkgHdr,
+ uintmax_t pkgSize) = 0;
+
+ /** @brief Get firmware device ID records from the package
+ *
+ * @return if parsing the package is successful, return firmware device ID
+ * records
+ */
+ const FirmwareDeviceIDRecords& getFwDeviceIDRecords() const
+ {
+ return fwDeviceIDRecords;
+ }
+
+ /** @brief Get component image information from the package
+ *
+ * @return if parsing the package is successful, return component image
+ * information
+ */
+ const ComponentImageInfos& getComponentImageInfos() const
+ {
+ return componentImageInfos;
+ }
+
+ /** @brief Device identifiers of the managed FDs */
+ const PackageHeaderSize pkgHeaderSize;
+
+ /** @brief Package version string */
+ const PackageVersion pkgVersion;
+
+ protected:
+ /** @brief Parse the firmware device identification area
+ *
+ * @param[in] deviceIdRecCount - count of firmware device ID records
+ * @param[in] pkgHdr - firmware package header
+ * @param[in] offset - offset in package header which is the start of the
+ * firmware device identification area
+ *
+ * @return On success return the offset which is the end of the firmware
+ * device identification area, on error throw exception.
+ */
+ size_t parseFDIdentificationArea(DeviceIDRecordCount deviceIdRecCount,
+ const std::vector<uint8_t>& pkgHdr,
+ size_t offset);
+
+ /** @brief Parse the component image information area
+ *
+ * @param[in] compImageCount - component image count
+ * @param[in] pkgHdr - firmware package header
+ * @param[in] offset - offset in package header which is the start of the
+ * component image information area
+ *
+ * @return On success return the offset which is the end of the component
+ * image information area, on error throw exception.
+ */
+ size_t parseCompImageInfoArea(ComponentImageCount compImageCount,
+ const std::vector<uint8_t>& pkgHdr,
+ size_t offset);
+
+ /** @brief Validate the total size of the package
+ *
+ * Verify the total size of the package is the sum of package header and
+ * the size of each component.
+ *
+ * @param[in] pkgSize - firmware update package size
+ *
+ * @note Throws exception if validation fails
+ */
+ void validatePkgTotalSize(uintmax_t pkgSize);
+
+ /** @brief Firmware Device ID Records in the package */
+ FirmwareDeviceIDRecords fwDeviceIDRecords;
+
+ /** @brief Component Image Information in the package */
+ ComponentImageInfos componentImageInfos;
+
+ /** @brief The number of bits that will be used to represent the bitmap in
+ * the ApplicableComponents field for matching device. The value
+ * shall be a multiple of 8 and be large enough to contain a bit
+ * for each component in the package.
+ */
+ const ComponentBitmapBitLength componentBitmapBitLength;
+};
+
+/** @class PackageParserV1
+ *
+ * This class implements the package parser for the header format version 0x01
+ */
+class PackageParserV1 final : public PackageParser
+{
+ public:
+ PackageParserV1() = delete;
+ PackageParserV1(const PackageParserV1&) = delete;
+ PackageParserV1(PackageParserV1&&) = default;
+ PackageParserV1& operator=(const PackageParserV1&) = delete;
+ PackageParserV1& operator=(PackageParserV1&&) = delete;
+ ~PackageParserV1() = default;
+
+ /** @brief Constructor
+ *
+ * @param[in] pkgHeaderSize - Size of package header section
+ * @param[in] pkgVersion - Package version
+ * @param[in] componentBitmapBitLength - The number of bits used to
+ * represent the bitmap in the
+ * ApplicableComponents field for a
+ * matching device.
+ */
+ explicit PackageParserV1(
+ PackageHeaderSize pkgHeaderSize, const PackageVersion& pkgVersion,
+ ComponentBitmapBitLength componentBitmapBitLength) :
+ PackageParser(pkgHeaderSize, pkgVersion, componentBitmapBitLength)
+ {}
+
+ virtual void parse(const std::vector<uint8_t>& pkgHdr, uintmax_t pkgSize);
+};
+
+/** @brief Parse the package header information
+ *
+ * @param[in] pkgHdrInfo - package header information section in the package
+ *
+ * @return On success return the PackageParser for the header format version
+ * on failure return nullptr
+ */
+std::unique_ptr<PackageParser>
+ parsePackageHeader(std::vector<uint8_t>& pkgHdrInfo);
+
+} // namespace fw_update
+
+} // namespace pldm
+
+// NOLINTEND