move files around to create a common convenience library
Problem: plan is to add another blob handler into ipmi-flash
(ipmi-flash-version). This new handler will re-use much of the
ipmi-flash (firmware-handler) code. The common code should be presented
as a convenience library to reduce code duplication.
Solution: move anticipated firmware-handler specific code into the
subdirectory bmc/firmware-handler and leave common code in bmc/.
The end goal is to have version-handler re-use as
much code as possible.
Tested:
rebuilt everything and ran unit tests.
Signed-off-by: Jason Ling <jasonling@google.com>
Change-Id: I2128da629b0ddf27b89f1faee358d1941f1dff38
diff --git a/bmc/firmware-handler/firmware_handler.hpp b/bmc/firmware-handler/firmware_handler.hpp
new file mode 100644
index 0000000..505f1a7
--- /dev/null
+++ b/bmc/firmware-handler/firmware_handler.hpp
@@ -0,0 +1,264 @@
+#pragma once
+
+#include "config.h"
+
+#include "data_handler.hpp"
+#include "image_handler.hpp"
+#include "status.hpp"
+#include "util.hpp"
+
+#include <blobs-ipmid/blobs.hpp>
+
+#include <algorithm>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace ipmi_flash
+{
+
+/**
+ * Given a firmware name, provide a set of triggerable action interfaces
+ * associated with that firmware type.
+ */
+struct ActionPack
+{
+ /** The name of the action pack, something like image, or tarball, or bios.
+ * The firmware blob id is parsed to pull the "filename" portion from the
+ * path, and matched against the key to a map of these.
+ */
+ std::unique_ptr<TriggerableActionInterface> preparation;
+ std::unique_ptr<TriggerableActionInterface> verification;
+ std::unique_ptr<TriggerableActionInterface> update;
+};
+
+using ActionMap =
+ std::unordered_map<std::string, std::unique_ptr<ipmi_flash::ActionPack>>;
+
+/**
+ * Representation of a session, includes how to read/write data.
+ */
+struct Session
+{
+ /**
+ * Built a session object.
+ *
+ * @param[in] the active path to which this corresponds.
+ */
+ explicit Session(const std::string& path) :
+ dataHandler(nullptr), imageHandler(nullptr), flags(0), activePath(path)
+ {}
+
+ /**
+ * Pointer to the correct Data handler interface. (nullptr on BT (or KCS))
+ */
+ DataInterface* dataHandler;
+
+ /**
+ * Pointer to the correct image handler interface. (nullptr on hash
+ * blob_id)
+ */
+ ipmi_flash::ImageHandlerInterface* imageHandler;
+
+ /** The flags used to open the session. */
+ std::uint16_t flags;
+
+ /** The active path. */
+ std::string activePath;
+};
+
+/**
+ * Register only one firmware blob handler that will manage all sessions.
+ */
+class FirmwareBlobHandler : public blobs::GenericBlobInterface
+{
+ public:
+ /** The state of the firmware update process. */
+ enum class UpdateState
+ {
+ /** The initial state. */
+ notYetStarted = 0,
+ /** The BMC is expecting to receive bytes. */
+ uploadInProgress,
+ /** The BMC is ready for verification or more bytes. */
+ verificationPending,
+ /** The verification process has started, no more writes allowed. */
+ verificationStarted,
+ /** The verification process has completed. */
+ verificationCompleted,
+ /** The update process is pending. */
+ updatePending,
+ /** The update process has started. */
+ updateStarted,
+ /** The update has completed (optional state to reach) */
+ updateCompleted,
+ };
+
+ /**
+ * Create a FirmwareBlobHandler.
+ *
+ * @param[in] firmwares - list of firmware blob_ids to support.
+ * @param[in] transports - list of transports to support.
+ * @param[in] verification - pointer to object for triggering verification
+ * @param[in] update - point to object for triggering the update
+ */
+ static std::unique_ptr<blobs::GenericBlobInterface>
+ CreateFirmwareBlobHandler(std::vector<HandlerPack>&& firmwares,
+ std::vector<DataHandlerPack>&& transports,
+ ActionMap&& actionPacks);
+
+ /**
+ * Create a FirmwareBlobHandler.
+ *
+ * @param[in] firmwares - list of firmware types and their handlers
+ * @param[in] blobs - list of blobs_ids to support
+ * @param[in] transports - list of transport types and their handlers
+ * @param[in] verification - pointer to object for triggering verification
+ * @param[in] update - point to object for triggering the update
+ */
+ FirmwareBlobHandler(std::vector<HandlerPack>&& firmwares,
+ const std::vector<std::string>& blobs,
+ std::vector<DataHandlerPack>&& transports,
+ ActionMap&& actionPacks) :
+ handlers(std::move(firmwares)),
+ blobIDs(blobs), transports(std::move(transports)),
+ activeImage(activeImageBlobId), activeHash(activeHashBlobId),
+ verifyImage(verifyBlobId), updateImage(updateBlobId), lookup(),
+ state(UpdateState::notYetStarted), actionPacks(std::move(actionPacks))
+ {}
+ ~FirmwareBlobHandler() = default;
+ FirmwareBlobHandler(const FirmwareBlobHandler&) = delete;
+ FirmwareBlobHandler& operator=(const FirmwareBlobHandler&) = delete;
+ FirmwareBlobHandler(FirmwareBlobHandler&&) = default;
+ FirmwareBlobHandler& operator=(FirmwareBlobHandler&&) = default;
+
+ bool canHandleBlob(const std::string& path) override;
+ std::vector<std::string> getBlobIds() override;
+ bool deleteBlob(const std::string& path) override;
+ bool stat(const std::string& path, blobs::BlobMeta* meta) override;
+ bool open(uint16_t session, uint16_t flags,
+ const std::string& path) override;
+ std::vector<uint8_t> read(uint16_t session, uint32_t offset,
+ uint32_t requestedSize) override;
+ bool write(uint16_t session, uint32_t offset,
+ const std::vector<uint8_t>& data) override;
+ bool writeMeta(uint16_t session, uint32_t offset,
+ const std::vector<uint8_t>& data) override;
+ bool commit(uint16_t session, const std::vector<uint8_t>& data) override;
+ bool close(uint16_t session) override;
+ bool stat(uint16_t session, blobs::BlobMeta* meta) override;
+ bool expire(uint16_t session) override;
+
+ void abortProcess();
+
+ void abortVerification();
+ bool triggerVerification();
+ void abortUpdate();
+ bool triggerUpdate();
+
+ /** Allow grabbing the current state. */
+ UpdateState getCurrentState() const
+ {
+ return state;
+ };
+
+ /** Provide for any state change triggers in convenience handler. */
+ void changeState(UpdateState next);
+
+ private:
+ /**
+ * Given the current session type, grab the ActionPack (likely will be
+ * worked into the Session for lookup).
+ */
+ ActionPack* getActionPack()
+ {
+ if (openedFirmwareType.empty())
+ {
+ /* No firmware type has been opened, but we're triggering
+ * verification, or preparing. This can happen if they open the hash
+ * before the image, which is possible.
+ */
+ return nullptr;
+ }
+
+ /* TODO: Once the actionPacks and supportedFirmwares are merged this'll
+ * be less dangerous
+ */
+ return actionPacks[openedFirmwareType].get();
+ }
+
+ void addBlobId(const std::string& blob)
+ {
+ auto blobIdMatch = std::find_if(
+ blobIDs.begin(), blobIDs.end(),
+ [&blob](const std::string& iter) { return (iter == blob); });
+ if (blobIdMatch == blobIDs.end())
+ {
+ blobIDs.push_back(blob);
+ }
+ }
+
+ void removeBlobId(const std::string& blob)
+ {
+ blobIDs.erase(std::remove(blobIDs.begin(), blobIDs.end(), blob),
+ blobIDs.end());
+ }
+
+ inline bool fileOpen()
+ {
+ return !lookup.empty();
+ }
+
+ ActionStatus getVerifyStatus();
+ ActionStatus getActionStatus();
+
+ /** List of handlers by type. */
+ std::vector<HandlerPack> handlers;
+
+ /** Active list of blobIDs. */
+ std::vector<std::string> blobIDs;
+
+ /** List of handlers by transport type. */
+ std::vector<DataHandlerPack> transports;
+
+ /** Active image session. */
+ Session activeImage;
+
+ /** Active hash session. */
+ Session activeHash;
+
+ /** Session for verification. */
+ Session verifyImage;
+
+ /** Session for update. */
+ Session updateImage;
+
+ /** A quick method for looking up a session's mechanisms and details. */
+ std::map<std::uint16_t, Session*> lookup;
+
+ /** The firmware update state. */
+ UpdateState state;
+
+ /** Track what firmware blobid they opened to start this sequence. */
+ std::string openedFirmwareType;
+
+ /* preparation is triggered once we go into uploadInProgress(), but only
+ * once per full cycle, going back to notYetStarted resets this.
+ */
+ bool preparationTriggered = false;
+ ActionMap actionPacks;
+
+ ActionStatus lastVerificationStatus = ActionStatus::unknown;
+
+ ActionStatus lastUpdateStatus = ActionStatus::unknown;
+
+ /** Portion of "flags" argument to open() which specifies the desired
+ * transport type
+ */
+ static constexpr std::uint16_t transportMask = 0xff00;
+};
+
+} // namespace ipmi_flash