xref: /openbmc/pldm/fw-update/device_updater.hpp (revision 3124782739408b77dbf7df07833336ee63dcc239)
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