1ded66d0fSJason Ling #pragma once
2ded66d0fSJason Ling 
3ded66d0fSJason Ling #include "config.h"
4ded66d0fSJason Ling 
5ded66d0fSJason Ling #include "data_handler.hpp"
6ded66d0fSJason Ling #include "image_handler.hpp"
7ded66d0fSJason Ling #include "status.hpp"
8ded66d0fSJason Ling #include "util.hpp"
9ded66d0fSJason Ling 
10ded66d0fSJason Ling #include <blobs-ipmid/blobs.hpp>
11ded66d0fSJason Ling 
12ded66d0fSJason Ling #include <algorithm>
13ded66d0fSJason Ling #include <cstdint>
14ded66d0fSJason Ling #include <map>
15ded66d0fSJason Ling #include <memory>
16ded66d0fSJason Ling #include <string>
17ded66d0fSJason Ling #include <unordered_map>
18ded66d0fSJason Ling #include <vector>
19ded66d0fSJason Ling 
20ded66d0fSJason Ling namespace ipmi_flash
21ded66d0fSJason Ling {
22ded66d0fSJason Ling 
23ded66d0fSJason Ling /**
24ded66d0fSJason Ling  * Given a firmware name, provide a set of triggerable action interfaces
25ded66d0fSJason Ling  * associated with that firmware type.
26ded66d0fSJason Ling  */
27ded66d0fSJason Ling struct ActionPack
28ded66d0fSJason Ling {
29ded66d0fSJason Ling     /** The name of the action pack, something like image, or tarball, or bios.
30ded66d0fSJason Ling      * The firmware blob id is parsed to pull the "filename" portion from the
31ded66d0fSJason Ling      * path, and matched against the key to a map of these.
32ded66d0fSJason Ling      */
33ded66d0fSJason Ling     std::unique_ptr<TriggerableActionInterface> preparation;
34ded66d0fSJason Ling     std::unique_ptr<TriggerableActionInterface> verification;
35ded66d0fSJason Ling     std::unique_ptr<TriggerableActionInterface> update;
36ded66d0fSJason Ling };
37ded66d0fSJason Ling 
38ded66d0fSJason Ling using ActionMap =
39ded66d0fSJason Ling     std::unordered_map<std::string, std::unique_ptr<ipmi_flash::ActionPack>>;
40ded66d0fSJason Ling 
41ded66d0fSJason Ling /**
42ded66d0fSJason Ling  * Representation of a session, includes how to read/write data.
43ded66d0fSJason Ling  */
44ded66d0fSJason Ling struct Session
45ded66d0fSJason Ling {
46ded66d0fSJason Ling     /**
47ded66d0fSJason Ling      * Built a session object.
48ded66d0fSJason Ling      *
49ded66d0fSJason Ling      * @param[in] the active path to which this corresponds.
50ded66d0fSJason Ling      */
51ded66d0fSJason Ling     explicit Session(const std::string& path) :
52ded66d0fSJason Ling         dataHandler(nullptr), imageHandler(nullptr), flags(0), activePath(path)
53ded66d0fSJason Ling     {}
54ded66d0fSJason Ling 
55ded66d0fSJason Ling     /**
56ded66d0fSJason Ling      * Pointer to the correct Data handler interface. (nullptr on BT (or KCS))
57ded66d0fSJason Ling      */
58ded66d0fSJason Ling     DataInterface* dataHandler;
59ded66d0fSJason Ling 
60ded66d0fSJason Ling     /**
61ded66d0fSJason Ling      * Pointer to the correct image handler interface.  (nullptr on hash
62ded66d0fSJason Ling      * blob_id)
63ded66d0fSJason Ling      */
64ded66d0fSJason Ling     ipmi_flash::ImageHandlerInterface* imageHandler;
65ded66d0fSJason Ling 
66ded66d0fSJason Ling     /** The flags used to open the session. */
67ded66d0fSJason Ling     std::uint16_t flags;
68ded66d0fSJason Ling 
69ded66d0fSJason Ling     /** The active path. */
70ded66d0fSJason Ling     std::string activePath;
71ded66d0fSJason Ling };
72ded66d0fSJason Ling 
73ded66d0fSJason Ling /**
74ded66d0fSJason Ling  * Register only one firmware blob handler that will manage all sessions.
75ded66d0fSJason Ling  */
76ded66d0fSJason Ling class FirmwareBlobHandler : public blobs::GenericBlobInterface
77ded66d0fSJason Ling {
78ded66d0fSJason Ling   public:
79ded66d0fSJason Ling     /** The state of the firmware update process. */
80ded66d0fSJason Ling     enum class UpdateState
81ded66d0fSJason Ling     {
82ded66d0fSJason Ling         /** The initial state. */
83ded66d0fSJason Ling         notYetStarted = 0,
84ded66d0fSJason Ling         /** The BMC is expecting to receive bytes. */
85ded66d0fSJason Ling         uploadInProgress,
86ded66d0fSJason Ling         /** The BMC is ready for verification or more bytes. */
87ded66d0fSJason Ling         verificationPending,
88ded66d0fSJason Ling         /** The verification process has started, no more writes allowed. */
89ded66d0fSJason Ling         verificationStarted,
90ded66d0fSJason Ling         /** The verification process has completed. */
91ded66d0fSJason Ling         verificationCompleted,
92ded66d0fSJason Ling         /** The update process is pending. */
93ded66d0fSJason Ling         updatePending,
94ded66d0fSJason Ling         /** The update process has started. */
95ded66d0fSJason Ling         updateStarted,
96ded66d0fSJason Ling         /** The update has completed (optional state to reach) */
97ded66d0fSJason Ling         updateCompleted,
98ded66d0fSJason Ling     };
99ded66d0fSJason Ling 
100ded66d0fSJason Ling     /**
101ded66d0fSJason Ling      * Create a FirmwareBlobHandler.
102ded66d0fSJason Ling      *
103ded66d0fSJason Ling      * @param[in] firmwares - list of firmware blob_ids to support.
104ded66d0fSJason Ling      * @param[in] transports - list of transports to support.
105ded66d0fSJason Ling      * @param[in] verification - pointer to object for triggering verification
106ded66d0fSJason Ling      * @param[in] update - point to object for triggering the update
107ded66d0fSJason Ling      */
108ded66d0fSJason Ling     static std::unique_ptr<blobs::GenericBlobInterface>
109ded66d0fSJason Ling         CreateFirmwareBlobHandler(std::vector<HandlerPack>&& firmwares,
110ded66d0fSJason Ling                                   std::vector<DataHandlerPack>&& transports,
111ded66d0fSJason Ling                                   ActionMap&& actionPacks);
112ded66d0fSJason Ling 
113ded66d0fSJason Ling     /**
114ded66d0fSJason Ling      * Create a FirmwareBlobHandler.
115ded66d0fSJason Ling      *
116ded66d0fSJason Ling      * @param[in] firmwares - list of firmware types and their handlers
117ded66d0fSJason Ling      * @param[in] blobs - list of blobs_ids to support
118ded66d0fSJason Ling      * @param[in] transports - list of transport types and their handlers
119ded66d0fSJason Ling      * @param[in] verification - pointer to object for triggering verification
120ded66d0fSJason Ling      * @param[in] update - point to object for triggering the update
121ded66d0fSJason Ling      */
122ded66d0fSJason Ling     FirmwareBlobHandler(std::vector<HandlerPack>&& firmwares,
123ded66d0fSJason Ling                         const std::vector<std::string>& blobs,
124ded66d0fSJason Ling                         std::vector<DataHandlerPack>&& transports,
125ded66d0fSJason Ling                         ActionMap&& actionPacks) :
126ded66d0fSJason Ling         handlers(std::move(firmwares)),
127ded66d0fSJason Ling         blobIDs(blobs), transports(std::move(transports)),
128ded66d0fSJason Ling         activeImage(activeImageBlobId), activeHash(activeHashBlobId),
129ded66d0fSJason Ling         verifyImage(verifyBlobId), updateImage(updateBlobId), lookup(),
130ded66d0fSJason Ling         state(UpdateState::notYetStarted), actionPacks(std::move(actionPacks))
131ded66d0fSJason Ling     {}
132ded66d0fSJason Ling     ~FirmwareBlobHandler() = default;
133ded66d0fSJason Ling     FirmwareBlobHandler(const FirmwareBlobHandler&) = delete;
134ded66d0fSJason Ling     FirmwareBlobHandler& operator=(const FirmwareBlobHandler&) = delete;
135ded66d0fSJason Ling     FirmwareBlobHandler(FirmwareBlobHandler&&) = default;
136ded66d0fSJason Ling     FirmwareBlobHandler& operator=(FirmwareBlobHandler&&) = default;
137ded66d0fSJason Ling 
138ded66d0fSJason Ling     bool canHandleBlob(const std::string& path) override;
139ded66d0fSJason Ling     std::vector<std::string> getBlobIds() override;
140ded66d0fSJason Ling     bool deleteBlob(const std::string& path) override;
141ded66d0fSJason Ling     bool stat(const std::string& path, blobs::BlobMeta* meta) override;
142ded66d0fSJason Ling     bool open(uint16_t session, uint16_t flags,
143ded66d0fSJason Ling               const std::string& path) override;
144ded66d0fSJason Ling     std::vector<uint8_t> read(uint16_t session, uint32_t offset,
145ded66d0fSJason Ling                               uint32_t requestedSize) override;
146ded66d0fSJason Ling     bool write(uint16_t session, uint32_t offset,
147ded66d0fSJason Ling                const std::vector<uint8_t>& data) override;
148ded66d0fSJason Ling     bool writeMeta(uint16_t session, uint32_t offset,
149ded66d0fSJason Ling                    const std::vector<uint8_t>& data) override;
150ded66d0fSJason Ling     bool commit(uint16_t session, const std::vector<uint8_t>& data) override;
151ded66d0fSJason Ling     bool close(uint16_t session) override;
152ded66d0fSJason Ling     bool stat(uint16_t session, blobs::BlobMeta* meta) override;
153ded66d0fSJason Ling     bool expire(uint16_t session) override;
154ded66d0fSJason Ling 
155ded66d0fSJason Ling     void abortProcess();
156ded66d0fSJason Ling 
157ded66d0fSJason Ling     void abortVerification();
158ded66d0fSJason Ling     bool triggerVerification();
159ded66d0fSJason Ling     void abortUpdate();
160ded66d0fSJason Ling     bool triggerUpdate();
161ded66d0fSJason Ling 
162ded66d0fSJason Ling     /** Allow grabbing the current state. */
163ded66d0fSJason Ling     UpdateState getCurrentState() const
164ded66d0fSJason Ling     {
165ded66d0fSJason Ling         return state;
166ded66d0fSJason Ling     };
167ded66d0fSJason Ling 
168ded66d0fSJason Ling     /** Provide for any state change triggers in convenience handler. */
169ded66d0fSJason Ling     void changeState(UpdateState next);
170ded66d0fSJason Ling 
171ded66d0fSJason Ling   private:
172ded66d0fSJason Ling     /**
173ded66d0fSJason Ling      * Given the current session type, grab the ActionPack (likely will be
174ded66d0fSJason Ling      * worked into the Session for lookup).
175ded66d0fSJason Ling      */
176ded66d0fSJason Ling     ActionPack* getActionPack()
177ded66d0fSJason Ling     {
178ded66d0fSJason Ling         if (openedFirmwareType.empty())
179ded66d0fSJason Ling         {
180ded66d0fSJason Ling             /* No firmware type has been opened, but we're triggering
181ded66d0fSJason Ling              * verification, or preparing. This can happen if they open the hash
182ded66d0fSJason Ling              * before the image, which is possible.
183ded66d0fSJason Ling              */
184ded66d0fSJason Ling             return nullptr;
185ded66d0fSJason Ling         }
186ded66d0fSJason Ling 
187ded66d0fSJason Ling         /* TODO: Once the actionPacks and supportedFirmwares are merged this'll
188ded66d0fSJason Ling          * be less dangerous
189ded66d0fSJason Ling          */
190ded66d0fSJason Ling         return actionPacks[openedFirmwareType].get();
191ded66d0fSJason Ling     }
192ded66d0fSJason Ling 
193ded66d0fSJason Ling     void addBlobId(const std::string& blob)
194ded66d0fSJason Ling     {
195*a9423469SPatrick Williams         auto blobIdMatch = std::find_if(
196*a9423469SPatrick Williams             blobIDs.begin(), blobIDs.end(),
197*a9423469SPatrick Williams             [&blob](const std::string& iter) { return (iter == blob); });
198ded66d0fSJason Ling         if (blobIdMatch == blobIDs.end())
199ded66d0fSJason Ling         {
200ded66d0fSJason Ling             blobIDs.push_back(blob);
201ded66d0fSJason Ling         }
202ded66d0fSJason Ling     }
203ded66d0fSJason Ling 
204ded66d0fSJason Ling     void removeBlobId(const std::string& blob)
205ded66d0fSJason Ling     {
206ded66d0fSJason Ling         blobIDs.erase(std::remove(blobIDs.begin(), blobIDs.end(), blob),
207ded66d0fSJason Ling                       blobIDs.end());
208ded66d0fSJason Ling     }
209ded66d0fSJason Ling 
210ded66d0fSJason Ling     inline bool fileOpen()
211ded66d0fSJason Ling     {
212ded66d0fSJason Ling         return !lookup.empty();
213ded66d0fSJason Ling     }
214ded66d0fSJason Ling 
215ded66d0fSJason Ling     ActionStatus getVerifyStatus();
216ded66d0fSJason Ling     ActionStatus getActionStatus();
217ded66d0fSJason Ling 
218ded66d0fSJason Ling     /** List of handlers by type. */
219ded66d0fSJason Ling     std::vector<HandlerPack> handlers;
220ded66d0fSJason Ling 
221ded66d0fSJason Ling     /** Active list of blobIDs. */
222ded66d0fSJason Ling     std::vector<std::string> blobIDs;
223ded66d0fSJason Ling 
224ded66d0fSJason Ling     /** List of handlers by transport type. */
225ded66d0fSJason Ling     std::vector<DataHandlerPack> transports;
226ded66d0fSJason Ling 
227ded66d0fSJason Ling     /** Active image session. */
228ded66d0fSJason Ling     Session activeImage;
229ded66d0fSJason Ling 
230ded66d0fSJason Ling     /** Active hash session. */
231ded66d0fSJason Ling     Session activeHash;
232ded66d0fSJason Ling 
233ded66d0fSJason Ling     /** Session for verification. */
234ded66d0fSJason Ling     Session verifyImage;
235ded66d0fSJason Ling 
236ded66d0fSJason Ling     /** Session for update. */
237ded66d0fSJason Ling     Session updateImage;
238ded66d0fSJason Ling 
239ded66d0fSJason Ling     /** A quick method for looking up a session's mechanisms and details. */
240ded66d0fSJason Ling     std::map<std::uint16_t, Session*> lookup;
241ded66d0fSJason Ling 
242ded66d0fSJason Ling     /** The firmware update state. */
243ded66d0fSJason Ling     UpdateState state;
244ded66d0fSJason Ling 
245ded66d0fSJason Ling     /** Track what firmware blobid they opened to start this sequence. */
246ded66d0fSJason Ling     std::string openedFirmwareType;
247ded66d0fSJason Ling 
248ded66d0fSJason Ling     /* preparation is triggered once we go into uploadInProgress(), but only
249ded66d0fSJason Ling      * once per full cycle, going back to notYetStarted resets this.
250ded66d0fSJason Ling      */
251ded66d0fSJason Ling     bool preparationTriggered = false;
252ded66d0fSJason Ling     ActionMap actionPacks;
253ded66d0fSJason Ling 
254ded66d0fSJason Ling     ActionStatus lastVerificationStatus = ActionStatus::unknown;
255ded66d0fSJason Ling 
256ded66d0fSJason Ling     ActionStatus lastUpdateStatus = ActionStatus::unknown;
257ded66d0fSJason Ling 
258ded66d0fSJason Ling     /** Portion of "flags" argument to open() which specifies the desired
259ded66d0fSJason Ling      *  transport type
260ded66d0fSJason Ling      */
261ded66d0fSJason Ling     static constexpr std::uint16_t transportMask = 0xff00;
262ded66d0fSJason Ling };
263ded66d0fSJason Ling 
264ded66d0fSJason Ling } // namespace ipmi_flash
265