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