1 #pragma once 2 3 #include "common/instance_id.hpp" 4 #include "common/types.hpp" 5 #include "device_updater.hpp" 6 #include "fw-update/activation.hpp" 7 #include "fw-update/update.hpp" 8 #ifdef FW_UPDATE_INOTIFY_ENABLED 9 #include "fw-update/watch.hpp" 10 #endif 11 #include "package_parser.hpp" 12 #include "requester/handler.hpp" 13 14 #include <libpldm/base.h> 15 16 #include <sdbusplus/async.hpp> 17 #include <sdbusplus/server/object.hpp> 18 #include <xyz/openbmc_project/Software/Activation/server.hpp> 19 20 #include <chrono> 21 #include <filesystem> 22 #include <fstream> 23 #include <sstream> 24 #include <tuple> 25 #include <unordered_map> 26 27 namespace pldm 28 { 29 30 namespace fw_update 31 { 32 33 using namespace sdeventplus; 34 using namespace sdeventplus::source; 35 using namespace pldm; 36 37 using DeviceIDRecordOffset = size_t; 38 using DeviceUpdaterInfo = std::pair<mctp_eid_t, DeviceIDRecordOffset>; 39 using DeviceUpdaterInfos = std::vector<DeviceUpdaterInfo>; 40 using TotalComponentUpdates = size_t; 41 42 class UpdateManager 43 { 44 public: 45 UpdateManager() = delete; 46 UpdateManager(const UpdateManager&) = delete; 47 UpdateManager(UpdateManager&&) = delete; 48 UpdateManager& operator=(const UpdateManager&) = delete; 49 UpdateManager& operator=(UpdateManager&&) = delete; 50 ~UpdateManager() = default; 51 UpdateManager(Event & event,pldm::requester::Handler<pldm::requester::Request> & handler,InstanceIdDb & instanceIdDb,const DescriptorMap & descriptorMap,const ComponentInfoMap & componentInfoMap)52 explicit UpdateManager( 53 Event& event, 54 pldm::requester::Handler<pldm::requester::Request>& handler, 55 InstanceIdDb& instanceIdDb, const DescriptorMap& descriptorMap, 56 const ComponentInfoMap& componentInfoMap) : 57 event(event), handler(handler), instanceIdDb(instanceIdDb), 58 descriptorMap(descriptorMap), componentInfoMap(componentInfoMap), 59 #ifdef FW_UPDATE_INOTIFY_ENABLED 60 watch(event.get(), 61 [this](std::string& packageFilePath) { 62 return this->processPackage( 63 std::filesystem::path(packageFilePath)); 64 }), 65 #else 66 updater(std::make_unique<Update>(pldm::utils::DBusHandler::getBus(), 67 "/xyz/openbmc_project/software/pldm", 68 this)), 69 #endif 70 totalNumComponentUpdates(0), compUpdateCompletedCount(0) 71 {} 72 73 /** @brief Handle PLDM request for the commands in the FW update 74 * specification 75 * 76 * @param[in] eid - Remote MCTP Endpoint ID 77 * @param[in] command - PLDM command code 78 * @param[in] request - PLDM request message 79 * @param[in] requestLen - PLDM request message length 80 * 81 * @return PLDM response message 82 */ 83 Response handleRequest(mctp_eid_t eid, uint8_t command, 84 const pldm_msg* request, size_t reqMsgLen); 85 86 int processPackage(const std::filesystem::path& packageFilePath); 87 88 /** @brief Process the firmware update package 89 * 90 * @param[in] packageStream - Stream of the firmware update package 91 * @param[in] packageSize - Size of the firmware update package 92 * 93 * @return Object path of the created Software object 94 */ 95 void processStream(std::istream& packageStream, uintmax_t packageSize); 96 97 /** @brief Defers processing the package stream 98 * 99 * @param[in] packageStream - Stream of the firmware update package 100 * @param[in] packageSize - Size of the firmware update package 101 * 102 * @return Object path of the created Software object as a string 103 */ 104 std::string processStreamDefer(std::istream& packageStream, 105 uintmax_t packageSize); 106 107 void updateDeviceCompletion(mctp_eid_t eid, bool status); 108 109 void updateActivationProgress(); 110 111 /** @brief Callback function that will be invoked when the 112 * RequestedActivation will be set to active in the Activation 113 * interface 114 */ 115 void activatePackage(); 116 117 void clearActivationInfo(); 118 119 /** @brief 120 * 121 */ 122 DeviceUpdaterInfos associatePkgToDevices( 123 const FirmwareDeviceIDRecords& fwDeviceIDRecords, 124 const DescriptorMap& descriptorMap, 125 TotalComponentUpdates& totalNumComponentUpdates); 126 127 /** @brief Generate a unique software ID based on current timestamp 128 * 129 * @return String representation of the current timestamp in seconds 130 */ 131 static std::string getSwId(); 132 133 const std::string swRootPath{"/xyz/openbmc_project/software/"}; 134 Event& event; //!< reference to PLDM daemon's main event loop 135 /** @brief PLDM request handler */ 136 pldm::requester::Handler<pldm::requester::Request>& handler; 137 InstanceIdDb& instanceIdDb; //!< reference to an InstanceIdDb 138 139 std::unique_ptr<Activation> activation; 140 141 private: 142 /** @brief Device identifiers of the managed FDs */ 143 const DescriptorMap& descriptorMap; 144 /** @brief Component information needed for the update of the managed FDs */ 145 const ComponentInfoMap& componentInfoMap; 146 #ifdef FW_UPDATE_INOTIFY_ENABLED 147 Watch watch; 148 #else 149 std::unique_ptr<Update> updater; 150 #endif 151 152 std::unique_ptr<ActivationProgress> activationProgress; 153 std::string objPath; 154 155 std::filesystem::path fwPackageFilePath; 156 std::unique_ptr<PackageParser> parser; 157 std::ifstream package; 158 159 std::unordered_map<mctp_eid_t, std::unique_ptr<DeviceUpdater>> 160 deviceUpdaterMap; 161 std::unordered_map<mctp_eid_t, bool> deviceUpdateCompletionMap; 162 163 /** @brief Total number of component updates to calculate the progress of 164 * the Firmware activation 165 */ 166 size_t totalNumComponentUpdates; 167 168 /** @brief FW update package can contain updates for multiple firmware 169 * devices and each device can have multiple components. Once 170 * each component is updated (Transfer completed, Verified and 171 * Applied) ActivationProgress is updated. 172 */ 173 size_t compUpdateCompletedCount; 174 decltype(std::chrono::steady_clock::now()) startTime; 175 std::unique_ptr<sdeventplus::source::Defer> updateDeferHandler; 176 }; 177 178 } // namespace fw_update 179 180 } // namespace pldm 181