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 /*
78 * Convert PLDM Firmware String Type to uint8_t
79 *
80 * @param[in] compImgVerStrType - the component version string
81 *
82 * @return - the component version string converted to a numeric value.
83 */
convertStringTypeToUInt8(std::string compImgVerStrType)84 uint8_t convertStringTypeToUInt8(std::string compImgVerStrType)
85 {
86 static const std::map<std::string, pldm_firmware_update_string_type>
87 pldmFirmwareUpdateStringType{
88 {"UNKNOWN", PLDM_STR_TYPE_UNKNOWN},
89 {"ASCII", PLDM_STR_TYPE_ASCII},
90 {"UTF_8", PLDM_STR_TYPE_UTF_8},
91 {"UTF_16", PLDM_STR_TYPE_UTF_16},
92 {"UTF_16LE", PLDM_STR_TYPE_UTF_16LE},
93 {"UTF_16BE", PLDM_STR_TYPE_UTF_16BE},
94 };
95
96 if (pldmFirmwareUpdateStringType.contains(compImgVerStrType))
97 {
98 return pldmFirmwareUpdateStringType.at(compImgVerStrType);
99 }
100 else
101 {
102 return static_cast<uint8_t>(std::stoi(compImgVerStrType));
103 }
104 }
105
106 class GetStatus : public CommandInterface
107 {
108 public:
109 ~GetStatus() = default;
110 GetStatus() = delete;
111 GetStatus(const GetStatus&) = delete;
112 GetStatus(GetStatus&&) = default;
113 GetStatus& operator=(const GetStatus&) = delete;
114 GetStatus& operator=(GetStatus&&) = delete;
115
116 using CommandInterface::CommandInterface;
117
createRequestMsg()118 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
119 {
120 std::vector<uint8_t> requestMsg(
121 sizeof(pldm_msg_hdr) + PLDM_GET_STATUS_REQ_BYTES);
122 auto request = new (requestMsg.data()) pldm_msg;
123 auto rc = encode_get_status_req(instanceId, request,
124 PLDM_GET_STATUS_REQ_BYTES);
125 return {rc, requestMsg};
126 }
127
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)128 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
129 {
130 uint8_t completionCode = 0;
131 uint8_t currentState = 0;
132 uint8_t previousState = 0;
133 uint8_t auxState = 0;
134 uint8_t auxStateStatus = 0;
135 uint8_t progressPercent = 0;
136 uint8_t reasonCode = 0;
137 bitfield32_t updateOptionFlagsEnabled{0};
138
139 auto rc = decode_get_status_resp(
140 responsePtr, payloadLength, &completionCode, ¤tState,
141 &previousState, &auxState, &auxStateStatus, &progressPercent,
142 &reasonCode, &updateOptionFlagsEnabled);
143 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
144 {
145 std::cerr << "Response Message Error: "
146 << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
147 return;
148 }
149
150 ordered_json data;
151 data["CurrentState"] = fdStateMachine.at(currentState);
152 data["PreviousState"] = fdStateMachine.at(previousState);
153 data["AuxState"] = fdAuxState.at(auxState);
154 if (auxStateStatus >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
155 auxStateStatus <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)
156 {
157 data["AuxStateStatus"] = auxStateStatus;
158 }
159 else
160 {
161 data["AuxStateStatus"] = fdAuxStateStatus.at(auxStateStatus);
162 }
163 data["ProgressPercent"] = progressPercent;
164 if (reasonCode >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN &&
165 reasonCode <= PLDM_FD_STATUS_VENDOR_DEFINED_MAX)
166 {
167 data["ReasonCode"] = reasonCode;
168 }
169 else
170 {
171 data["ReasonCode"] = fdReasonCode.at(reasonCode);
172 }
173 data["UpdateOptionFlagsEnabled"] = updateOptionFlagsEnabled.value;
174
175 pldmtool::helper::DisplayInJson(data);
176 }
177 };
178
179 const std::map<uint16_t, std::string> componentClassification{
180 {PLDM_COMP_UNKNOWN, "Unknown"},
181 {PLDM_COMP_OTHER, "Other"},
182 {PLDM_COMP_DRIVER, "Driver"},
183 {PLDM_COMP_CONFIGURATION_SOFTWARE, "Configuration Software"},
184 {PLDM_COMP_APPLICATION_SOFTWARE, "Application Software"},
185 {PLDM_COMP_INSTRUMENTATION, "Instrumentation"},
186 {PLDM_COMP_FIRMWARE_OR_BIOS, "Firmware/BIOS"},
187 {PLDM_COMP_DIAGNOSTIC_SOFTWARE, "Diagnostic Software"},
188 {PLDM_COMP_OPERATING_SYSTEM, "Operating System"},
189 {PLDM_COMP_MIDDLEWARE, "Middleware"},
190 {PLDM_COMP_FIRMWARE, "Firmware"},
191 {PLDM_COMP_BIOS_OR_FCODE, "BIOS/FCode"},
192 {PLDM_COMP_SUPPORT_OR_SERVICEPACK, "Support/Service Pack"},
193 {PLDM_COMP_SOFTWARE_BUNDLE, "Software Bundle"},
194 {PLDM_COMP_DOWNSTREAM_DEVICE, "Downstream Device"}};
195
196 class GetFwParams : public CommandInterface
197 {
198 public:
199 ~GetFwParams() = default;
200 GetFwParams() = delete;
201 GetFwParams(const GetFwParams&) = delete;
202 GetFwParams(GetFwParams&&) = default;
203 GetFwParams& operator=(const GetFwParams&) = delete;
204 GetFwParams& operator=(GetFwParams&&) = delete;
205
206 using CommandInterface::CommandInterface;
207
createRequestMsg()208 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
209 {
210 std::vector<uint8_t> requestMsg(
211 sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
212 auto request = new (requestMsg.data()) pldm_msg;
213 auto rc = encode_get_firmware_parameters_req(
214 instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
215 return {rc, requestMsg};
216 }
217
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)218 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
219 {
220 pldm_get_firmware_parameters_resp fwParams{};
221 variable_field activeCompImageSetVersion{};
222 variable_field pendingCompImageSetVersion{};
223 variable_field compParameterTable{};
224
225 auto rc = decode_get_firmware_parameters_resp(
226 responsePtr, payloadLength, &fwParams, &activeCompImageSetVersion,
227 &pendingCompImageSetVersion, &compParameterTable);
228 if (rc != PLDM_SUCCESS || fwParams.completion_code != PLDM_SUCCESS)
229 {
230 std::cerr << "Response Message Error: "
231 << "rc=" << rc << ",cc=" << (int)fwParams.completion_code
232 << "\n";
233 return;
234 }
235
236 ordered_json capabilitiesDuringUpdate;
237 if (fwParams.capabilities_during_update.bits.bit0)
238 {
239 capabilitiesDuringUpdate
240 ["Component Update Failure Recovery Capability"] =
241 "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer.";
242 }
243 else
244 {
245 capabilitiesDuringUpdate
246 ["Component Update Failure Recovery Capability"] =
247 "Device will revert to previous component image upon failure, timeout or cancellation of the transfer.";
248 }
249
250 if (fwParams.capabilities_during_update.bits.bit1)
251 {
252 capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
253 "Device will not be able to update component again unless it exits update mode and the UA sends a new Request Update command.";
254 }
255 else
256 {
257 capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
258 " Device can have component updated again without exiting update mode and restarting transfer via RequestUpdate command.";
259 }
260
261 if (fwParams.capabilities_during_update.bits.bit2)
262 {
263 capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
264 "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.";
265 }
266 else
267 {
268 capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
269 "Firmware Device cannot accept a partial update and all components present on the FD shall be updated.";
270 }
271
272 if (fwParams.capabilities_during_update.bits.bit3)
273 {
274 capabilitiesDuringUpdate
275 ["Firmware Device Host Functionality during Firmware Update"] =
276 "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer";
277 }
278 else
279 {
280 capabilitiesDuringUpdate
281 ["Firmware Device Host Functionality during Firmware Update"] =
282 "Device will revert to previous component image upon failure, timeout or cancellation of the transfer";
283 }
284
285 if (fwParams.capabilities_during_update.bits.bit4)
286 {
287 capabilitiesDuringUpdate["Firmware Device Update Mode Restrictions"] =
288 "Firmware device unable to enter update mode if host OS environment is active.";
289 }
290 else
291 {
292 capabilitiesDuringUpdate
293 ["Firmware Device Update Mode Restrictions"] =
294 "No host OS environment restriction for update mode";
295 }
296
297 ordered_json data;
298 data["CapabilitiesDuringUpdate"] = capabilitiesDuringUpdate;
299 data["ComponentCount"] = static_cast<uint16_t>(fwParams.comp_count);
300 data["ActiveComponentImageSetVersionString"] =
301 pldm::utils::toString(activeCompImageSetVersion);
302 data["PendingComponentImageSetVersionString"] =
303 pldm::utils::toString(pendingCompImageSetVersion);
304
305 auto compParamPtr = compParameterTable.ptr;
306 auto compParamTableLen = compParameterTable.length;
307 pldm_component_parameter_entry compEntry{};
308 variable_field activeCompVerStr{};
309 variable_field pendingCompVerStr{};
310 ordered_json compDataEntries;
311
312 while (fwParams.comp_count-- && (compParamTableLen > 0))
313 {
314 ordered_json compData;
315 auto rc = decode_get_firmware_parameters_resp_comp_entry(
316 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
317 &pendingCompVerStr);
318 if (rc)
319 {
320 std::cerr
321 << "Decoding component parameter table entry failed, RC="
322 << rc << "\n";
323 return;
324 }
325
326 if (componentClassification.contains(compEntry.comp_classification))
327 {
328 compData["ComponentClassification"] =
329 componentClassification.at(compEntry.comp_classification);
330 }
331 else
332 {
333 compData["ComponentClassification"] =
334 static_cast<uint16_t>(compEntry.comp_classification);
335 }
336 compData["ComponentIdentifier"] =
337 static_cast<uint16_t>(compEntry.comp_identifier);
338 compData["ComponentClassificationIndex"] =
339 static_cast<uint8_t>(compEntry.comp_classification_index);
340 compData["ActiveComponentComparisonStamp"] =
341 static_cast<uint32_t>(compEntry.active_comp_comparison_stamp);
342
343 // ActiveComponentReleaseData
344 std::array<uint8_t, 8> noReleaseData{0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00};
346 if (std::equal(noReleaseData.begin(), noReleaseData.end(),
347 compEntry.active_comp_release_date))
348 {
349 compData["ActiveComponentReleaseDate"] = "";
350 }
351 else
352 {
353 std::string activeComponentReleaseDate(
354 reinterpret_cast<const char*>(
355 compEntry.active_comp_release_date),
356 sizeof(compEntry.active_comp_release_date));
357 compData["ActiveComponentReleaseDate"] =
358 activeComponentReleaseDate;
359 }
360
361 compData["PendingComponentComparisonStamp"] =
362 static_cast<uint32_t>(compEntry.pending_comp_comparison_stamp);
363
364 // PendingComponentReleaseData
365 if (std::equal(noReleaseData.begin(), noReleaseData.end(),
366 compEntry.pending_comp_release_date))
367 {
368 compData["PendingComponentReleaseDate"] = "";
369 }
370 else
371 {
372 std::string pendingComponentReleaseDate(
373 reinterpret_cast<const char*>(
374 compEntry.pending_comp_release_date),
375 sizeof(compEntry.pending_comp_release_date));
376 compData["PendingComponentReleaseDate"] =
377 pendingComponentReleaseDate;
378 }
379
380 // ComponentActivationMethods
381 ordered_json componentActivationMethods;
382 if (compEntry.comp_activation_methods.bits.bit0)
383 {
384 componentActivationMethods.push_back("Automatic");
385 }
386 else if (compEntry.comp_activation_methods.bits.bit1)
387 {
388 componentActivationMethods.push_back("Self-Contained");
389 }
390 else if (compEntry.comp_activation_methods.bits.bit2)
391 {
392 componentActivationMethods.push_back("Medium-specific reset");
393 }
394 else if (compEntry.comp_activation_methods.bits.bit3)
395 {
396 componentActivationMethods.push_back("System reboot");
397 }
398 else if (compEntry.comp_activation_methods.bits.bit4)
399 {
400 componentActivationMethods.push_back("DC power cycel");
401 }
402 else if (compEntry.comp_activation_methods.bits.bit5)
403 {
404 componentActivationMethods.push_back("AC power cycle");
405 }
406 compData["ComponentActivationMethods"] = componentActivationMethods;
407
408 // CapabilitiesDuringUpdate
409 ordered_json compCapabilitiesDuringUpdate;
410 if (compEntry.capabilities_during_update.bits.bit0)
411 {
412 compCapabilitiesDuringUpdate
413 ["Firmware Device apply state functionality"] =
414 "Firmware Device performs an auto-apply during transfer phase and apply step will be completed immediately.";
415 }
416 else
417 {
418 compCapabilitiesDuringUpdate
419 ["Firmware Device apply state functionality"] =
420 " 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.";
421 }
422 compData["CapabilitiesDuringUpdate"] = compCapabilitiesDuringUpdate;
423
424 compData["ActiveComponentVersionString"] =
425 pldm::utils::toString(activeCompVerStr);
426 compData["PendingComponentVersionString"] =
427 pldm::utils::toString(pendingCompVerStr);
428
429 compParamPtr += sizeof(pldm_component_parameter_entry) +
430 activeCompVerStr.length + pendingCompVerStr.length;
431 compParamTableLen -=
432 sizeof(pldm_component_parameter_entry) +
433 activeCompVerStr.length + pendingCompVerStr.length;
434 compDataEntries.push_back(compData);
435 }
436 data["ComponentParameterEntries"] = compDataEntries;
437
438 pldmtool::helper::DisplayInJson(data);
439 }
440 };
441
442 class QueryDeviceIdentifiers : public CommandInterface
443 {
444 public:
445 ~QueryDeviceIdentifiers() = default;
446 QueryDeviceIdentifiers() = delete;
447 QueryDeviceIdentifiers(const QueryDeviceIdentifiers&) = delete;
448 QueryDeviceIdentifiers(QueryDeviceIdentifiers&&) = default;
449 QueryDeviceIdentifiers& operator=(const QueryDeviceIdentifiers&) = delete;
450 QueryDeviceIdentifiers& operator=(QueryDeviceIdentifiers&&) = delete;
451
452 /**
453 * @brief Implementation of createRequestMsg for QueryDeviceIdentifiers
454 *
455 * @return std::pair<int, std::vector<uint8_t>>
456 */
457 std::pair<int, std::vector<uint8_t>> createRequestMsg() override;
458
459 /**
460 * @brief Implementation of parseResponseMsg for QueryDeviceIdentifiers
461 *
462 * @param[in] responsePtr
463 * @param[in] payloadLength
464 */
465 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override;
466 using CommandInterface::CommandInterface;
467
468 private:
469 /**
470 * @brief Method to update QueryDeviceIdentifiers json response in a user
471 * friendly format
472 *
473 * @param[in] descriptors - descriptor json response
474 * @param[in] descriptorType - descriptor type
475 * @param[in] descriptorVal - descriptor value
476 */
477 void updateDescriptor(
478 ordered_json& descriptors, const DescriptorType& descriptorType,
479 const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
480 descriptorVal);
481 };
482
updateDescriptor(ordered_json & descriptors,const DescriptorType & descriptorType,const std::variant<DescriptorData,VendorDefinedDescriptorInfo> & descriptorVal)483 void QueryDeviceIdentifiers::updateDescriptor(
484 ordered_json& descriptors, const DescriptorType& descriptorType,
485 const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
486 descriptorVal)
487 {
488 std::ostringstream descDataStream;
489 DescriptorData descData;
490 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
491 {
492 descData = std::get<DescriptorData>(descriptorVal);
493 }
494 else
495 {
496 descData = std::get<VendorDefinedDescriptorData>(
497 std::get<VendorDefinedDescriptorInfo>(descriptorVal));
498 }
499 for (int byte : descData)
500 {
501 descDataStream << std::setfill('0') << std::setw(2) << std::hex << byte;
502 }
503
504 if (descriptorName.contains(descriptorType))
505 {
506 // Update the existing json response if entry is already present
507 for (auto& descriptor : descriptors)
508 {
509 if (descriptor["Type"] == descriptorName.at(descriptorType))
510 {
511 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
512 {
513 descriptor["Value"].emplace_back(descDataStream.str());
514 }
515 else
516 {
517 ordered_json vendorDefinedVal;
518 vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
519 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
520 descDataStream.str();
521 descriptor["Value"].emplace_back(vendorDefinedVal);
522 }
523 return;
524 }
525 }
526 // Entry is not present, add type and value to json response
527 ordered_json descriptor = ordered_json::object(
528 {{"Type", descriptorName.at(descriptorType)},
529 {"Value", ordered_json::array()}});
530 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
531 {
532 descriptor["Value"].emplace_back(descDataStream.str());
533 }
534 else
535 {
536 ordered_json vendorDefinedVal;
537 vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
538 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
539 descDataStream.str();
540 descriptor["Value"].emplace_back(vendorDefinedVal);
541 }
542 descriptors.emplace_back(descriptor);
543 }
544 else
545 {
546 std::cerr << "Unknown descriptor type, type=" << descriptorType << "\n";
547 }
548 }
createRequestMsg()549 std::pair<int, std::vector<uint8_t>> QueryDeviceIdentifiers::createRequestMsg()
550 {
551 std::vector<uint8_t> requestMsg(
552 sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
553 auto request = new (requestMsg.data()) pldm_msg;
554 auto rc = encode_query_device_identifiers_req(
555 instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
556 return {rc, requestMsg};
557 }
558
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)559 void QueryDeviceIdentifiers::parseResponseMsg(pldm_msg* responsePtr,
560 size_t payloadLength)
561 {
562 uint8_t completionCode = PLDM_SUCCESS;
563 uint32_t deviceIdentifiersLen = 0;
564 uint8_t descriptorCount = 0;
565 uint8_t* descriptorPtr = nullptr;
566 uint8_t eid = getMCTPEID();
567 auto rc = decode_query_device_identifiers_resp(
568 responsePtr, payloadLength, &completionCode, &deviceIdentifiersLen,
569 &descriptorCount, &descriptorPtr);
570 if (rc)
571 {
572 std::cerr << "Decoding QueryDeviceIdentifiers response failed,EID="
573 << unsigned(eid) << ", RC=" << rc << "\n";
574 return;
575 }
576 if (completionCode)
577 {
578 std::cerr << "QueryDeviceIdentifiers response failed with error "
579 "completion code, EID="
580 << unsigned(eid) << ", CC=" << unsigned(completionCode)
581 << "\n";
582 return;
583 }
584 ordered_json data;
585 data["EID"] = eid;
586 ordered_json descriptors;
587 while (descriptorCount-- && (deviceIdentifiersLen > 0))
588 {
589 DescriptorType descriptorType = 0;
590 variable_field descriptorData{};
591
592 rc = decode_descriptor_type_length_value(
593 descriptorPtr, deviceIdentifiersLen, &descriptorType,
594 &descriptorData);
595 if (rc)
596 {
597 std::cerr << "Decoding descriptor type, length and value failed,"
598 << "EID=" << unsigned(eid) << ",RC=" << rc << "\n ";
599 return;
600 }
601
602 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
603 {
604 std::vector<uint8_t> descData(
605 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
606 updateDescriptor(descriptors, descriptorType, descData);
607 }
608 else
609 {
610 uint8_t descriptorTitleStrType = 0;
611 variable_field descriptorTitleStr{};
612 variable_field vendorDefinedDescriptorData{};
613
614 rc = decode_vendor_defined_descriptor_value(
615 descriptorData.ptr, descriptorData.length,
616 &descriptorTitleStrType, &descriptorTitleStr,
617 &vendorDefinedDescriptorData);
618 if (rc)
619 {
620 std::cerr << "Decoding Vendor-defined descriptor value"
621 << "failed EID=" << unsigned(eid) << ", RC=" << rc
622 << "\n ";
623 return;
624 }
625
626 auto vendorDescTitle = pldm::utils::toString(descriptorTitleStr);
627 std::vector<uint8_t> vendorDescData(
628 vendorDefinedDescriptorData.ptr,
629 vendorDefinedDescriptorData.ptr +
630 vendorDefinedDescriptorData.length);
631 updateDescriptor(descriptors, descriptorType,
632 std::make_tuple(vendorDescTitle, vendorDescData));
633 }
634 auto nextDescriptorOffset =
635 sizeof(pldm_descriptor_tlv().descriptor_type) +
636 sizeof(pldm_descriptor_tlv().descriptor_length) +
637 descriptorData.length;
638 descriptorPtr += nextDescriptorOffset;
639 deviceIdentifiersLen -= nextDescriptorOffset;
640 }
641 data["Descriptors"] = descriptors;
642 pldmtool::helper::DisplayInJson(data);
643 }
644
645 class RequestUpdate : public CommandInterface
646 {
647 public:
648 ~RequestUpdate() = default;
649 RequestUpdate() = delete;
650 RequestUpdate(const RequestUpdate&) = delete;
651 RequestUpdate(RequestUpdate&&) = delete;
652 RequestUpdate& operator=(const RequestUpdate&) = delete;
653 RequestUpdate& operator=(RequestUpdate&&) = delete;
654
RequestUpdate(const char * type,const char * name,CLI::App * app)655 explicit RequestUpdate(const char* type, const char* name, CLI::App* app) :
656 CommandInterface(type, name, app)
657 {
658 app->add_option(
659 "--max_transfer_size", maxTransferSize,
660 "Specifies the maximum size, in bytes, of the variable payload allowed to\n"
661 "be requested by the FD via the RequestFirmwareData command that is contained\n"
662 "within a PLDM message. This value shall be equal to or greater than firmware update\n"
663 "baseline transfer size.")
664 ->required();
665
666 app->add_option(
667 "--num_comps", numComps,
668 "Specifies the number of components that will be passed to the FD during the update.\n"
669 "The FD can use this value to compare against the number of PassComponentTable\n"
670 "commands received.")
671 ->required();
672
673 app->add_option(
674 "--max_transfer_reqs", maxTransferReqs,
675 "Specifies the number of outstanding RequestFirmwareData commands that can be\n"
676 "sent by the FD. The minimum required value is '1' which the UA shall support.\n"
677 "It is optional for the UA to support a value higher than '1' for this field.")
678 ->required();
679
680 app->add_option(
681 "--package_data_length", packageDataLength,
682 "This field shall be set to the value contained within\n"
683 "the FirmwareDevicePackageDataLength field that was provided in\n"
684 "the firmware package header. If no firmware package data was\n"
685 "provided in the firmware update package then this length field\n"
686 "shall be set to 0x0000.")
687 ->required();
688
689 app->add_option(
690 "--comp_img_ver_str_type", compImgVerStrType,
691 "The type of string used in the ComponentImageSetVersionString\n"
692 "field. Possible values\n"
693 "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
694 "OR {0,1,2,3,4,5}")
695 ->required()
696 ->check([](const std::string& value) -> std::string {
697 static const std::set<std::string> validStrings{
698 "UNKNOWN", "ASCII", "UTF_8",
699 "UTF_16", "UTF_16LE", "UTF_16BE"};
700
701 if (validStrings.contains(value))
702 {
703 return "";
704 }
705
706 try
707 {
708 int intValue = std::stoi(value);
709 if (intValue >= 0 && intValue <= 255)
710 {
711 return "";
712 }
713 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
714 }
715 catch (const std::exception&)
716 {
717 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
718 }
719 });
720
721 app->add_option(
722 "--comp_img_ver_str_len", compImgVerStrLen,
723 "The length, in bytes, of the ComponentImageSetVersionString.")
724 ->required();
725
726 app->add_option(
727 "--comp_img_set_ver_str", compImgSetVerStr,
728 "Component Image Set version information, up to 255 bytes.")
729 ->required();
730 }
731
createRequestMsg()732 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
733 {
734 variable_field compImgSetVerStrInfo{};
735 compImgSetVerStrInfo.ptr =
736 reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());
737 compImgSetVerStrInfo.length =
738 static_cast<uint8_t>(compImgSetVerStr.size());
739
740 std::vector<uint8_t> requestMsg(
741 sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) +
742 compImgSetVerStrInfo.length);
743
744 auto request = new (requestMsg.data()) pldm_msg;
745
746 auto rc = encode_request_update_req(
747 instanceId, maxTransferSize, numComps, maxTransferReqs,
748 packageDataLength, convertStringTypeToUInt8(compImgVerStrType),
749 compImgVerStrLen, &compImgSetVerStrInfo, request,
750 sizeof(struct pldm_request_update_req) +
751 compImgSetVerStrInfo.length);
752
753 return {rc, requestMsg};
754 }
755
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)756 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
757 {
758 uint8_t cc = 0;
759 uint16_t fdMetaDataLen = 0;
760 uint8_t fdWillSendPkgData = 0;
761
762 auto rc =
763 decode_request_update_resp(responsePtr, payloadLength, &cc,
764 &fdMetaDataLen, &fdWillSendPkgData);
765 if (rc)
766 {
767 std::cerr << "Response Message Error: "
768 << "rc=" << rc << ",cc=" << (int)cc << "\n";
769 return;
770 }
771
772 ordered_json data;
773 fillCompletionCode(cc, data, PLDM_FWUP);
774
775 if (cc == PLDM_SUCCESS)
776 {
777 data["FirmwareDeviceMetaDataLength"] = fdMetaDataLen;
778 data["FDWillSendGetPackageDataCommand"] =
779 std::format("0x{:02X}", fdWillSendPkgData);
780 }
781 pldmtool::helper::DisplayInJson(data);
782 }
783
784 private:
785 uint32_t maxTransferSize;
786 uint16_t numComps;
787 uint8_t maxTransferReqs;
788 uint16_t packageDataLength;
789 std::string compImgVerStrType;
790 uint8_t compImgVerStrLen;
791 std::string compImgSetVerStr;
792 };
793
registerCommand(CLI::App & app)794 void registerCommand(CLI::App& app)
795 {
796 auto fwUpdate =
797 app.add_subcommand("fw_update", "firmware update type commands");
798 fwUpdate->require_subcommand(1);
799
800 auto getStatus = fwUpdate->add_subcommand("GetStatus", "Status of the FD");
801 commands.push_back(
802 std::make_unique<GetStatus>("fw_update", "GetStatus", getStatus));
803
804 auto getFwParams = fwUpdate->add_subcommand(
805 "GetFwParams", "To get the component details of the FD");
806 commands.push_back(
807 std::make_unique<GetFwParams>("fw_update", "GetFwParams", getFwParams));
808
809 auto queryDeviceIdentifiers = fwUpdate->add_subcommand(
810 "QueryDeviceIdentifiers", "To query device identifiers of the FD");
811 commands.push_back(std::make_unique<QueryDeviceIdentifiers>(
812 "fw_update", "QueryDeviceIdentifiers", queryDeviceIdentifiers));
813
814 auto requestUpdate = fwUpdate->add_subcommand(
815 "RequestUpdate", "To initiate a firmware update");
816 commands.push_back(std::make_unique<RequestUpdate>(
817 "fw_update", "RequestUpdate", requestUpdate));
818 }
819
820 } // namespace fw_update
821
822 } // namespace pldmtool
823