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 #include <format>
9
10 namespace pldmtool
11 {
12
13 namespace fw_update
14 {
15
16 namespace
17 {
18
19 using namespace pldmtool::helper;
20 using namespace pldm::fw_update;
21
22 std::vector<std::unique_ptr<CommandInterface>> commands;
23
24 } // namespace
25
26 const std::map<uint8_t, std::string> fdStateMachine{
27 {PLDM_FD_STATE_IDLE, "IDLE"},
28 {PLDM_FD_STATE_LEARN_COMPONENTS, "LEARN COMPONENTS"},
29 {PLDM_FD_STATE_READY_XFER, "READY XFER"},
30 {PLDM_FD_STATE_DOWNLOAD, "DOWNLOAD"},
31 {PLDM_FD_STATE_VERIFY, "VERIFY"},
32 {PLDM_FD_STATE_APPLY, "APPLY"},
33 {PLDM_FD_STATE_ACTIVATE, "ACTIVATE"}};
34
35 const std::map<uint8_t, const char*> fdAuxState{
36 {PLDM_FD_OPERATION_IN_PROGRESS, "Operation in progress"},
37 {PLDM_FD_OPERATION_SUCCESSFUL, "Operation successful"},
38 {PLDM_FD_OPERATION_FAILED, "Operation Failed"},
39 {PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER,
40 "Not applicable in current state"}};
41
42 const std::map<uint8_t, const char*> fdAuxStateStatus{
43 {PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS,
44 "AuxState is In Progress or Success"},
45 {PLDM_FD_TIMEOUT, "Timeout occurred while performing action"},
46 {PLDM_FD_GENERIC_ERROR, "Generic Error has occurred"}};
47
48 const std::map<uint8_t, const char*> fdReasonCode{
49 {PLDM_FD_INITIALIZATION, "Initialization of firmware device has occurred"},
50 {PLDM_FD_ACTIVATE_FW, "ActivateFirmware command was received"},
51 {PLDM_FD_CANCEL_UPDATE, "CancelUpdate command was received"},
52 {PLDM_FD_TIMEOUT_LEARN_COMPONENT,
53 "Timeout occurred when in LEARN COMPONENT state"},
54 {PLDM_FD_TIMEOUT_READY_XFER, "Timeout occurred when in READY XFER state"},
55 {PLDM_FD_TIMEOUT_DOWNLOAD, "Timeout occurred when in DOWNLOAD state"},
56 {PLDM_FD_TIMEOUT_VERIFY, "Timeout occurred when in VERIFY state"},
57 {PLDM_FD_TIMEOUT_APPLY, "Timeout occurred when in APPLY state"}};
58
59 /**
60 * @brief descriptor type to name mapping
61 *
62 */
63 const std::map<DescriptorType, const char*> descriptorName{
64 {PLDM_FWUP_PCI_VENDOR_ID, "PCI Vendor ID"},
65 {PLDM_FWUP_IANA_ENTERPRISE_ID, "IANA Enterprise ID"},
66 {PLDM_FWUP_UUID, "UUID"},
67 {PLDM_FWUP_PNP_VENDOR_ID, "PnP Vendor ID"},
68 {PLDM_FWUP_ACPI_VENDOR_ID, "ACPI Vendor ID"},
69 {PLDM_FWUP_PCI_DEVICE_ID, "PCI Device ID"},
70 {PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID, "PCI Subsystem Vendor ID"},
71 {PLDM_FWUP_PCI_SUBSYSTEM_ID, "PCI Subsystem ID"},
72 {PLDM_FWUP_PCI_REVISION_ID, "PCI Revision ID"},
73 {PLDM_FWUP_PNP_PRODUCT_IDENTIFIER, "PnP Product Identifier"},
74 {PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER, "ACPI Product Identifier"},
75 {PLDM_FWUP_VENDOR_DEFINED, "Vendor Defined"}};
76
77 const std::map<std::string, transfer_resp_flag> transferRespFlag{
78 {"START", PLDM_START},
79 {"MIDDLE", PLDM_MIDDLE},
80 {"END", PLDM_END},
81 {"STARTANDEND", PLDM_START_AND_END},
82 };
83
84 const std::map<const char*, pldm_self_contained_activation_req>
85 pldmSelfContainedActivation{
86 {"False", PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS},
87 {"True", PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS},
88 };
89
90 /*
91 * Convert PLDM Firmware String Type to uint8_t
92 *
93 * @param[in] compImgVerStrType - the component version string
94 *
95 * @return - the component version string converted to a numeric value.
96 */
convertStringTypeToUInt8(std::string compImgVerStrType)97 uint8_t convertStringTypeToUInt8(std::string compImgVerStrType)
98 {
99 static const std::map<std::string, pldm_firmware_update_string_type>
100 pldmFirmwareUpdateStringType{
101 {"UNKNOWN", PLDM_STR_TYPE_UNKNOWN},
102 {"ASCII", PLDM_STR_TYPE_ASCII},
103 {"UTF_8", PLDM_STR_TYPE_UTF_8},
104 {"UTF_16", PLDM_STR_TYPE_UTF_16},
105 {"UTF_16LE", PLDM_STR_TYPE_UTF_16LE},
106 {"UTF_16BE", PLDM_STR_TYPE_UTF_16BE},
107 };
108
109 if (pldmFirmwareUpdateStringType.contains(compImgVerStrType))
110 {
111 return pldmFirmwareUpdateStringType.at(compImgVerStrType);
112 }
113 else
114 {
115 return static_cast<uint8_t>(std::stoi(compImgVerStrType));
116 }
117 }
118
119 class GetStatus : public CommandInterface
120 {
121 public:
122 ~GetStatus() = default;
123 GetStatus() = delete;
124 GetStatus(const GetStatus&) = delete;
125 GetStatus(GetStatus&&) = default;
126 GetStatus& operator=(const GetStatus&) = delete;
127 GetStatus& operator=(GetStatus&&) = delete;
128
129 using CommandInterface::CommandInterface;
130
createRequestMsg()131 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
132 {
133 std::vector<uint8_t> requestMsg(
134 sizeof(pldm_msg_hdr) + PLDM_GET_STATUS_REQ_BYTES);
135 auto request = new (requestMsg.data()) pldm_msg;
136 auto rc = encode_get_status_req(instanceId, request,
137 PLDM_GET_STATUS_REQ_BYTES);
138 return {rc, requestMsg};
139 }
140
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)141 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
142 {
143 uint8_t completionCode = 0;
144 uint8_t currentState = 0;
145 uint8_t previousState = 0;
146 uint8_t auxState = 0;
147 uint8_t auxStateStatus = 0;
148 uint8_t progressPercent = 0;
149 uint8_t reasonCode = 0;
150 bitfield32_t updateOptionFlagsEnabled{0};
151
152 auto rc = decode_get_status_resp(
153 responsePtr, payloadLength, &completionCode, ¤tState,
154 &previousState, &auxState, &auxStateStatus, &progressPercent,
155 &reasonCode, &updateOptionFlagsEnabled);
156 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
157 {
158 std::cerr << "Response Message Error: "
159 << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
160 return;
161 }
162
163 ordered_json data;
164 data["CurrentState"] = fdStateMachine.at(currentState);
165 data["PreviousState"] = fdStateMachine.at(previousState);
166 data["AuxState"] = fdAuxState.at(auxState);
167 if (auxStateStatus >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
168 auxStateStatus <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)
169 {
170 data["AuxStateStatus"] = auxStateStatus;
171 }
172 else
173 {
174 data["AuxStateStatus"] = fdAuxStateStatus.at(auxStateStatus);
175 }
176 data["ProgressPercent"] = progressPercent;
177 if (reasonCode >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN &&
178 reasonCode <= PLDM_FD_STATUS_VENDOR_DEFINED_MAX)
179 {
180 data["ReasonCode"] = reasonCode;
181 }
182 else
183 {
184 data["ReasonCode"] = fdReasonCode.at(reasonCode);
185 }
186 data["UpdateOptionFlagsEnabled"] = updateOptionFlagsEnabled.value;
187
188 pldmtool::helper::DisplayInJson(data);
189 }
190 };
191
192 const std::map<uint16_t, std::string> componentClassification{
193 {PLDM_COMP_UNKNOWN, "Unknown"},
194 {PLDM_COMP_OTHER, "Other"},
195 {PLDM_COMP_DRIVER, "Driver"},
196 {PLDM_COMP_CONFIGURATION_SOFTWARE, "Configuration Software"},
197 {PLDM_COMP_APPLICATION_SOFTWARE, "Application Software"},
198 {PLDM_COMP_INSTRUMENTATION, "Instrumentation"},
199 {PLDM_COMP_FIRMWARE_OR_BIOS, "Firmware/BIOS"},
200 {PLDM_COMP_DIAGNOSTIC_SOFTWARE, "Diagnostic Software"},
201 {PLDM_COMP_OPERATING_SYSTEM, "Operating System"},
202 {PLDM_COMP_MIDDLEWARE, "Middleware"},
203 {PLDM_COMP_FIRMWARE, "Firmware"},
204 {PLDM_COMP_BIOS_OR_FCODE, "BIOS/FCode"},
205 {PLDM_COMP_SUPPORT_OR_SERVICEPACK, "Support/Service Pack"},
206 {PLDM_COMP_SOFTWARE_BUNDLE, "Software Bundle"},
207 {PLDM_COMP_DOWNSTREAM_DEVICE, "Downstream Device"}};
208
209 class GetFwParams : public CommandInterface
210 {
211 public:
212 ~GetFwParams() = default;
213 GetFwParams() = delete;
214 GetFwParams(const GetFwParams&) = delete;
215 GetFwParams(GetFwParams&&) = default;
216 GetFwParams& operator=(const GetFwParams&) = delete;
217 GetFwParams& operator=(GetFwParams&&) = delete;
218
219 using CommandInterface::CommandInterface;
220
createRequestMsg()221 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
222 {
223 std::vector<uint8_t> requestMsg(
224 sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
225 auto request = new (requestMsg.data()) pldm_msg;
226 auto rc = encode_get_firmware_parameters_req(
227 instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
228 return {rc, requestMsg};
229 }
230
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)231 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
232 {
233 pldm_get_firmware_parameters_resp fwParams{};
234 variable_field activeCompImageSetVersion{};
235 variable_field pendingCompImageSetVersion{};
236 variable_field compParameterTable{};
237
238 auto rc = decode_get_firmware_parameters_resp(
239 responsePtr, payloadLength, &fwParams, &activeCompImageSetVersion,
240 &pendingCompImageSetVersion, &compParameterTable);
241 if (rc != PLDM_SUCCESS || fwParams.completion_code != PLDM_SUCCESS)
242 {
243 std::cerr << "Response Message Error: "
244 << "rc=" << rc << ",cc=" << (int)fwParams.completion_code
245 << "\n";
246 return;
247 }
248
249 ordered_json capabilitiesDuringUpdate;
250 if (fwParams.capabilities_during_update.bits.bit0)
251 {
252 capabilitiesDuringUpdate
253 ["Component Update Failure Recovery Capability"] =
254 "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer.";
255 }
256 else
257 {
258 capabilitiesDuringUpdate
259 ["Component Update Failure Recovery Capability"] =
260 "Device will revert to previous component image upon failure, timeout or cancellation of the transfer.";
261 }
262
263 if (fwParams.capabilities_during_update.bits.bit1)
264 {
265 capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
266 "Device will not be able to update component again unless it exits update mode and the UA sends a new Request Update command.";
267 }
268 else
269 {
270 capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
271 " Device can have component updated again without exiting update mode and restarting transfer via RequestUpdate command.";
272 }
273
274 if (fwParams.capabilities_during_update.bits.bit2)
275 {
276 capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
277 "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.";
278 }
279 else
280 {
281 capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
282 "Firmware Device cannot accept a partial update and all components present on the FD shall be updated.";
283 }
284
285 if (fwParams.capabilities_during_update.bits.bit3)
286 {
287 capabilitiesDuringUpdate
288 ["Firmware Device Host Functionality during Firmware Update"] =
289 "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer";
290 }
291 else
292 {
293 capabilitiesDuringUpdate
294 ["Firmware Device Host Functionality during Firmware Update"] =
295 "Device will revert to previous component image upon failure, timeout or cancellation of the transfer";
296 }
297
298 if (fwParams.capabilities_during_update.bits.bit4)
299 {
300 capabilitiesDuringUpdate["Firmware Device Update Mode Restrictions"] =
301 "Firmware device unable to enter update mode if host OS environment is active.";
302 }
303 else
304 {
305 capabilitiesDuringUpdate
306 ["Firmware Device Update Mode Restrictions"] =
307 "No host OS environment restriction for update mode";
308 }
309
310 ordered_json data;
311 data["CapabilitiesDuringUpdate"] = capabilitiesDuringUpdate;
312 data["ComponentCount"] = static_cast<uint16_t>(fwParams.comp_count);
313 data["ActiveComponentImageSetVersionString"] =
314 pldm::utils::toString(activeCompImageSetVersion);
315 data["PendingComponentImageSetVersionString"] =
316 pldm::utils::toString(pendingCompImageSetVersion);
317
318 auto compParamPtr = compParameterTable.ptr;
319 auto compParamTableLen = compParameterTable.length;
320 pldm_component_parameter_entry compEntry{};
321 variable_field activeCompVerStr{};
322 variable_field pendingCompVerStr{};
323 ordered_json compDataEntries;
324
325 while (fwParams.comp_count-- && (compParamTableLen > 0))
326 {
327 ordered_json compData;
328 auto rc = decode_get_firmware_parameters_resp_comp_entry(
329 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
330 &pendingCompVerStr);
331 if (rc)
332 {
333 std::cerr
334 << "Decoding component parameter table entry failed, RC="
335 << rc << "\n";
336 return;
337 }
338
339 if (componentClassification.contains(compEntry.comp_classification))
340 {
341 compData["ComponentClassification"] =
342 componentClassification.at(compEntry.comp_classification);
343 }
344 else
345 {
346 compData["ComponentClassification"] =
347 static_cast<uint16_t>(compEntry.comp_classification);
348 }
349 compData["ComponentIdentifier"] =
350 static_cast<uint16_t>(compEntry.comp_identifier);
351 compData["ComponentClassificationIndex"] =
352 static_cast<uint8_t>(compEntry.comp_classification_index);
353 compData["ActiveComponentComparisonStamp"] =
354 static_cast<uint32_t>(compEntry.active_comp_comparison_stamp);
355
356 // ActiveComponentReleaseData
357 std::array<uint8_t, 8> noReleaseData{0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00};
359 if (std::equal(noReleaseData.begin(), noReleaseData.end(),
360 compEntry.active_comp_release_date))
361 {
362 compData["ActiveComponentReleaseDate"] = "";
363 }
364 else
365 {
366 std::string activeComponentReleaseDate(
367 reinterpret_cast<const char*>(
368 compEntry.active_comp_release_date),
369 sizeof(compEntry.active_comp_release_date));
370 compData["ActiveComponentReleaseDate"] =
371 activeComponentReleaseDate;
372 }
373
374 compData["PendingComponentComparisonStamp"] =
375 static_cast<uint32_t>(compEntry.pending_comp_comparison_stamp);
376
377 // PendingComponentReleaseData
378 if (std::equal(noReleaseData.begin(), noReleaseData.end(),
379 compEntry.pending_comp_release_date))
380 {
381 compData["PendingComponentReleaseDate"] = "";
382 }
383 else
384 {
385 std::string pendingComponentReleaseDate(
386 reinterpret_cast<const char*>(
387 compEntry.pending_comp_release_date),
388 sizeof(compEntry.pending_comp_release_date));
389 compData["PendingComponentReleaseDate"] =
390 pendingComponentReleaseDate;
391 }
392
393 // ComponentActivationMethods
394 ordered_json componentActivationMethods;
395 if (compEntry.comp_activation_methods.bits.bit0)
396 {
397 componentActivationMethods.push_back("Automatic");
398 }
399 else if (compEntry.comp_activation_methods.bits.bit1)
400 {
401 componentActivationMethods.push_back("Self-Contained");
402 }
403 else if (compEntry.comp_activation_methods.bits.bit2)
404 {
405 componentActivationMethods.push_back("Medium-specific reset");
406 }
407 else if (compEntry.comp_activation_methods.bits.bit3)
408 {
409 componentActivationMethods.push_back("System reboot");
410 }
411 else if (compEntry.comp_activation_methods.bits.bit4)
412 {
413 componentActivationMethods.push_back("DC power cycel");
414 }
415 else if (compEntry.comp_activation_methods.bits.bit5)
416 {
417 componentActivationMethods.push_back("AC power cycle");
418 }
419 compData["ComponentActivationMethods"] = componentActivationMethods;
420
421 // CapabilitiesDuringUpdate
422 ordered_json compCapabilitiesDuringUpdate;
423 if (compEntry.capabilities_during_update.bits.bit0)
424 {
425 compCapabilitiesDuringUpdate
426 ["Firmware Device apply state functionality"] =
427 "Firmware Device performs an auto-apply during transfer phase and apply step will be completed immediately.";
428 }
429 else
430 {
431 compCapabilitiesDuringUpdate
432 ["Firmware Device apply state functionality"] =
433 " 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.";
434 }
435 compData["CapabilitiesDuringUpdate"] = compCapabilitiesDuringUpdate;
436
437 compData["ActiveComponentVersionString"] =
438 pldm::utils::toString(activeCompVerStr);
439 compData["PendingComponentVersionString"] =
440 pldm::utils::toString(pendingCompVerStr);
441
442 compParamPtr += sizeof(pldm_component_parameter_entry) +
443 activeCompVerStr.length + pendingCompVerStr.length;
444 compParamTableLen -=
445 sizeof(pldm_component_parameter_entry) +
446 activeCompVerStr.length + pendingCompVerStr.length;
447 compDataEntries.push_back(compData);
448 }
449 data["ComponentParameterEntries"] = compDataEntries;
450
451 pldmtool::helper::DisplayInJson(data);
452 }
453 };
454
455 class QueryDeviceIdentifiers : public CommandInterface
456 {
457 public:
458 ~QueryDeviceIdentifiers() = default;
459 QueryDeviceIdentifiers() = delete;
460 QueryDeviceIdentifiers(const QueryDeviceIdentifiers&) = delete;
461 QueryDeviceIdentifiers(QueryDeviceIdentifiers&&) = default;
462 QueryDeviceIdentifiers& operator=(const QueryDeviceIdentifiers&) = delete;
463 QueryDeviceIdentifiers& operator=(QueryDeviceIdentifiers&&) = delete;
464
465 /**
466 * @brief Implementation of createRequestMsg for QueryDeviceIdentifiers
467 *
468 * @return std::pair<int, std::vector<uint8_t>>
469 */
470 std::pair<int, std::vector<uint8_t>> createRequestMsg() override;
471
472 /**
473 * @brief Implementation of parseResponseMsg for QueryDeviceIdentifiers
474 *
475 * @param[in] responsePtr
476 * @param[in] payloadLength
477 */
478 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override;
479 using CommandInterface::CommandInterface;
480
481 private:
482 /**
483 * @brief Method to update QueryDeviceIdentifiers json response in a user
484 * friendly format
485 *
486 * @param[in] descriptors - descriptor json response
487 * @param[in] descriptorType - descriptor type
488 * @param[in] descriptorVal - descriptor value
489 */
490 void updateDescriptor(
491 ordered_json& descriptors, const DescriptorType& descriptorType,
492 const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
493 descriptorVal);
494 };
495
updateDescriptor(ordered_json & descriptors,const DescriptorType & descriptorType,const std::variant<DescriptorData,VendorDefinedDescriptorInfo> & descriptorVal)496 void QueryDeviceIdentifiers::updateDescriptor(
497 ordered_json& descriptors, const DescriptorType& descriptorType,
498 const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
499 descriptorVal)
500 {
501 std::ostringstream descDataStream;
502 DescriptorData descData;
503 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
504 {
505 descData = std::get<DescriptorData>(descriptorVal);
506 }
507 else
508 {
509 descData = std::get<VendorDefinedDescriptorData>(
510 std::get<VendorDefinedDescriptorInfo>(descriptorVal));
511 }
512 for (int byte : descData)
513 {
514 descDataStream << std::setfill('0') << std::setw(2) << std::hex << byte;
515 }
516
517 if (descriptorName.contains(descriptorType))
518 {
519 // Update the existing json response if entry is already present
520 for (auto& descriptor : descriptors)
521 {
522 if (descriptor["Type"] == descriptorName.at(descriptorType))
523 {
524 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
525 {
526 descriptor["Value"].emplace_back(descDataStream.str());
527 }
528 else
529 {
530 ordered_json vendorDefinedVal;
531 vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
532 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
533 descDataStream.str();
534 descriptor["Value"].emplace_back(vendorDefinedVal);
535 }
536 return;
537 }
538 }
539 // Entry is not present, add type and value to json response
540 ordered_json descriptor = ordered_json::object(
541 {{"Type", descriptorName.at(descriptorType)},
542 {"Value", ordered_json::array()}});
543 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
544 {
545 descriptor["Value"].emplace_back(descDataStream.str());
546 }
547 else
548 {
549 ordered_json vendorDefinedVal;
550 vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
551 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
552 descDataStream.str();
553 descriptor["Value"].emplace_back(vendorDefinedVal);
554 }
555 descriptors.emplace_back(descriptor);
556 }
557 else
558 {
559 std::cerr << "Unknown descriptor type, type=" << descriptorType << "\n";
560 }
561 }
createRequestMsg()562 std::pair<int, std::vector<uint8_t>> QueryDeviceIdentifiers::createRequestMsg()
563 {
564 std::vector<uint8_t> requestMsg(
565 sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
566 auto request = new (requestMsg.data()) pldm_msg;
567 auto rc = encode_query_device_identifiers_req(
568 instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
569 return {rc, requestMsg};
570 }
571
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)572 void QueryDeviceIdentifiers::parseResponseMsg(pldm_msg* responsePtr,
573 size_t payloadLength)
574 {
575 uint8_t completionCode = PLDM_SUCCESS;
576 uint32_t deviceIdentifiersLen = 0;
577 uint8_t descriptorCount = 0;
578 uint8_t* descriptorPtr = nullptr;
579 uint8_t eid = getMCTPEID();
580 auto rc = decode_query_device_identifiers_resp(
581 responsePtr, payloadLength, &completionCode, &deviceIdentifiersLen,
582 &descriptorCount, &descriptorPtr);
583 if (rc)
584 {
585 std::cerr << "Decoding QueryDeviceIdentifiers response failed,EID="
586 << unsigned(eid) << ", RC=" << rc << "\n";
587 return;
588 }
589 if (completionCode)
590 {
591 std::cerr << "QueryDeviceIdentifiers response failed with error "
592 "completion code, EID="
593 << unsigned(eid) << ", CC=" << unsigned(completionCode)
594 << "\n";
595 return;
596 }
597 ordered_json data;
598 data["EID"] = eid;
599 ordered_json descriptors;
600 while (descriptorCount-- && (deviceIdentifiersLen > 0))
601 {
602 DescriptorType descriptorType = 0;
603 variable_field descriptorData{};
604
605 rc = decode_descriptor_type_length_value(
606 descriptorPtr, deviceIdentifiersLen, &descriptorType,
607 &descriptorData);
608 if (rc)
609 {
610 std::cerr << "Decoding descriptor type, length and value failed,"
611 << "EID=" << unsigned(eid) << ",RC=" << rc << "\n ";
612 return;
613 }
614
615 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
616 {
617 std::vector<uint8_t> descData(
618 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
619 updateDescriptor(descriptors, descriptorType, descData);
620 }
621 else
622 {
623 uint8_t descriptorTitleStrType = 0;
624 variable_field descriptorTitleStr{};
625 variable_field vendorDefinedDescriptorData{};
626
627 rc = decode_vendor_defined_descriptor_value(
628 descriptorData.ptr, descriptorData.length,
629 &descriptorTitleStrType, &descriptorTitleStr,
630 &vendorDefinedDescriptorData);
631 if (rc)
632 {
633 std::cerr << "Decoding Vendor-defined descriptor value"
634 << "failed EID=" << unsigned(eid) << ", RC=" << rc
635 << "\n ";
636 return;
637 }
638
639 auto vendorDescTitle = pldm::utils::toString(descriptorTitleStr);
640 std::vector<uint8_t> vendorDescData(
641 vendorDefinedDescriptorData.ptr,
642 vendorDefinedDescriptorData.ptr +
643 vendorDefinedDescriptorData.length);
644 updateDescriptor(descriptors, descriptorType,
645 std::make_tuple(vendorDescTitle, vendorDescData));
646 }
647 auto nextDescriptorOffset =
648 sizeof(pldm_descriptor_tlv().descriptor_type) +
649 sizeof(pldm_descriptor_tlv().descriptor_length) +
650 descriptorData.length;
651 descriptorPtr += nextDescriptorOffset;
652 deviceIdentifiersLen -= nextDescriptorOffset;
653 }
654 data["Descriptors"] = descriptors;
655 pldmtool::helper::DisplayInJson(data);
656 }
657
658 class RequestUpdate : public CommandInterface
659 {
660 public:
661 ~RequestUpdate() = default;
662 RequestUpdate() = delete;
663 RequestUpdate(const RequestUpdate&) = delete;
664 RequestUpdate(RequestUpdate&&) = delete;
665 RequestUpdate& operator=(const RequestUpdate&) = delete;
666 RequestUpdate& operator=(RequestUpdate&&) = delete;
667
RequestUpdate(const char * type,const char * name,CLI::App * app)668 explicit RequestUpdate(const char* type, const char* name, CLI::App* app) :
669 CommandInterface(type, name, app)
670 {
671 app->add_option(
672 "--max_transfer_size", maxTransferSize,
673 "Specifies the maximum size, in bytes, of the variable payload allowed to\n"
674 "be requested by the FD via the RequestFirmwareData command that is contained\n"
675 "within a PLDM message. This value shall be equal to or greater than firmware update\n"
676 "baseline transfer size.")
677 ->required();
678
679 app->add_option(
680 "--num_comps", numComps,
681 "Specifies the number of components that will be passed to the FD during the update.\n"
682 "The FD can use this value to compare against the number of PassComponentTable\n"
683 "commands received.")
684 ->required();
685
686 app->add_option(
687 "--max_transfer_reqs", maxTransferReqs,
688 "Specifies the number of outstanding RequestFirmwareData commands that can be\n"
689 "sent by the FD. The minimum required value is '1' which the UA shall support.\n"
690 "It is optional for the UA to support a value higher than '1' for this field.")
691 ->required();
692
693 app->add_option(
694 "--package_data_length", packageDataLength,
695 "This field shall be set to the value contained within\n"
696 "the FirmwareDevicePackageDataLength field that was provided in\n"
697 "the firmware package header. If no firmware package data was\n"
698 "provided in the firmware update package then this length field\n"
699 "shall be set to 0x0000.")
700 ->required();
701
702 app->add_option(
703 "--comp_img_ver_str_type", compImgVerStrType,
704 "The type of string used in the ComponentImageSetVersionString\n"
705 "field. Possible values\n"
706 "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
707 "OR {0,1,2,3,4,5}")
708 ->required()
709 ->check([](const std::string& value) -> std::string {
710 static const std::set<std::string> validStrings{
711 "UNKNOWN", "ASCII", "UTF_8",
712 "UTF_16", "UTF_16LE", "UTF_16BE"};
713
714 if (validStrings.contains(value))
715 {
716 return "";
717 }
718
719 try
720 {
721 int intValue = std::stoi(value);
722 if (intValue >= 0 && intValue <= 255)
723 {
724 return "";
725 }
726 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
727 }
728 catch (const std::exception&)
729 {
730 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
731 }
732 });
733
734 app->add_option(
735 "--comp_img_ver_str_len", compImgVerStrLen,
736 "The length, in bytes, of the ComponentImageSetVersionString.")
737 ->required();
738
739 app->add_option(
740 "--comp_img_set_ver_str", compImgSetVerStr,
741 "Component Image Set version information, up to 255 bytes.")
742 ->required();
743 }
744
createRequestMsg()745 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
746 {
747 variable_field compImgSetVerStrInfo{};
748 compImgSetVerStrInfo.ptr =
749 reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());
750 compImgSetVerStrInfo.length =
751 static_cast<uint8_t>(compImgSetVerStr.size());
752
753 std::vector<uint8_t> requestMsg(
754 sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) +
755 compImgSetVerStrInfo.length);
756
757 auto request = new (requestMsg.data()) pldm_msg;
758
759 auto rc = encode_request_update_req(
760 instanceId, maxTransferSize, numComps, maxTransferReqs,
761 packageDataLength, convertStringTypeToUInt8(compImgVerStrType),
762 compImgVerStrLen, &compImgSetVerStrInfo, request,
763 sizeof(struct pldm_request_update_req) +
764 compImgSetVerStrInfo.length);
765
766 return {rc, requestMsg};
767 }
768
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)769 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
770 {
771 uint8_t cc = 0;
772 uint16_t fdMetaDataLen = 0;
773 uint8_t fdWillSendPkgData = 0;
774
775 auto rc =
776 decode_request_update_resp(responsePtr, payloadLength, &cc,
777 &fdMetaDataLen, &fdWillSendPkgData);
778 if (rc)
779 {
780 std::cerr << "Response Message Error: "
781 << "rc=" << rc << ",cc=" << (int)cc << "\n";
782 return;
783 }
784
785 ordered_json data;
786 fillCompletionCode(cc, data, PLDM_FWUP);
787
788 if (cc == PLDM_SUCCESS)
789 {
790 data["FirmwareDeviceMetaDataLength"] = fdMetaDataLen;
791 data["FDWillSendGetPackageDataCommand"] =
792 std::format("0x{:02X}", fdWillSendPkgData);
793 }
794 pldmtool::helper::DisplayInJson(data);
795 }
796
797 private:
798 uint32_t maxTransferSize;
799 uint16_t numComps;
800 uint8_t maxTransferReqs;
801 uint16_t packageDataLength;
802 std::string compImgVerStrType;
803 uint8_t compImgVerStrLen;
804 std::string compImgSetVerStr;
805 };
806
807 class PassComponentTable : public CommandInterface
808 {
809 public:
810 ~PassComponentTable() = default;
811 PassComponentTable() = delete;
812 PassComponentTable(const PassComponentTable&) = delete;
813 PassComponentTable(PassComponentTable&&) = delete;
814 PassComponentTable& operator=(const PassComponentTable&) = delete;
815 PassComponentTable& operator=(PassComponentTable&&) = delete;
816
PassComponentTable(const char * type,const char * name,CLI::App * app)817 explicit PassComponentTable(const char* type, const char* name,
818 CLI::App* app) :
819 CommandInterface(type, name, app)
820 {
821 app->add_option(
822 "--transfer_flag", transferFlag,
823 "The transfer flag that indicates what part of the Component Table\n"
824 "this request represents.\nPossible values\n"
825 "{Start = 0x1, Middle = 0x2, End = 0x4, StartAndEnd = 0x5}")
826 ->required()
827 ->transform(
828 CLI::CheckedTransformer(transferRespFlag, CLI::ignore_case));
829
830 app->add_option(
831 "--comp_classification", compClassification,
832 "Vendor specific component classification information.\n"
833 "Special values: 0x0000, 0xFFFF = reserved")
834 ->required();
835
836 app->add_option("--comp_identifier", compIdentifier,
837 "FD vendor selected unique value "
838 "to distinguish between component images")
839 ->required();
840
841 app->add_option("--comp_classification_idx", compClassificationIdx,
842 "The component classification index which was obtained "
843 "from the GetFirmwareParameters command to indicate \n"
844 "which firmware component the information contained "
845 "within this command is applicable for")
846 ->required();
847
848 app->add_option(
849 "--comp_compare_stamp", compCompareStamp,
850 "FD vendor selected value to use as a comparison value in determining if a firmware\n"
851 "component is down-level or up-level. For the same component identifier,\n"
852 "the greater of two component comparison stamps is considered up-level compared\n"
853 "to the other when performing an unsigned integer comparison")
854 ->required();
855
856 app->add_option(
857 "--comp_ver_str_type", compVerStrType,
858 "The type of strings used in the ComponentVersionString\n"
859 "Possible values\n"
860 "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
861 "OR {0,1,2,3,4,5}")
862 ->required()
863 ->check([](const std::string& value) -> std::string {
864 static const std::set<std::string> validStrings{
865 "UNKNOWN", "ASCII", "UTF_8",
866 "UTF_16", "UTF_16LE", "UTF_16BE"};
867
868 if (validStrings.contains(value))
869 {
870 return "";
871 }
872
873 try
874 {
875 int intValue = std::stoi(value);
876 if (intValue >= 0 && intValue <= 255)
877 {
878 return "";
879 }
880 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
881 }
882 catch (const std::exception&)
883 {
884 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
885 }
886 });
887
888 app->add_option("--comp_ver_str_len", compVerStrLen,
889 "The length, in bytes, of the ComponentVersionString")
890 ->required();
891
892 app->add_option(
893 "--comp_ver_str", compVerStr,
894 "Firmware component version information up to 255 bytes. \n"
895 "Contains a variable type string describing the component version")
896 ->required();
897 }
898
createRequestMsg()899 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
900 {
901 variable_field compVerStrInfo{};
902 std::vector<uint8_t> compVerStrData(compVerStr.begin(),
903 compVerStr.end());
904 compVerStrInfo.ptr = compVerStrData.data();
905 compVerStrInfo.length = static_cast<uint8_t>(compVerStrData.size());
906
907 std::vector<uint8_t> requestMsg(
908 sizeof(pldm_msg_hdr) +
909 sizeof(struct pldm_pass_component_table_req) +
910 compVerStrInfo.length);
911
912 auto request = new (requestMsg.data()) pldm_msg;
913
914 auto rc = encode_pass_component_table_req(
915 instanceId, transferFlag, compClassification, compIdentifier,
916 compClassificationIdx, compCompareStamp,
917 convertStringTypeToUInt8(compVerStrType), compVerStrInfo.length,
918 &compVerStrInfo, request,
919 sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
920
921 return {rc, requestMsg};
922 }
923
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)924 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
925 {
926 uint8_t cc = 0;
927 uint8_t compResponse = 0;
928 uint8_t compResponseCode = 0;
929
930 auto rc = decode_pass_component_table_resp(
931 responsePtr, payloadLength, &cc, &compResponse, &compResponseCode);
932
933 if (rc != PLDM_SUCCESS)
934 {
935 std::cerr << "Response Message Error: "
936 << "rc=" << rc << ",cc=" << (int)cc << "\n";
937 return;
938 }
939
940 ordered_json data;
941 fillCompletionCode(cc, data, PLDM_FWUP);
942
943 if (cc == PLDM_SUCCESS)
944 {
945 data["ComponentResponse"] =
946 compResponse ? "Component may be updateable"
947 : "Component can be updated";
948
949 data["ComponentResponseCode"] =
950 std::format("0x{:02X}", compResponseCode);
951 }
952
953 pldmtool::helper::DisplayInJson(data);
954 }
955
956 private:
957 uint8_t transferFlag;
958 uint16_t compClassification;
959 uint16_t compIdentifier;
960 uint8_t compClassificationIdx;
961 uint32_t compCompareStamp;
962 std::string compVerStrType;
963 uint8_t compVerStrLen;
964 std::string compVerStr;
965 };
966
967 class UpdateComponent : public CommandInterface
968 {
969 public:
970 ~UpdateComponent() = default;
971 UpdateComponent() = delete;
972 UpdateComponent(const UpdateComponent&) = delete;
973 UpdateComponent(UpdateComponent&&) = delete;
974 UpdateComponent& operator=(const UpdateComponent&) = delete;
975 UpdateComponent& operator=(UpdateComponent&&) = delete;
976
UpdateComponent(const char * type,const char * name,CLI::App * app)977 explicit UpdateComponent(const char* type, const char* name,
978 CLI::App* app) : CommandInterface(type, name, app)
979 {
980 app->add_option(
981 "--component_classification", componentClassification,
982 "Classification value provided by the firmware package header information for\n"
983 "the component to be transferred.\n"
984 "Special values: 0x0000, 0xFFFF = reserved")
985 ->required();
986
987 app->add_option(
988 "--component_identifier", componentIdentifier,
989 "FD vendor selected unique value to distinguish between component images")
990 ->required();
991
992 app->add_option(
993 "--component_classification_index", componentClassificationIndex,
994 "The component classification index which was obtained from the GetFirmwareParameters\n"
995 "command to indicate which firmware component the information contained within this\n"
996 "command is applicable for")
997 ->required();
998
999 app->add_option(
1000 "--component_comparison_stamp", componentComparisonStamp,
1001 "FD vendor selected value to use as a comparison value in determining if a firmware\n"
1002 "component is down-level or up-level. For the same component identifier, the greater\n"
1003 "of two component comparison stamps is considered up-level compared to the other\n"
1004 "when performing an unsigned integer comparison")
1005 ->required();
1006
1007 app->add_option("--component_image_size", componentImageSize,
1008 "Size in bytes of the component image")
1009 ->required();
1010
1011 app->add_option(
1012 "--update_option_flags", strUpdateOptionFlags,
1013 "32-bit field, where each non-reserved bit represents an update option that can be\n"
1014 "requested by the UA to be enabled for the transfer of this component image.\n"
1015 "[2] Security Revision Number Delayed Update\n"
1016 "[1] Component Opaque Data\n"
1017 "[0] Request Force Update of component")
1018 ->required();
1019
1020 app->add_option(
1021 "--component_version_string_type", componentVersionStringType,
1022 "The type of strings used in the ComponentVersionString\n"
1023 "Possible values\n"
1024 "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
1025 "OR {0,1,2,3,4,5}")
1026 ->required()
1027 ->check([](const std::string& value) -> std::string {
1028 static const std::set<std::string> validStrings{
1029 "UNKNOWN", "ASCII", "UTF_8",
1030 "UTF_16", "UTF_16LE", "UTF_16BE"};
1031
1032 if (validStrings.contains(value))
1033 {
1034 return "";
1035 }
1036
1037 try
1038 {
1039 int intValue = std::stoi(value);
1040 if (intValue >= 0 && intValue <= 255)
1041 {
1042 return "";
1043 }
1044 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
1045 }
1046 catch (const std::exception&)
1047 {
1048 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
1049 }
1050 });
1051
1052 app->add_option("--component_version_string_length",
1053 componentVersionStringLength,
1054 "The length, in bytes, of the ComponentVersionString")
1055 ->required();
1056
1057 app->add_option(
1058 "--component_version_string", componentVersionString,
1059 "Firmware component version information up to 255 bytes.\n"
1060 "Contains a variable type string describing the component version")
1061 ->required();
1062 }
1063
createRequestMsg()1064 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1065 {
1066 variable_field componentVersionStringInfo{};
1067
1068 componentVersionStringInfo.ptr =
1069 reinterpret_cast<const uint8_t*>(componentVersionString.data());
1070 componentVersionStringInfo.length =
1071 static_cast<uint8_t>(componentVersionString.size());
1072
1073 std::vector<uint8_t> requestMsg(
1074 sizeof(pldm_msg_hdr) + sizeof(struct pldm_update_component_req) +
1075 componentVersionStringInfo.length);
1076
1077 auto request = new (requestMsg.data()) pldm_msg;
1078
1079 bitfield32_t updateOptionFlags;
1080 std::stringstream ss(strUpdateOptionFlags);
1081 ss >> std::hex >> updateOptionFlags.value;
1082 if (ss.fail())
1083 {
1084 std::cerr << "Failed to parse update option flags: "
1085 << strUpdateOptionFlags << "\n";
1086 return {PLDM_ERROR_INVALID_DATA, std::vector<uint8_t>()};
1087 }
1088
1089 auto rc = encode_update_component_req(
1090 instanceId, componentClassification, componentIdentifier,
1091 componentClassificationIndex, componentComparisonStamp,
1092 componentImageSize, updateOptionFlags,
1093 convertStringTypeToUInt8(componentVersionStringType),
1094 componentVersionStringLength, &componentVersionStringInfo, request,
1095 sizeof(pldm_update_component_req) +
1096 componentVersionStringInfo.length);
1097
1098 return {rc, requestMsg};
1099 }
1100
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1101 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1102 {
1103 uint8_t cc = 0;
1104 uint8_t componentCompatibilityResp = 0;
1105 uint8_t componentCompatibilityRespCode = 0;
1106 bitfield32_t updateOptionFlagsEnabled{};
1107 uint16_t timeBeforeReqFWData = 0;
1108
1109 auto rc = decode_update_component_resp(
1110 responsePtr, payloadLength, &cc, &componentCompatibilityResp,
1111 &componentCompatibilityRespCode, &updateOptionFlagsEnabled,
1112 &timeBeforeReqFWData);
1113
1114 if (rc != PLDM_SUCCESS)
1115 {
1116 std::cerr << "Parsing UpdateComponent response failed: "
1117 << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1118 return;
1119 }
1120
1121 ordered_json data;
1122 fillCompletionCode(cc, data, PLDM_FWUP);
1123
1124 if (cc == PLDM_SUCCESS)
1125 {
1126 // Possible values:
1127 // 0 – Component can be updated,
1128 // 1 – Component will not be updated
1129 data["ComponentCompatibilityResponse"] =
1130 componentCompatibilityResp ? "Component will not be updated"
1131 : "Component can be updated";
1132
1133 data["ComponentCompatibilityResponseCode"] =
1134 std::format("0x{:02X}", componentCompatibilityRespCode);
1135 data["UpdateOptionFlagsEnabled"] =
1136 std::to_string(updateOptionFlagsEnabled.value);
1137 data["EstimatedTimeBeforeSendingRequestFirmwareData"] =
1138 std::to_string(timeBeforeReqFWData) + "s";
1139 }
1140
1141 pldmtool::helper::DisplayInJson(data);
1142 }
1143
1144 private:
1145 uint16_t componentClassification;
1146 uint16_t componentIdentifier;
1147 uint8_t componentClassificationIndex;
1148 uint32_t componentComparisonStamp;
1149 uint32_t componentImageSize;
1150 std::string strUpdateOptionFlags;
1151 std::string componentVersionStringType;
1152 uint8_t componentVersionStringLength;
1153 std::string componentVersionString;
1154 };
1155
1156 class ActivateFirmware : public CommandInterface
1157 {
1158 public:
1159 ~ActivateFirmware() = default;
1160 ActivateFirmware() = delete;
1161 ActivateFirmware(const ActivateFirmware&) = delete;
1162 ActivateFirmware(ActivateFirmware&&) = delete;
1163 ActivateFirmware& operator=(const ActivateFirmware&) = delete;
1164 ActivateFirmware& operator=(ActivateFirmware&&) = delete;
1165
ActivateFirmware(const char * type,const char * name,CLI::App * app)1166 explicit ActivateFirmware(const char* type, const char* name,
1167 CLI::App* app) : CommandInterface(type, name, app)
1168 {
1169 app->add_option("--self_contained_activation_request",
1170 selfContainedActivRequest,
1171 "Self contained activation request")
1172 ->required()
1173 ->transform(CLI::CheckedTransformer(pldmSelfContainedActivation,
1174 CLI::ignore_case));
1175 }
1176
createRequestMsg()1177 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1178 {
1179 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
1180 auto request = new (requestMsg.data()) pldm_msg;
1181 auto rc = encode_activate_firmware_req(
1182 instanceId, selfContainedActivRequest, request,
1183 sizeof(pldm_activate_firmware_req));
1184
1185 return {rc, requestMsg};
1186 }
1187
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1188 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1189 {
1190 uint8_t cc = 0;
1191 uint16_t estimatedTimeForActivation = 0;
1192
1193 auto rc = decode_activate_firmware_resp(responsePtr, payloadLength, &cc,
1194 &estimatedTimeForActivation);
1195 if (rc != PLDM_SUCCESS)
1196 {
1197 std::cerr << "Parsing ActivateFirmware response failed: "
1198 << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1199 return;
1200 }
1201
1202 ordered_json data;
1203 fillCompletionCode(cc, data, PLDM_FWUP);
1204
1205 if (cc == PLDM_SUCCESS)
1206 {
1207 data["EstimatedTimeForSelfContainedActivation"] =
1208 std::to_string(estimatedTimeForActivation) + "s";
1209 }
1210
1211 pldmtool::helper::DisplayInJson(data);
1212 }
1213
1214 private:
1215 bool8_t selfContainedActivRequest;
1216 };
1217
1218 class CancelUpdateComponent : public CommandInterface
1219 {
1220 public:
1221 ~CancelUpdateComponent() = default;
1222 CancelUpdateComponent() = delete;
1223 CancelUpdateComponent(const CancelUpdateComponent&) = delete;
1224 CancelUpdateComponent(CancelUpdateComponent&&) = delete;
1225 CancelUpdateComponent& operator=(const CancelUpdateComponent&) = delete;
1226 CancelUpdateComponent& operator=(CancelUpdateComponent&&) = delete;
1227
1228 using CommandInterface::CommandInterface;
1229
createRequestMsg()1230 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1231 {
1232 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
1233 auto request = new (requestMsg.data()) pldm_msg;
1234 auto rc = encode_cancel_update_component_req(
1235 instanceId, request, PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES);
1236 return {rc, requestMsg};
1237 }
1238
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1239 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1240 {
1241 uint8_t cc = 0;
1242
1243 auto rc = decode_cancel_update_component_resp(responsePtr,
1244 payloadLength, &cc);
1245 if (rc != PLDM_SUCCESS)
1246 {
1247 std::cerr << "Parsing CancelUpdateComponent response failed: "
1248 << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1249 return;
1250 }
1251
1252 ordered_json data;
1253 fillCompletionCode(cc, data, PLDM_FWUP);
1254
1255 pldmtool::helper::DisplayInJson(data);
1256 }
1257 };
1258
1259 class CancelUpdate : public CommandInterface
1260 {
1261 public:
1262 ~CancelUpdate() = default;
1263 CancelUpdate() = delete;
1264 CancelUpdate(const CancelUpdate&) = delete;
1265 CancelUpdate(CancelUpdate&&) = delete;
1266 CancelUpdate& operator=(const CancelUpdate&) = delete;
1267 CancelUpdate& operator=(CancelUpdate&&) = delete;
1268
1269 using CommandInterface::CommandInterface;
1270
createRequestMsg()1271 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1272 {
1273 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
1274 auto request = new (requestMsg.data()) pldm_msg;
1275 auto rc = encode_cancel_update_req(instanceId, request,
1276 PLDM_CANCEL_UPDATE_REQ_BYTES);
1277
1278 return {rc, requestMsg};
1279 }
1280
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1281 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1282 {
1283 uint8_t cc = 0;
1284 bool8_t nonFunctioningComponentIndication;
1285 bitfield64_t nonFunctioningComponentBitmap{0};
1286 auto rc = decode_cancel_update_resp(responsePtr, payloadLength, &cc,
1287 &nonFunctioningComponentIndication,
1288 &nonFunctioningComponentBitmap);
1289 if (rc != PLDM_SUCCESS)
1290 {
1291 std::cerr << "Parsing CancelUpdate response failed: "
1292 << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1293 return;
1294 }
1295
1296 ordered_json data;
1297
1298 fillCompletionCode(cc, data, PLDM_FWUP);
1299
1300 if (cc == PLDM_SUCCESS)
1301 {
1302 data["NonFunctioningComponentIndication"] =
1303 nonFunctioningComponentIndication ? "True" : "False";
1304
1305 if (nonFunctioningComponentIndication)
1306 {
1307 data["NonFunctioningComponentBitmap"] =
1308 std::to_string(nonFunctioningComponentBitmap.value);
1309 }
1310 }
1311
1312 pldmtool::helper::DisplayInJson(data);
1313 }
1314 };
1315
registerCommand(CLI::App & app)1316 void registerCommand(CLI::App& app)
1317 {
1318 auto fwUpdate =
1319 app.add_subcommand("fw_update", "firmware update type commands");
1320 fwUpdate->require_subcommand(1);
1321
1322 auto getStatus = fwUpdate->add_subcommand("GetStatus", "Status of the FD");
1323 commands.push_back(
1324 std::make_unique<GetStatus>("fw_update", "GetStatus", getStatus));
1325
1326 auto getFwParams = fwUpdate->add_subcommand(
1327 "GetFwParams", "To get the component details of the FD");
1328 commands.push_back(
1329 std::make_unique<GetFwParams>("fw_update", "GetFwParams", getFwParams));
1330
1331 auto queryDeviceIdentifiers = fwUpdate->add_subcommand(
1332 "QueryDeviceIdentifiers", "To query device identifiers of the FD");
1333 commands.push_back(std::make_unique<QueryDeviceIdentifiers>(
1334 "fw_update", "QueryDeviceIdentifiers", queryDeviceIdentifiers));
1335
1336 auto requestUpdate = fwUpdate->add_subcommand(
1337 "RequestUpdate", "To initiate a firmware update");
1338 commands.push_back(std::make_unique<RequestUpdate>(
1339 "fw_update", "RequestUpdate", requestUpdate));
1340
1341 auto passCompTable = fwUpdate->add_subcommand("PassComponentTable",
1342 "To pass component table");
1343 commands.push_back(std::make_unique<PassComponentTable>(
1344 "fw_update", "PassComponentTable", passCompTable));
1345
1346 auto updateComp = fwUpdate->add_subcommand(
1347 "UpdateComponent", "To request updating a specific firmware component");
1348 commands.push_back(std::make_unique<UpdateComponent>(
1349 "fw_update", "UpdateComponent", updateComp));
1350
1351 auto activateFirmware =
1352 fwUpdate->add_subcommand("ActivateFirmware", "To activate firmware");
1353 commands.push_back(std::make_unique<ActivateFirmware>(
1354 "fw_update", "ActivateFirmware", activateFirmware));
1355
1356 auto cancelUpdateComp = fwUpdate->add_subcommand(
1357 "CancelUpdateComponent", "To cancel component update");
1358 commands.push_back(std::make_unique<CancelUpdateComponent>(
1359 "fw_update", "CancelUpdateComponent", cancelUpdateComp));
1360
1361 auto cancelUpdate =
1362 fwUpdate->add_subcommand("CancelUpdate", "To cancel update");
1363 commands.push_back(std::make_unique<CancelUpdate>(
1364 "fw_update", "CancelUpdate", cancelUpdate));
1365 }
1366
1367 } // namespace fw_update
1368
1369 } // namespace pldmtool
1370