1 #pragma once 2 3 #include "common/types.hpp" 4 #include "requester/handler.hpp" 5 #include "requester/request.hpp" 6 7 #include <sdbusplus/timer.hpp> 8 #include <sdeventplus/event.hpp> 9 #include <sdeventplus/source/event.hpp> 10 11 #include <fstream> 12 #include <numeric> 13 14 namespace pldm 15 { 16 17 namespace fw_update 18 { 19 20 /** @brief Type alias for component update status tracking 21 * Maps component index to its update completion status (true indicates 22 * successful completion, false indicates cancellation) 23 */ 24 using ComponentUpdateStatusMap = std::map<size_t, bool>; 25 26 class UpdateManager; 27 28 /** @class UpdateProgress 29 * 30 * Attempts to provide accurate reporting of firmware update progress 31 * Called at the various phases of firmware update. 32 * A single UpdateProgress object represents a component of a pldm package 33 */ 34 class UpdateProgress 35 { 36 public: 37 /** @brief an enum to define the different states of progress 38 * 39 */ 40 enum class state 41 { 42 Update, 43 Verify, 44 Apply, 45 }; 46 47 /** @brief Construct an UpdateProgress object given to the total component 48 * size 49 * 50 * @param[in] totalSize the size in bytes of a component for a given device 51 * @param[in] eid the eid of the device this class tracks progress for 52 */ 53 UpdateProgress(uint32_t totalSize, mctp_eid_t eid); 54 ~UpdateProgress() = default; 55 UpdateProgress& operator=(UpdateProgress&&) = default; 56 UpdateProgress& operator=(const UpdateProgress&) = delete; 57 UpdateProgress(UpdateProgress&&) = default; 58 UpdateProgress(const UpdateProgress&) = delete; 59 60 /** @brief Called when switching between phases of firmware update 61 * 62 * @param[in] newState the state that we are entering. See 63 * UpdateProgress::state 64 * @return true on success, false on failure 65 */ 66 void updateState(state newState); 67 68 /** @brief called when servicing RequestFirmwareData commands 69 * 70 * @param[in] amountUpdate the length of firmware transmitted, in bytes 71 * @return true on success, false on failure 72 */ 73 void reportFwUpdate(uint32_t amountUpdated); 74 75 /** @brief get the progress as a percentage of this component 76 * 77 * @return the progress of this component as an int in [0-100] 78 */ 79 uint8_t getProgress() const; 80 81 /** @brief get the total size of the firmware component in bytes 82 * 83 * @return the total number of bytes for the component 84 */ 85 uint32_t getTotalSize() const; 86 87 private: 88 /** 89 * @brief progress of firmware update in percentage [0-100] 90 */ 91 uint8_t progress; 92 93 /** 94 * @brief the eid of the device this object tracks 95 */ 96 mctp_eid_t eid; 97 /** 98 * @brief the total size in bytes of this component 99 */ 100 uint32_t totalSize; 101 /** 102 * @brief the total number of bytes sent 103 */ 104 uint32_t totalUpdated; 105 /** 106 * @brief the current state of update for this component 107 */ 108 state currentState; 109 }; 110 111 /** @class DeviceUpdater 112 * 113 * DeviceUpdater orchestrates the firmware update of the firmware device and 114 * updates the UpdateManager about the status once it is complete. 115 */ 116 class DeviceUpdater 117 { 118 public: 119 DeviceUpdater() = delete; 120 DeviceUpdater(const DeviceUpdater&) = delete; 121 DeviceUpdater(DeviceUpdater&&) = default; 122 DeviceUpdater& operator=(const DeviceUpdater&) = delete; 123 DeviceUpdater& operator=(DeviceUpdater&&) = delete; 124 ~DeviceUpdater() = default; 125 126 /** @brief Constructor 127 * 128 * @param[in] eid - Endpoint ID of the firmware device 129 * @param[in] package - File stream for firmware update package 130 * @param[in] fwDeviceIDRecord - FirmwareDeviceIDRecord in the fw update 131 * package that matches this firmware device 132 * @param[in] compImageInfos - Component image information for all the 133 * components in the fw update package 134 * @param[in] compInfo - Component info for the components in this FD 135 * derived from GetFirmwareParameters response 136 * @param[in] maxTransferSize - Maximum size in bytes of the variable 137 * payload allowed to be requested by the FD 138 * @param[in] updateManager - To update the status of fw update of the 139 * device 140 */ 141 explicit DeviceUpdater(mctp_eid_t eid, std::istream& package, 142 const FirmwareDeviceIDRecord& fwDeviceIDRecord, 143 const ComponentImageInfos& compImageInfos, 144 const ComponentInfo& compInfo, 145 uint32_t maxTransferSize, 146 UpdateManager* updateManager); 147 148 /** @brief Get the progress of updating this device as percentage 149 * 150 * Goes through each component for this device and calculates 151 * the percentage we are through the update process 152 * 153 * @return The percentage as an int [0-100], 0 is no progress, 100 is done. 154 */ 155 uint8_t getProgress() const; 156 157 /** @brief Start the firmware update flow for the FD 158 * 159 * To start the update flow RequestUpdate command is sent to the FD. 160 * 161 */ 162 void startFwUpdateFlow(); 163 164 /** @brief Handler for RequestUpdate command response 165 * 166 * The response of the RequestUpdate is processed and if the response 167 * is success, send PassComponentTable request to FD. 168 * 169 * @param[in] eid - Remote MCTP endpoint 170 * @param[in] response - PLDM response message 171 * @param[in] respMsgLen - Response message length 172 */ 173 void requestUpdate(mctp_eid_t eid, const pldm_msg* response, 174 size_t respMsgLen); 175 176 /** @brief Handler for PassComponentTable command response 177 * 178 * The response of the PassComponentTable is processed. If the response 179 * indicates component can be updated, continue with either a) or b). 180 * 181 * a. Send PassComponentTable request for the next component if 182 * applicable 183 * b. UpdateComponent command to request updating a specific 184 * firmware component 185 * 186 * If the response indicates component may be updateable, continue 187 * based on the policy in DeviceUpdateOptionFlags. 188 * 189 * @param[in] eid - Remote MCTP endpoint 190 * @param[in] response - PLDM response message 191 * @param[in] respMsgLen - Response message length 192 */ 193 void passCompTable(mctp_eid_t eid, const pldm_msg* response, 194 size_t respMsgLen); 195 196 /** @brief Handler for UpdateComponent command response 197 * 198 * The response of the UpdateComponent is processed and will wait for 199 * FD to request the firmware data. 200 * 201 * @param[in] eid - Remote MCTP endpoint 202 * @param[in] response - PLDM response message 203 * @param[in] respMsgLen - Response message length 204 */ 205 void updateComponent(mctp_eid_t eid, const pldm_msg* response, 206 size_t respMsgLen); 207 208 /** @brief Handler for RequestFirmwareData request 209 * 210 * @param[in] request - Request message 211 * @param[in] payload_length - Request message payload length 212 * @return Response - PLDM Response message 213 */ 214 Response requestFwData(const pldm_msg* request, size_t payloadLength); 215 216 /** @brief Handler for TransferComplete request 217 * 218 * @param[in] request - Request message 219 * @param[in] payload_length - Request message payload length 220 * @return Response - PLDM Response message 221 */ 222 Response transferComplete(const pldm_msg* request, size_t payloadLength); 223 224 /** @brief Handler for VerifyComplete request 225 * 226 * @param[in] request - Request message 227 * @param[in] payload_length - Request message payload length 228 * @return Response - PLDM Response message 229 */ 230 Response verifyComplete(const pldm_msg* request, size_t payloadLength); 231 232 /** @brief Handler for ApplyComplete request 233 * 234 * @param[in] request - Request message 235 * @param[in] payload_length - Request message payload length 236 * @return Response - PLDM Response message 237 */ 238 Response applyComplete(const pldm_msg* request, size_t payloadLength); 239 240 /** @brief Handler for ActivateFirmware command response 241 * 242 * The response of the ActivateFirmware is processed and will update the 243 * UpdateManager with the completion of the firmware update. 244 * 245 * @param[in] eid - Remote MCTP endpoint 246 * @param[in] response - PLDM response message 247 * @param[in] respMsgLen - Response message length 248 */ 249 void activateFirmware(mctp_eid_t eid, const pldm_msg* response, 250 size_t respMsgLen); 251 /** 252 * @brief Handler for CancelUpdateComponent command response 253 * 254 * @param[in] eid - Remote MCTP endpoint 255 * @param[in] response - PLDM Response message 256 * @param[in] respMsgLen - Response message length 257 */ 258 void cancelUpdateComponent(mctp_eid_t eid, const pldm_msg* response, 259 size_t respMsgLen); 260 261 private: 262 /** @brief Send PassComponentTable command request 263 * 264 * @param[in] compOffset - component offset in compImageInfos 265 */ 266 void sendPassCompTableRequest(size_t offset); 267 268 /** @brief Send UpdateComponent command request 269 * 270 * @param[in] compOffset - component offset in compImageInfos 271 */ 272 void sendUpdateComponentRequest(size_t offset); 273 274 /** @brief Send ActivateFirmware command request */ 275 void sendActivateFirmwareRequest(); 276 277 /** 278 * @brief Send cancel update component request 279 */ 280 void sendCancelUpdateComponentRequest(); 281 282 /** 283 * @brief Create a timer to handle RequestFirmwareData timeout (UA_T2) 284 */ 285 void createRequestFwDataTimer(); 286 287 /** @brief Endpoint ID of the firmware device */ 288 mctp_eid_t eid; 289 290 /** @brief File stream for firmware update package */ 291 std::istream& package; 292 293 /** @brief FirmwareDeviceIDRecord in the fw update package that matches this 294 * firmware device 295 */ 296 const FirmwareDeviceIDRecord& fwDeviceIDRecord; 297 298 /** @brief Component image information for all the components in the fw 299 * update package 300 */ 301 const ComponentImageInfos& compImageInfos; 302 303 /** @brief Component info for the components in this FD derived from 304 * GetFirmwareParameters response 305 */ 306 const ComponentInfo& compInfo; 307 308 /** @brief Maximum size in bytes of the variable payload to be requested by 309 * the FD via RequestFirmwareData command 310 */ 311 uint32_t maxTransferSize; 312 313 /** @brief To update the status of fw update of the FD */ 314 UpdateManager* updateManager; 315 316 /** @brief Component index is used to track the current component being 317 * updated if multiple components are applicable for the FD. 318 * It is also used to keep track of the next component in 319 * PassComponentTable 320 */ 321 size_t componentIndex = 0; 322 323 /** @brief To send a PLDM request after the current command handling */ 324 std::unique_ptr<sdeventplus::source::Defer> pldmRequest; 325 326 /** 327 * @brief Map to hold component update status. True - success, False - 328 * cancelled 329 */ 330 ComponentUpdateStatusMap componentUpdateStatus; 331 332 /** 333 * @brief Timeout in seconds for the UA to cancel the component update if no 334 * command is received from the FD during component image transfer stage 335 * 336 */ 337 static constexpr int updateTimeoutSeconds = UPDATE_TIMEOUT_SECONDS; 338 339 /** 340 * @brief Timer to handle RequestFirmwareData timeout(UA_T2) 341 * 342 */ 343 std::unique_ptr<sdbusplus::Timer> reqFwDataTimer; 344 /** 345 * @brief a list of UpdateProgress objects, one for each firmware component 346 * applicable to this device 347 */ 348 std::vector<UpdateProgress> progress; 349 /** 350 * @brief Whether this device has gone through application. Needed because 351 * UpdateProgress handles each component but application happens at 352 * the device level 353 */ 354 bool activationComplete; 355 }; 356 357 } // namespace fw_update 358 359 } // namespace pldm 360