1 #include "pldm_fw_update_cmd.hpp"
2 
3 #include "common/utils.hpp"
4 #include "pldm_cmd_helper.hpp"
5 
6 #include <libpldm/firmware_update.h>
7 
8 namespace pldmtool
9 {
10 
11 namespace fw_update
12 {
13 
14 namespace
15 {
16 
17 using namespace pldmtool::helper;
18 
19 std::vector<std::unique_ptr<CommandInterface>> commands;
20 
21 } // namespace
22 
23 const std::map<uint8_t, std::string> fdStateMachine{
24     {PLDM_FD_STATE_IDLE, "IDLE"},
25     {PLDM_FD_STATE_LEARN_COMPONENTS, "LEARN COMPONENTS"},
26     {PLDM_FD_STATE_READY_XFER, "READY XFER"},
27     {PLDM_FD_STATE_DOWNLOAD, "DOWNLOAD"},
28     {PLDM_FD_STATE_VERIFY, "VERIFY"},
29     {PLDM_FD_STATE_APPLY, "APPLY"},
30     {PLDM_FD_STATE_ACTIVATE, "ACTIVATE"}};
31 
32 const std::map<uint8_t, const char*> fdAuxState{
33     {PLDM_FD_OPERATION_IN_PROGRESS, "Operation in progress"},
34     {PLDM_FD_OPERATION_SUCCESSFUL, "Operation successful"},
35     {PLDM_FD_OPERATION_FAILED, "Operation Failed"},
36     {PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER,
37      "Not applicable in current state"}};
38 
39 const std::map<uint8_t, const char*> fdAuxStateStatus{
40     {PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS,
41      "AuxState is In Progress or Success"},
42     {PLDM_FD_TIMEOUT, "Timeout occurred while performing action"},
43     {PLDM_FD_GENERIC_ERROR, "Generic Error has occured"}};
44 
45 const std::map<uint8_t, const char*> fdReasonCode{
46     {PLDM_FD_INITIALIZATION, "Initialization of firmware device has occurred"},
47     {PLDM_FD_ACTIVATE_FW, "ActivateFirmware command was received"},
48     {PLDM_FD_CANCEL_UPDATE, "CancelUpdate command was received"},
49     {PLDM_FD_TIMEOUT_LEARN_COMPONENT,
50      "Timeout occurred when in LEARN COMPONENT state"},
51     {PLDM_FD_TIMEOUT_READY_XFER, "Timeout occurred when in READY XFER state"},
52     {PLDM_FD_TIMEOUT_DOWNLOAD, "Timeout occurred when in DOWNLOAD state"},
53     {PLDM_FD_TIMEOUT_VERIFY, "Timeout occurred when in VERIFY state"},
54     {PLDM_FD_TIMEOUT_APPLY, "Timeout occurred when in APPLY state"}};
55 
56 class GetStatus : public CommandInterface
57 {
58   public:
59     ~GetStatus() = default;
60     GetStatus() = delete;
61     GetStatus(const GetStatus&) = delete;
62     GetStatus(GetStatus&&) = default;
63     GetStatus& operator=(const GetStatus&) = delete;
64     GetStatus& operator=(GetStatus&&) = default;
65 
66     using CommandInterface::CommandInterface;
67 
68     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
69     {
70         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
71                                         PLDM_GET_STATUS_REQ_BYTES);
72         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
73         auto rc = encode_get_status_req(instanceId, request,
74                                         PLDM_GET_STATUS_REQ_BYTES);
75         return {rc, requestMsg};
76     }
77 
78     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
79     {
80         uint8_t completionCode = 0;
81         uint8_t currentState = 0;
82         uint8_t previousState = 0;
83         uint8_t auxState = 0;
84         uint8_t auxStateStatus = 0;
85         uint8_t progressPercent = 0;
86         uint8_t reasonCode = 0;
87         bitfield32_t updateOptionFlagsEnabled{0};
88 
89         auto rc = decode_get_status_resp(
90             responsePtr, payloadLength, &completionCode, &currentState,
91             &previousState, &auxState, &auxStateStatus, &progressPercent,
92             &reasonCode, &updateOptionFlagsEnabled);
93         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
94         {
95             std::cerr << "Response Message Error: "
96                       << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
97             return;
98         }
99 
100         ordered_json data;
101         data["CurrentState"] = fdStateMachine.at(currentState);
102         data["PreviousState"] = fdStateMachine.at(previousState);
103         data["AuxState"] = fdAuxState.at(auxState);
104         if (auxStateStatus >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
105             auxStateStatus <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)
106         {
107             data["AuxStateStatus"] = auxStateStatus;
108         }
109         else
110         {
111             data["AuxStateStatus"] = fdAuxStateStatus.at(auxStateStatus);
112         }
113         data["ProgressPercent"] = progressPercent;
114         if (reasonCode >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN &&
115             reasonCode <= PLDM_FD_STATUS_VENDOR_DEFINED_MAX)
116         {
117             data["ReasonCode"] = reasonCode;
118         }
119         else
120         {
121             data["ReasonCode"] = fdReasonCode.at(reasonCode);
122         }
123         data["UpdateOptionFlagsEnabled"] = updateOptionFlagsEnabled.value;
124 
125         pldmtool::helper::DisplayInJson(data);
126     }
127 };
128 
129 const std::map<uint16_t, std::string> componentClassification{
130     {PLDM_COMP_UNKNOWN, "Unknown"},
131     {PLDM_COMP_OTHER, "Other"},
132     {PLDM_COMP_DRIVER, "Driver"},
133     {PLDM_COMP_CONFIGURATION_SOFTWARE, "Configuration Software"},
134     {PLDM_COMP_APPLICATION_SOFTWARE, "Application Software"},
135     {PLDM_COMP_INSTRUMENTATION, "Instrumentation"},
136     {PLDM_COMP_FIRMWARE_OR_BIOS, "Firmware/BIOS"},
137     {PLDM_COMP_DIAGNOSTIC_SOFTWARE, "Diagnostic Software"},
138     {PLDM_COMP_OPERATING_SYSTEM, "Operating System"},
139     {PLDM_COMP_MIDDLEWARE, "Middleware"},
140     {PLDM_COMP_FIRMWARE, "Firmware"},
141     {PLDM_COMP_BIOS_OR_FCODE, "BIOS/FCode"},
142     {PLDM_COMP_SUPPORT_OR_SERVICEPACK, "Support/Service Pack"},
143     {PLDM_COMP_SOFTWARE_BUNDLE, "Software Bundle"},
144     {PLDM_COMP_DOWNSTREAM_DEVICE, "Downstream Device"}};
145 
146 class GetFwParams : public CommandInterface
147 {
148   public:
149     ~GetFwParams() = default;
150     GetFwParams() = delete;
151     GetFwParams(const GetFwParams&) = delete;
152     GetFwParams(GetFwParams&&) = default;
153     GetFwParams& operator=(const GetFwParams&) = delete;
154     GetFwParams& operator=(GetFwParams&&) = default;
155 
156     using CommandInterface::CommandInterface;
157 
158     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
159     {
160         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
161                                         PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
162         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
163         auto rc = encode_get_firmware_parameters_req(
164             instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
165         return {rc, requestMsg};
166     }
167 
168     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
169     {
170         pldm_get_firmware_parameters_resp fwParams{};
171         variable_field activeCompImageSetVersion{};
172         variable_field pendingCompImageSetVersion{};
173         variable_field compParameterTable{};
174 
175         auto rc = decode_get_firmware_parameters_resp(
176             responsePtr, payloadLength, &fwParams, &activeCompImageSetVersion,
177             &pendingCompImageSetVersion, &compParameterTable);
178         if (rc != PLDM_SUCCESS || fwParams.completion_code != PLDM_SUCCESS)
179         {
180             std::cerr << "Response Message Error: "
181                       << "rc=" << rc << ",cc=" << (int)fwParams.completion_code
182                       << "\n";
183             return;
184         }
185 
186         ordered_json capabilitiesDuringUpdate;
187         if (fwParams.capabilities_during_update.bits.bit0)
188         {
189             capabilitiesDuringUpdate
190                 ["Component Update Failure Recovery Capability"] =
191                     "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer.";
192         }
193         else
194         {
195             capabilitiesDuringUpdate
196                 ["Component Update Failure Recovery Capability"] =
197                     "Device will revert to previous component image upon failure, timeout or cancellation of the transfer.";
198         }
199 
200         if (fwParams.capabilities_during_update.bits.bit1)
201         {
202             capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
203                 "Device will not be able to update component again unless it exits update mode and the UA sends a new Request Update command.";
204         }
205         else
206         {
207             capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
208                 " Device can have component updated again without exiting update mode and restarting transfer via RequestUpdate command.";
209         }
210 
211         if (fwParams.capabilities_during_update.bits.bit2)
212         {
213             capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
214                 "Firmware Device can support a partial update, whereby a package which contains a component image set that is a subset of all components currently residing on the FD, can be transferred.";
215         }
216         else
217         {
218             capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
219                 "Firmware Device cannot accept a partial update and all components present on the FD shall be updated.";
220         }
221 
222         if (fwParams.capabilities_during_update.bits.bit3)
223         {
224             capabilitiesDuringUpdate
225                 ["Firmware Device Host Functionality during Firmware Update"] =
226                     "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer";
227         }
228         else
229         {
230             capabilitiesDuringUpdate
231                 ["Firmware Device Host Functionality during Firmware Update"] =
232                     "Device will revert to previous component image upon failure, timeout or cancellation of the transfer";
233         }
234 
235         if (fwParams.capabilities_during_update.bits.bit4)
236         {
237             capabilitiesDuringUpdate["Firmware Device Update Mode Restrictions"] =
238                 "Firmware device unable to enter update mode if host OS environment is active.";
239         }
240         else
241         {
242             capabilitiesDuringUpdate
243                 ["Firmware Device Update Mode Restrictions"] =
244                     "No host OS environment restriction for update mode";
245         }
246 
247         ordered_json data;
248         data["CapabilitiesDuringUpdate"] = capabilitiesDuringUpdate;
249         data["ComponentCount"] = static_cast<uint16_t>(fwParams.comp_count);
250         data["ActiveComponentImageSetVersionString"] =
251             pldm::utils::toString(activeCompImageSetVersion);
252         data["PendingComponentImageSetVersionString"] =
253             pldm::utils::toString(pendingCompImageSetVersion);
254 
255         auto compParamPtr = compParameterTable.ptr;
256         auto compParamTableLen = compParameterTable.length;
257         pldm_component_parameter_entry compEntry{};
258         variable_field activeCompVerStr{};
259         variable_field pendingCompVerStr{};
260         ordered_json compDataEntries;
261 
262         while (fwParams.comp_count-- && (compParamTableLen > 0))
263         {
264             ordered_json compData;
265             auto rc = decode_get_firmware_parameters_resp_comp_entry(
266                 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
267                 &pendingCompVerStr);
268             if (rc)
269             {
270                 std::cerr
271                     << "Decoding component parameter table entry failed, RC="
272                     << rc << "\n";
273                 return;
274             }
275 
276             if (componentClassification.contains(compEntry.comp_classification))
277             {
278                 compData["ComponentClassification"] =
279                     componentClassification.at(compEntry.comp_classification);
280             }
281             else
282             {
283                 compData["ComponentClassification"] =
284                     static_cast<uint16_t>(compEntry.comp_classification);
285             }
286             compData["ComponentIdentifier"] =
287                 static_cast<uint16_t>(compEntry.comp_identifier);
288             compData["ComponentClassificationIndex"] =
289                 static_cast<uint8_t>(compEntry.comp_classification_index);
290             compData["ActiveComponentComparisonStamp"] =
291                 static_cast<uint32_t>(compEntry.active_comp_comparison_stamp);
292 
293             // ActiveComponentReleaseData
294             std::array<uint8_t, 8> noReleaseData{0x00, 0x00, 0x00, 0x00,
295                                                  0x00, 0x00, 0x00, 0x00};
296             if (std::equal(noReleaseData.begin(), noReleaseData.end(),
297                            compEntry.active_comp_release_date))
298             {
299                 compData["ActiveComponentReleaseDate"] = "";
300             }
301             else
302             {
303                 std::string activeComponentReleaseDate(
304                     reinterpret_cast<const char*>(
305                         compEntry.active_comp_release_date),
306                     sizeof(compEntry.active_comp_release_date));
307                 compData["ActiveComponentReleaseDate"] =
308                     activeComponentReleaseDate;
309             }
310 
311             compData["PendingComponentComparisonStamp"] =
312                 static_cast<uint32_t>(compEntry.pending_comp_comparison_stamp);
313 
314             // PendingComponentReleaseData
315             if (std::equal(noReleaseData.begin(), noReleaseData.end(),
316                            compEntry.pending_comp_release_date))
317             {
318                 compData["PendingComponentReleaseDate"] = "";
319             }
320             else
321             {
322                 std::string pendingComponentReleaseDate(
323                     reinterpret_cast<const char*>(
324                         compEntry.pending_comp_release_date),
325                     sizeof(compEntry.pending_comp_release_date));
326                 compData["PendingComponentReleaseDate"] =
327                     pendingComponentReleaseDate;
328             }
329 
330             // ComponentActivationMethods
331             ordered_json componentActivationMethods;
332             if (compEntry.comp_activation_methods.bits.bit0)
333             {
334                 componentActivationMethods.push_back("Automatic");
335             }
336             else if (compEntry.comp_activation_methods.bits.bit1)
337             {
338                 componentActivationMethods.push_back("Self-Contained");
339             }
340             else if (compEntry.comp_activation_methods.bits.bit2)
341             {
342                 componentActivationMethods.push_back("Medium-specific reset");
343             }
344             else if (compEntry.comp_activation_methods.bits.bit3)
345             {
346                 componentActivationMethods.push_back("System reboot");
347             }
348             else if (compEntry.comp_activation_methods.bits.bit4)
349             {
350                 componentActivationMethods.push_back("DC power cycel");
351             }
352             else if (compEntry.comp_activation_methods.bits.bit5)
353             {
354                 componentActivationMethods.push_back("AC power cycle");
355             }
356             compData["ComponentActivationMethods"] = componentActivationMethods;
357 
358             // CapabilitiesDuringUpdate
359             ordered_json compCapabilitiesDuringUpdate;
360             if (compEntry.capabilities_during_update.bits.bit0)
361             {
362                 compCapabilitiesDuringUpdate
363                     ["Firmware Device apply state functionality"] =
364                         "Firmware Device performs an auto-apply during transfer phase and apply step will be completed immediately.";
365             }
366             else
367             {
368                 compCapabilitiesDuringUpdate
369                     ["Firmware Device apply state functionality"] =
370                         " Firmware Device will execute an operation during the APPLY state which will include migrating the new component image to its final non-volatile storage destination.";
371             }
372             compData["CapabilitiesDuringUpdate"] = compCapabilitiesDuringUpdate;
373 
374             compData["ActiveComponentVersionString"] =
375                 pldm::utils::toString(activeCompVerStr);
376             compData["PendingComponentVersionString"] =
377                 pldm::utils::toString(pendingCompVerStr);
378 
379             compParamPtr += sizeof(pldm_component_parameter_entry) +
380                             activeCompVerStr.length + pendingCompVerStr.length;
381             compParamTableLen -= sizeof(pldm_component_parameter_entry) +
382                                  activeCompVerStr.length +
383                                  pendingCompVerStr.length;
384             compDataEntries.push_back(compData);
385         }
386         data["ComponentParameterEntries"] = compDataEntries;
387 
388         pldmtool::helper::DisplayInJson(data);
389     }
390 };
391 
392 void registerCommand(CLI::App& app)
393 {
394     auto fwUpdate =
395         app.add_subcommand("fw_update", "firmware update type commands");
396     fwUpdate->require_subcommand(1);
397 
398     auto getStatus = fwUpdate->add_subcommand("GetStatus", "Status of the FD");
399     commands.push_back(
400         std::make_unique<GetStatus>("fw_update", "GetStatus", getStatus));
401 
402     auto getFwParams = fwUpdate->add_subcommand(
403         "GetFwParams", "To get the component details of the FD");
404     commands.push_back(
405         std::make_unique<GetFwParams>("fw_update", "GetFwParams", getFwParams));
406 }
407 
408 } // namespace fw_update
409 
410 } // namespace pldmtool