blob: 4c740d52f3c884d8e9342d05eef481af0eaf806a [file] [log] [blame]
Tom Josepheea835a2021-10-25 19:30:32 +05301#include "pldm_fw_update_cmd.hpp"
2
Tom Josepheea835a2021-10-25 19:30:32 +05303#include "common/utils.hpp"
4#include "pldm_cmd_helper.hpp"
5
George Liuc453e162022-12-21 17:16:23 +08006#include <libpldm/firmware_update.h>
7
rajeeranjan2bc3dd02025-03-25 15:22:24 +05308#include <format>
9
Tom Josepheea835a2021-10-25 19:30:32 +053010namespace pldmtool
11{
12
13namespace fw_update
14{
15
16namespace
17{
18
19using namespace pldmtool::helper;
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +053020using namespace pldm::fw_update;
Tom Josepheea835a2021-10-25 19:30:32 +053021
22std::vector<std::unique_ptr<CommandInterface>> commands;
23
24} // namespace
25
26const 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
35const 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
42const 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"},
Manojkiran Eda2576aec2024-06-17 12:05:17 +053046 {PLDM_FD_GENERIC_ERROR, "Generic Error has occurred"}};
Tom Josepheea835a2021-10-25 19:30:32 +053047
48const 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
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +053059/**
60 * @brief descriptor type to name mapping
61 *
62 */
63const 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
rajeeranjan2bc3dd02025-03-25 15:22:24 +053077/*
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 */
84uint8_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
Tom Josepheea835a2021-10-25 19:30:32 +0530106class 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;
Pavithra Barithayaa7dbca52023-07-07 04:19:37 -0500114 GetStatus& operator=(GetStatus&&) = delete;
Tom Josepheea835a2021-10-25 19:30:32 +0530115
116 using CommandInterface::CommandInterface;
117
118 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
119 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400120 std::vector<uint8_t> requestMsg(
121 sizeof(pldm_msg_hdr) + PLDM_GET_STATUS_REQ_BYTES);
Pavithra Barithaya5c3f0d12025-01-30 14:05:49 +0530122 auto request = new (requestMsg.data()) pldm_msg;
Tom Josepheea835a2021-10-25 19:30:32 +0530123 auto rc = encode_get_status_req(instanceId, request,
124 PLDM_GET_STATUS_REQ_BYTES);
125 return {rc, requestMsg};
126 }
127
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, &currentState,
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
Tom Joseph6f2a2482021-10-27 18:28:16 +0530179const 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
196class 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;
Pavithra Barithayaa7dbca52023-07-07 04:19:37 -0500204 GetFwParams& operator=(GetFwParams&&) = delete;
Tom Joseph6f2a2482021-10-27 18:28:16 +0530205
206 using CommandInterface::CommandInterface;
207
208 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
209 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400210 std::vector<uint8_t> requestMsg(
211 sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
Pavithra Barithaya5c3f0d12025-01-30 14:05:49 +0530212 auto request = new (requestMsg.data()) pldm_msg;
Tom Joseph6f2a2482021-10-27 18:28:16 +0530213 auto rc = encode_get_firmware_parameters_req(
214 instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
215 return {rc, requestMsg};
216 }
217
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;
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400431 compParamTableLen -=
432 sizeof(pldm_component_parameter_entry) +
433 activeCompVerStr.length + pendingCompVerStr.length;
Tom Joseph6f2a2482021-10-27 18:28:16 +0530434 compDataEntries.push_back(compData);
435 }
436 data["ComponentParameterEntries"] = compDataEntries;
437
438 pldmtool::helper::DisplayInJson(data);
439 }
440};
441
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530442class 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;
Pavithra Barithayaa7dbca52023-07-07 04:19:37 -0500450 QueryDeviceIdentifiers& operator=(QueryDeviceIdentifiers&&) = delete;
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530451
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
483void 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
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400527 ordered_json descriptor = ordered_json::object(
528 {{"Type", descriptorName.at(descriptorType)},
529 {"Value", ordered_json::array()}});
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530530 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}
549std::pair<int, std::vector<uint8_t>> QueryDeviceIdentifiers::createRequestMsg()
550{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400551 std::vector<uint8_t> requestMsg(
552 sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
Pavithra Barithaya5c3f0d12025-01-30 14:05:49 +0530553 auto request = new (requestMsg.data()) pldm_msg;
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530554 auto rc = encode_query_device_identifiers_req(
555 instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
556 return {rc, requestMsg};
557}
558
559void 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
rajeeranjan2bc3dd02025-03-25 15:22:24 +0530645class 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
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
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
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
Tom Josepheea835a2021-10-25 19:30:32 +0530794void registerCommand(CLI::App& app)
795{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400796 auto fwUpdate =
797 app.add_subcommand("fw_update", "firmware update type commands");
Tom Josepheea835a2021-10-25 19:30:32 +0530798 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));
Tom Joseph6f2a2482021-10-27 18:28:16 +0530803
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));
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530808
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));
rajeeranjan2bc3dd02025-03-25 15:22:24 +0530813
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));
Tom Josepheea835a2021-10-25 19:30:32 +0530818}
819
820} // namespace fw_update
821
Patrick Williams6da4f912023-05-10 07:50:53 -0500822} // namespace pldmtool