blob: d550fa6e47a901b34bc94c96ca103bbfb65c76f3 [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
rajeeranjan6f67ca72025-04-08 00:21:56 +053077const 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
rajeeranjan2bc3dd02025-03-25 15:22:24 +053084/*
85 * Convert PLDM Firmware String Type to uint8_t
86 *
87 * @param[in] compImgVerStrType - the component version string
88 *
89 * @return - the component version string converted to a numeric value.
90 */
91uint8_t convertStringTypeToUInt8(std::string compImgVerStrType)
92{
93 static const std::map<std::string, pldm_firmware_update_string_type>
94 pldmFirmwareUpdateStringType{
95 {"UNKNOWN", PLDM_STR_TYPE_UNKNOWN},
96 {"ASCII", PLDM_STR_TYPE_ASCII},
97 {"UTF_8", PLDM_STR_TYPE_UTF_8},
98 {"UTF_16", PLDM_STR_TYPE_UTF_16},
99 {"UTF_16LE", PLDM_STR_TYPE_UTF_16LE},
100 {"UTF_16BE", PLDM_STR_TYPE_UTF_16BE},
101 };
102
103 if (pldmFirmwareUpdateStringType.contains(compImgVerStrType))
104 {
105 return pldmFirmwareUpdateStringType.at(compImgVerStrType);
106 }
107 else
108 {
109 return static_cast<uint8_t>(std::stoi(compImgVerStrType));
110 }
111}
112
Tom Josepheea835a2021-10-25 19:30:32 +0530113class GetStatus : public CommandInterface
114{
115 public:
116 ~GetStatus() = default;
117 GetStatus() = delete;
118 GetStatus(const GetStatus&) = delete;
119 GetStatus(GetStatus&&) = default;
120 GetStatus& operator=(const GetStatus&) = delete;
Pavithra Barithayaa7dbca52023-07-07 04:19:37 -0500121 GetStatus& operator=(GetStatus&&) = delete;
Tom Josepheea835a2021-10-25 19:30:32 +0530122
123 using CommandInterface::CommandInterface;
124
125 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
126 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400127 std::vector<uint8_t> requestMsg(
128 sizeof(pldm_msg_hdr) + PLDM_GET_STATUS_REQ_BYTES);
Pavithra Barithaya5c3f0d12025-01-30 14:05:49 +0530129 auto request = new (requestMsg.data()) pldm_msg;
Tom Josepheea835a2021-10-25 19:30:32 +0530130 auto rc = encode_get_status_req(instanceId, request,
131 PLDM_GET_STATUS_REQ_BYTES);
132 return {rc, requestMsg};
133 }
134
135 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
136 {
137 uint8_t completionCode = 0;
138 uint8_t currentState = 0;
139 uint8_t previousState = 0;
140 uint8_t auxState = 0;
141 uint8_t auxStateStatus = 0;
142 uint8_t progressPercent = 0;
143 uint8_t reasonCode = 0;
144 bitfield32_t updateOptionFlagsEnabled{0};
145
146 auto rc = decode_get_status_resp(
147 responsePtr, payloadLength, &completionCode, &currentState,
148 &previousState, &auxState, &auxStateStatus, &progressPercent,
149 &reasonCode, &updateOptionFlagsEnabled);
150 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
151 {
152 std::cerr << "Response Message Error: "
153 << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
154 return;
155 }
156
157 ordered_json data;
158 data["CurrentState"] = fdStateMachine.at(currentState);
159 data["PreviousState"] = fdStateMachine.at(previousState);
160 data["AuxState"] = fdAuxState.at(auxState);
161 if (auxStateStatus >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
162 auxStateStatus <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)
163 {
164 data["AuxStateStatus"] = auxStateStatus;
165 }
166 else
167 {
168 data["AuxStateStatus"] = fdAuxStateStatus.at(auxStateStatus);
169 }
170 data["ProgressPercent"] = progressPercent;
171 if (reasonCode >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN &&
172 reasonCode <= PLDM_FD_STATUS_VENDOR_DEFINED_MAX)
173 {
174 data["ReasonCode"] = reasonCode;
175 }
176 else
177 {
178 data["ReasonCode"] = fdReasonCode.at(reasonCode);
179 }
180 data["UpdateOptionFlagsEnabled"] = updateOptionFlagsEnabled.value;
181
182 pldmtool::helper::DisplayInJson(data);
183 }
184};
185
Tom Joseph6f2a2482021-10-27 18:28:16 +0530186const std::map<uint16_t, std::string> componentClassification{
187 {PLDM_COMP_UNKNOWN, "Unknown"},
188 {PLDM_COMP_OTHER, "Other"},
189 {PLDM_COMP_DRIVER, "Driver"},
190 {PLDM_COMP_CONFIGURATION_SOFTWARE, "Configuration Software"},
191 {PLDM_COMP_APPLICATION_SOFTWARE, "Application Software"},
192 {PLDM_COMP_INSTRUMENTATION, "Instrumentation"},
193 {PLDM_COMP_FIRMWARE_OR_BIOS, "Firmware/BIOS"},
194 {PLDM_COMP_DIAGNOSTIC_SOFTWARE, "Diagnostic Software"},
195 {PLDM_COMP_OPERATING_SYSTEM, "Operating System"},
196 {PLDM_COMP_MIDDLEWARE, "Middleware"},
197 {PLDM_COMP_FIRMWARE, "Firmware"},
198 {PLDM_COMP_BIOS_OR_FCODE, "BIOS/FCode"},
199 {PLDM_COMP_SUPPORT_OR_SERVICEPACK, "Support/Service Pack"},
200 {PLDM_COMP_SOFTWARE_BUNDLE, "Software Bundle"},
201 {PLDM_COMP_DOWNSTREAM_DEVICE, "Downstream Device"}};
202
203class GetFwParams : public CommandInterface
204{
205 public:
206 ~GetFwParams() = default;
207 GetFwParams() = delete;
208 GetFwParams(const GetFwParams&) = delete;
209 GetFwParams(GetFwParams&&) = default;
210 GetFwParams& operator=(const GetFwParams&) = delete;
Pavithra Barithayaa7dbca52023-07-07 04:19:37 -0500211 GetFwParams& operator=(GetFwParams&&) = delete;
Tom Joseph6f2a2482021-10-27 18:28:16 +0530212
213 using CommandInterface::CommandInterface;
214
215 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
216 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400217 std::vector<uint8_t> requestMsg(
218 sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
Pavithra Barithaya5c3f0d12025-01-30 14:05:49 +0530219 auto request = new (requestMsg.data()) pldm_msg;
Tom Joseph6f2a2482021-10-27 18:28:16 +0530220 auto rc = encode_get_firmware_parameters_req(
221 instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
222 return {rc, requestMsg};
223 }
224
225 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
226 {
227 pldm_get_firmware_parameters_resp fwParams{};
228 variable_field activeCompImageSetVersion{};
229 variable_field pendingCompImageSetVersion{};
230 variable_field compParameterTable{};
231
232 auto rc = decode_get_firmware_parameters_resp(
233 responsePtr, payloadLength, &fwParams, &activeCompImageSetVersion,
234 &pendingCompImageSetVersion, &compParameterTable);
235 if (rc != PLDM_SUCCESS || fwParams.completion_code != PLDM_SUCCESS)
236 {
237 std::cerr << "Response Message Error: "
238 << "rc=" << rc << ",cc=" << (int)fwParams.completion_code
239 << "\n";
240 return;
241 }
242
243 ordered_json capabilitiesDuringUpdate;
244 if (fwParams.capabilities_during_update.bits.bit0)
245 {
246 capabilitiesDuringUpdate
247 ["Component Update Failure Recovery Capability"] =
248 "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer.";
249 }
250 else
251 {
252 capabilitiesDuringUpdate
253 ["Component Update Failure Recovery Capability"] =
254 "Device will revert to previous component image upon failure, timeout or cancellation of the transfer.";
255 }
256
257 if (fwParams.capabilities_during_update.bits.bit1)
258 {
259 capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
260 "Device will not be able to update component again unless it exits update mode and the UA sends a new Request Update command.";
261 }
262 else
263 {
264 capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
265 " Device can have component updated again without exiting update mode and restarting transfer via RequestUpdate command.";
266 }
267
268 if (fwParams.capabilities_during_update.bits.bit2)
269 {
270 capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
271 "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.";
272 }
273 else
274 {
275 capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
276 "Firmware Device cannot accept a partial update and all components present on the FD shall be updated.";
277 }
278
279 if (fwParams.capabilities_during_update.bits.bit3)
280 {
281 capabilitiesDuringUpdate
282 ["Firmware Device Host Functionality during Firmware Update"] =
283 "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer";
284 }
285 else
286 {
287 capabilitiesDuringUpdate
288 ["Firmware Device Host Functionality during Firmware Update"] =
289 "Device will revert to previous component image upon failure, timeout or cancellation of the transfer";
290 }
291
292 if (fwParams.capabilities_during_update.bits.bit4)
293 {
294 capabilitiesDuringUpdate["Firmware Device Update Mode Restrictions"] =
295 "Firmware device unable to enter update mode if host OS environment is active.";
296 }
297 else
298 {
299 capabilitiesDuringUpdate
300 ["Firmware Device Update Mode Restrictions"] =
301 "No host OS environment restriction for update mode";
302 }
303
304 ordered_json data;
305 data["CapabilitiesDuringUpdate"] = capabilitiesDuringUpdate;
306 data["ComponentCount"] = static_cast<uint16_t>(fwParams.comp_count);
307 data["ActiveComponentImageSetVersionString"] =
308 pldm::utils::toString(activeCompImageSetVersion);
309 data["PendingComponentImageSetVersionString"] =
310 pldm::utils::toString(pendingCompImageSetVersion);
311
312 auto compParamPtr = compParameterTable.ptr;
313 auto compParamTableLen = compParameterTable.length;
314 pldm_component_parameter_entry compEntry{};
315 variable_field activeCompVerStr{};
316 variable_field pendingCompVerStr{};
317 ordered_json compDataEntries;
318
319 while (fwParams.comp_count-- && (compParamTableLen > 0))
320 {
321 ordered_json compData;
322 auto rc = decode_get_firmware_parameters_resp_comp_entry(
323 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
324 &pendingCompVerStr);
325 if (rc)
326 {
327 std::cerr
328 << "Decoding component parameter table entry failed, RC="
329 << rc << "\n";
330 return;
331 }
332
333 if (componentClassification.contains(compEntry.comp_classification))
334 {
335 compData["ComponentClassification"] =
336 componentClassification.at(compEntry.comp_classification);
337 }
338 else
339 {
340 compData["ComponentClassification"] =
341 static_cast<uint16_t>(compEntry.comp_classification);
342 }
343 compData["ComponentIdentifier"] =
344 static_cast<uint16_t>(compEntry.comp_identifier);
345 compData["ComponentClassificationIndex"] =
346 static_cast<uint8_t>(compEntry.comp_classification_index);
347 compData["ActiveComponentComparisonStamp"] =
348 static_cast<uint32_t>(compEntry.active_comp_comparison_stamp);
349
350 // ActiveComponentReleaseData
351 std::array<uint8_t, 8> noReleaseData{0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00};
353 if (std::equal(noReleaseData.begin(), noReleaseData.end(),
354 compEntry.active_comp_release_date))
355 {
356 compData["ActiveComponentReleaseDate"] = "";
357 }
358 else
359 {
360 std::string activeComponentReleaseDate(
361 reinterpret_cast<const char*>(
362 compEntry.active_comp_release_date),
363 sizeof(compEntry.active_comp_release_date));
364 compData["ActiveComponentReleaseDate"] =
365 activeComponentReleaseDate;
366 }
367
368 compData["PendingComponentComparisonStamp"] =
369 static_cast<uint32_t>(compEntry.pending_comp_comparison_stamp);
370
371 // PendingComponentReleaseData
372 if (std::equal(noReleaseData.begin(), noReleaseData.end(),
373 compEntry.pending_comp_release_date))
374 {
375 compData["PendingComponentReleaseDate"] = "";
376 }
377 else
378 {
379 std::string pendingComponentReleaseDate(
380 reinterpret_cast<const char*>(
381 compEntry.pending_comp_release_date),
382 sizeof(compEntry.pending_comp_release_date));
383 compData["PendingComponentReleaseDate"] =
384 pendingComponentReleaseDate;
385 }
386
387 // ComponentActivationMethods
388 ordered_json componentActivationMethods;
389 if (compEntry.comp_activation_methods.bits.bit0)
390 {
391 componentActivationMethods.push_back("Automatic");
392 }
393 else if (compEntry.comp_activation_methods.bits.bit1)
394 {
395 componentActivationMethods.push_back("Self-Contained");
396 }
397 else if (compEntry.comp_activation_methods.bits.bit2)
398 {
399 componentActivationMethods.push_back("Medium-specific reset");
400 }
401 else if (compEntry.comp_activation_methods.bits.bit3)
402 {
403 componentActivationMethods.push_back("System reboot");
404 }
405 else if (compEntry.comp_activation_methods.bits.bit4)
406 {
407 componentActivationMethods.push_back("DC power cycel");
408 }
409 else if (compEntry.comp_activation_methods.bits.bit5)
410 {
411 componentActivationMethods.push_back("AC power cycle");
412 }
413 compData["ComponentActivationMethods"] = componentActivationMethods;
414
415 // CapabilitiesDuringUpdate
416 ordered_json compCapabilitiesDuringUpdate;
417 if (compEntry.capabilities_during_update.bits.bit0)
418 {
419 compCapabilitiesDuringUpdate
420 ["Firmware Device apply state functionality"] =
421 "Firmware Device performs an auto-apply during transfer phase and apply step will be completed immediately.";
422 }
423 else
424 {
425 compCapabilitiesDuringUpdate
426 ["Firmware Device apply state functionality"] =
427 " 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.";
428 }
429 compData["CapabilitiesDuringUpdate"] = compCapabilitiesDuringUpdate;
430
431 compData["ActiveComponentVersionString"] =
432 pldm::utils::toString(activeCompVerStr);
433 compData["PendingComponentVersionString"] =
434 pldm::utils::toString(pendingCompVerStr);
435
436 compParamPtr += sizeof(pldm_component_parameter_entry) +
437 activeCompVerStr.length + pendingCompVerStr.length;
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400438 compParamTableLen -=
439 sizeof(pldm_component_parameter_entry) +
440 activeCompVerStr.length + pendingCompVerStr.length;
Tom Joseph6f2a2482021-10-27 18:28:16 +0530441 compDataEntries.push_back(compData);
442 }
443 data["ComponentParameterEntries"] = compDataEntries;
444
445 pldmtool::helper::DisplayInJson(data);
446 }
447};
448
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530449class QueryDeviceIdentifiers : public CommandInterface
450{
451 public:
452 ~QueryDeviceIdentifiers() = default;
453 QueryDeviceIdentifiers() = delete;
454 QueryDeviceIdentifiers(const QueryDeviceIdentifiers&) = delete;
455 QueryDeviceIdentifiers(QueryDeviceIdentifiers&&) = default;
456 QueryDeviceIdentifiers& operator=(const QueryDeviceIdentifiers&) = delete;
Pavithra Barithayaa7dbca52023-07-07 04:19:37 -0500457 QueryDeviceIdentifiers& operator=(QueryDeviceIdentifiers&&) = delete;
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530458
459 /**
460 * @brief Implementation of createRequestMsg for QueryDeviceIdentifiers
461 *
462 * @return std::pair<int, std::vector<uint8_t>>
463 */
464 std::pair<int, std::vector<uint8_t>> createRequestMsg() override;
465
466 /**
467 * @brief Implementation of parseResponseMsg for QueryDeviceIdentifiers
468 *
469 * @param[in] responsePtr
470 * @param[in] payloadLength
471 */
472 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override;
473 using CommandInterface::CommandInterface;
474
475 private:
476 /**
477 * @brief Method to update QueryDeviceIdentifiers json response in a user
478 * friendly format
479 *
480 * @param[in] descriptors - descriptor json response
481 * @param[in] descriptorType - descriptor type
482 * @param[in] descriptorVal - descriptor value
483 */
484 void updateDescriptor(
485 ordered_json& descriptors, const DescriptorType& descriptorType,
486 const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
487 descriptorVal);
488};
489
490void QueryDeviceIdentifiers::updateDescriptor(
491 ordered_json& descriptors, const DescriptorType& descriptorType,
492 const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
493 descriptorVal)
494{
495 std::ostringstream descDataStream;
496 DescriptorData descData;
497 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
498 {
499 descData = std::get<DescriptorData>(descriptorVal);
500 }
501 else
502 {
503 descData = std::get<VendorDefinedDescriptorData>(
504 std::get<VendorDefinedDescriptorInfo>(descriptorVal));
505 }
506 for (int byte : descData)
507 {
508 descDataStream << std::setfill('0') << std::setw(2) << std::hex << byte;
509 }
510
511 if (descriptorName.contains(descriptorType))
512 {
513 // Update the existing json response if entry is already present
514 for (auto& descriptor : descriptors)
515 {
516 if (descriptor["Type"] == descriptorName.at(descriptorType))
517 {
518 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
519 {
520 descriptor["Value"].emplace_back(descDataStream.str());
521 }
522 else
523 {
524 ordered_json vendorDefinedVal;
525 vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
526 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
527 descDataStream.str();
528 descriptor["Value"].emplace_back(vendorDefinedVal);
529 }
530 return;
531 }
532 }
533 // Entry is not present, add type and value to json response
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400534 ordered_json descriptor = ordered_json::object(
535 {{"Type", descriptorName.at(descriptorType)},
536 {"Value", ordered_json::array()}});
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530537 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
538 {
539 descriptor["Value"].emplace_back(descDataStream.str());
540 }
541 else
542 {
543 ordered_json vendorDefinedVal;
544 vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
545 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
546 descDataStream.str();
547 descriptor["Value"].emplace_back(vendorDefinedVal);
548 }
549 descriptors.emplace_back(descriptor);
550 }
551 else
552 {
553 std::cerr << "Unknown descriptor type, type=" << descriptorType << "\n";
554 }
555}
556std::pair<int, std::vector<uint8_t>> QueryDeviceIdentifiers::createRequestMsg()
557{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400558 std::vector<uint8_t> requestMsg(
559 sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
Pavithra Barithaya5c3f0d12025-01-30 14:05:49 +0530560 auto request = new (requestMsg.data()) pldm_msg;
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530561 auto rc = encode_query_device_identifiers_req(
562 instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
563 return {rc, requestMsg};
564}
565
566void QueryDeviceIdentifiers::parseResponseMsg(pldm_msg* responsePtr,
567 size_t payloadLength)
568{
569 uint8_t completionCode = PLDM_SUCCESS;
570 uint32_t deviceIdentifiersLen = 0;
571 uint8_t descriptorCount = 0;
572 uint8_t* descriptorPtr = nullptr;
573 uint8_t eid = getMCTPEID();
574 auto rc = decode_query_device_identifiers_resp(
575 responsePtr, payloadLength, &completionCode, &deviceIdentifiersLen,
576 &descriptorCount, &descriptorPtr);
577 if (rc)
578 {
579 std::cerr << "Decoding QueryDeviceIdentifiers response failed,EID="
580 << unsigned(eid) << ", RC=" << rc << "\n";
581 return;
582 }
583 if (completionCode)
584 {
585 std::cerr << "QueryDeviceIdentifiers response failed with error "
586 "completion code, EID="
587 << unsigned(eid) << ", CC=" << unsigned(completionCode)
588 << "\n";
589 return;
590 }
591 ordered_json data;
592 data["EID"] = eid;
593 ordered_json descriptors;
594 while (descriptorCount-- && (deviceIdentifiersLen > 0))
595 {
596 DescriptorType descriptorType = 0;
597 variable_field descriptorData{};
598
599 rc = decode_descriptor_type_length_value(
600 descriptorPtr, deviceIdentifiersLen, &descriptorType,
601 &descriptorData);
602 if (rc)
603 {
604 std::cerr << "Decoding descriptor type, length and value failed,"
605 << "EID=" << unsigned(eid) << ",RC=" << rc << "\n ";
606 return;
607 }
608
609 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
610 {
611 std::vector<uint8_t> descData(
612 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
613 updateDescriptor(descriptors, descriptorType, descData);
614 }
615 else
616 {
617 uint8_t descriptorTitleStrType = 0;
618 variable_field descriptorTitleStr{};
619 variable_field vendorDefinedDescriptorData{};
620
621 rc = decode_vendor_defined_descriptor_value(
622 descriptorData.ptr, descriptorData.length,
623 &descriptorTitleStrType, &descriptorTitleStr,
624 &vendorDefinedDescriptorData);
625 if (rc)
626 {
627 std::cerr << "Decoding Vendor-defined descriptor value"
628 << "failed EID=" << unsigned(eid) << ", RC=" << rc
629 << "\n ";
630 return;
631 }
632
633 auto vendorDescTitle = pldm::utils::toString(descriptorTitleStr);
634 std::vector<uint8_t> vendorDescData(
635 vendorDefinedDescriptorData.ptr,
636 vendorDefinedDescriptorData.ptr +
637 vendorDefinedDescriptorData.length);
638 updateDescriptor(descriptors, descriptorType,
639 std::make_tuple(vendorDescTitle, vendorDescData));
640 }
641 auto nextDescriptorOffset =
642 sizeof(pldm_descriptor_tlv().descriptor_type) +
643 sizeof(pldm_descriptor_tlv().descriptor_length) +
644 descriptorData.length;
645 descriptorPtr += nextDescriptorOffset;
646 deviceIdentifiersLen -= nextDescriptorOffset;
647 }
648 data["Descriptors"] = descriptors;
649 pldmtool::helper::DisplayInJson(data);
650}
651
rajeeranjan2bc3dd02025-03-25 15:22:24 +0530652class RequestUpdate : public CommandInterface
653{
654 public:
655 ~RequestUpdate() = default;
656 RequestUpdate() = delete;
657 RequestUpdate(const RequestUpdate&) = delete;
658 RequestUpdate(RequestUpdate&&) = delete;
659 RequestUpdate& operator=(const RequestUpdate&) = delete;
660 RequestUpdate& operator=(RequestUpdate&&) = delete;
661
662 explicit RequestUpdate(const char* type, const char* name, CLI::App* app) :
663 CommandInterface(type, name, app)
664 {
665 app->add_option(
666 "--max_transfer_size", maxTransferSize,
667 "Specifies the maximum size, in bytes, of the variable payload allowed to\n"
668 "be requested by the FD via the RequestFirmwareData command that is contained\n"
669 "within a PLDM message. This value shall be equal to or greater than firmware update\n"
670 "baseline transfer size.")
671 ->required();
672
673 app->add_option(
674 "--num_comps", numComps,
675 "Specifies the number of components that will be passed to the FD during the update.\n"
676 "The FD can use this value to compare against the number of PassComponentTable\n"
677 "commands received.")
678 ->required();
679
680 app->add_option(
681 "--max_transfer_reqs", maxTransferReqs,
682 "Specifies the number of outstanding RequestFirmwareData commands that can be\n"
683 "sent by the FD. The minimum required value is '1' which the UA shall support.\n"
684 "It is optional for the UA to support a value higher than '1' for this field.")
685 ->required();
686
687 app->add_option(
688 "--package_data_length", packageDataLength,
689 "This field shall be set to the value contained within\n"
690 "the FirmwareDevicePackageDataLength field that was provided in\n"
691 "the firmware package header. If no firmware package data was\n"
692 "provided in the firmware update package then this length field\n"
693 "shall be set to 0x0000.")
694 ->required();
695
696 app->add_option(
697 "--comp_img_ver_str_type", compImgVerStrType,
698 "The type of string used in the ComponentImageSetVersionString\n"
699 "field. Possible values\n"
700 "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
701 "OR {0,1,2,3,4,5}")
702 ->required()
703 ->check([](const std::string& value) -> std::string {
704 static const std::set<std::string> validStrings{
705 "UNKNOWN", "ASCII", "UTF_8",
706 "UTF_16", "UTF_16LE", "UTF_16BE"};
707
708 if (validStrings.contains(value))
709 {
710 return "";
711 }
712
713 try
714 {
715 int intValue = std::stoi(value);
716 if (intValue >= 0 && intValue <= 255)
717 {
718 return "";
719 }
720 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
721 }
722 catch (const std::exception&)
723 {
724 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
725 }
726 });
727
728 app->add_option(
729 "--comp_img_ver_str_len", compImgVerStrLen,
730 "The length, in bytes, of the ComponentImageSetVersionString.")
731 ->required();
732
733 app->add_option(
734 "--comp_img_set_ver_str", compImgSetVerStr,
735 "Component Image Set version information, up to 255 bytes.")
736 ->required();
737 }
738
739 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
740 {
741 variable_field compImgSetVerStrInfo{};
742 compImgSetVerStrInfo.ptr =
743 reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());
744 compImgSetVerStrInfo.length =
745 static_cast<uint8_t>(compImgSetVerStr.size());
746
747 std::vector<uint8_t> requestMsg(
748 sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) +
749 compImgSetVerStrInfo.length);
750
751 auto request = new (requestMsg.data()) pldm_msg;
752
753 auto rc = encode_request_update_req(
754 instanceId, maxTransferSize, numComps, maxTransferReqs,
755 packageDataLength, convertStringTypeToUInt8(compImgVerStrType),
756 compImgVerStrLen, &compImgSetVerStrInfo, request,
757 sizeof(struct pldm_request_update_req) +
758 compImgSetVerStrInfo.length);
759
760 return {rc, requestMsg};
761 }
762
763 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
764 {
765 uint8_t cc = 0;
766 uint16_t fdMetaDataLen = 0;
767 uint8_t fdWillSendPkgData = 0;
768
769 auto rc =
770 decode_request_update_resp(responsePtr, payloadLength, &cc,
771 &fdMetaDataLen, &fdWillSendPkgData);
772 if (rc)
773 {
774 std::cerr << "Response Message Error: "
775 << "rc=" << rc << ",cc=" << (int)cc << "\n";
776 return;
777 }
778
779 ordered_json data;
780 fillCompletionCode(cc, data, PLDM_FWUP);
781
782 if (cc == PLDM_SUCCESS)
783 {
784 data["FirmwareDeviceMetaDataLength"] = fdMetaDataLen;
785 data["FDWillSendGetPackageDataCommand"] =
786 std::format("0x{:02X}", fdWillSendPkgData);
787 }
788 pldmtool::helper::DisplayInJson(data);
789 }
790
791 private:
792 uint32_t maxTransferSize;
793 uint16_t numComps;
794 uint8_t maxTransferReqs;
795 uint16_t packageDataLength;
796 std::string compImgVerStrType;
797 uint8_t compImgVerStrLen;
798 std::string compImgSetVerStr;
799};
800
rajeeranjan6f67ca72025-04-08 00:21:56 +0530801class PassComponentTable : public CommandInterface
802{
803 public:
804 ~PassComponentTable() = default;
805 PassComponentTable() = delete;
806 PassComponentTable(const PassComponentTable&) = delete;
807 PassComponentTable(PassComponentTable&&) = delete;
808 PassComponentTable& operator=(const PassComponentTable&) = delete;
809 PassComponentTable& operator=(PassComponentTable&&) = delete;
810
811 explicit PassComponentTable(const char* type, const char* name,
812 CLI::App* app) :
813 CommandInterface(type, name, app)
814 {
815 app->add_option(
816 "--transfer_flag", transferFlag,
817 "The transfer flag that indicates what part of the Component Table\n"
818 "this request represents.\nPossible values\n"
819 "{Start = 0x1, Middle = 0x2, End = 0x4, StartAndEnd = 0x5}")
820 ->required()
821 ->transform(
822 CLI::CheckedTransformer(transferRespFlag, CLI::ignore_case));
823
824 app->add_option(
825 "--comp_classification", compClassification,
826 "Vendor specific component classification information.\n"
827 "Special values: 0x0000, 0xFFFF = reserved")
828 ->required();
829
830 app->add_option("--comp_identifier", compIdentifier,
831 "FD vendor selected unique value "
832 "to distinguish between component images")
833 ->required();
834
835 app->add_option("--comp_classification_idx", compClassificationIdx,
836 "The component classification index which was obtained "
837 "from the GetFirmwareParameters command to indicate \n"
838 "which firmware component the information contained "
839 "within this command is applicable for")
840 ->required();
841
842 app->add_option(
843 "--comp_compare_stamp", compCompareStamp,
844 "FD vendor selected value to use as a comparison value in determining if a firmware\n"
845 "component is down-level or up-level. For the same component identifier,\n"
846 "the greater of two component comparison stamps is considered up-level compared\n"
847 "to the other when performing an unsigned integer comparison")
848 ->required();
849
850 app->add_option(
851 "--comp_ver_str_type", compVerStrType,
852 "The type of strings used in the ComponentVersionString\n"
853 "Possible values\n"
854 "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
855 "OR {0,1,2,3,4,5}")
856 ->required()
857 ->check([](const std::string& value) -> std::string {
858 static const std::set<std::string> validStrings{
859 "UNKNOWN", "ASCII", "UTF_8",
860 "UTF_16", "UTF_16LE", "UTF_16BE"};
861
862 if (validStrings.contains(value))
863 {
864 return "";
865 }
866
867 try
868 {
869 int intValue = std::stoi(value);
870 if (intValue >= 0 && intValue <= 255)
871 {
872 return "";
873 }
874 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
875 }
876 catch (const std::exception&)
877 {
878 return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
879 }
880 });
881
882 app->add_option("--comp_ver_str_len", compVerStrLen,
883 "The length, in bytes, of the ComponentVersionString")
884 ->required();
885
886 app->add_option(
887 "--comp_ver_str", compVerStr,
888 "Firmware component version information up to 255 bytes. \n"
889 "Contains a variable type string describing the component version")
890 ->required();
891 }
892
893 std::pair<int, std::vector<uint8_t>> createRequestMsg() override
894 {
895 variable_field compVerStrInfo{};
896 std::vector<uint8_t> compVerStrData(compVerStr.begin(),
897 compVerStr.end());
898 compVerStrInfo.ptr = compVerStrData.data();
899 compVerStrInfo.length = static_cast<uint8_t>(compVerStrData.size());
900
901 std::vector<uint8_t> requestMsg(
902 sizeof(pldm_msg_hdr) +
903 sizeof(struct pldm_pass_component_table_req) +
904 compVerStrInfo.length);
905
906 auto request = new (requestMsg.data()) pldm_msg;
907
908 auto rc = encode_pass_component_table_req(
909 instanceId, transferFlag, compClassification, compIdentifier,
910 compClassificationIdx, compCompareStamp,
911 convertStringTypeToUInt8(compVerStrType), compVerStrInfo.length,
912 &compVerStrInfo, request,
913 sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
914
915 return {rc, requestMsg};
916 }
917
918 void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
919 {
920 uint8_t cc = 0;
921 uint8_t compResponse = 0;
922 uint8_t compResponseCode = 0;
923
924 auto rc = decode_pass_component_table_resp(
925 responsePtr, payloadLength, &cc, &compResponse, &compResponseCode);
926
927 if (rc != PLDM_SUCCESS)
928 {
929 std::cerr << "Response Message Error: "
930 << "rc=" << rc << ",cc=" << (int)cc << "\n";
931 return;
932 }
933
934 ordered_json data;
935 fillCompletionCode(cc, data, PLDM_FWUP);
936
937 if (cc == PLDM_SUCCESS)
938 {
939 data["ComponentResponse"] =
940 compResponse ? "Component may be updateable"
941 : "Component can be updated";
942
943 data["ComponentResponseCode"] =
944 std::format("0x{:02X}", compResponseCode);
945 }
946
947 pldmtool::helper::DisplayInJson(data);
948 }
949
950 private:
951 uint8_t transferFlag;
952 uint16_t compClassification;
953 uint16_t compIdentifier;
954 uint8_t compClassificationIdx;
955 uint32_t compCompareStamp;
956 std::string compVerStrType;
957 uint8_t compVerStrLen;
958 std::string compVerStr;
959};
960
Tom Josepheea835a2021-10-25 19:30:32 +0530961void registerCommand(CLI::App& app)
962{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400963 auto fwUpdate =
964 app.add_subcommand("fw_update", "firmware update type commands");
Tom Josepheea835a2021-10-25 19:30:32 +0530965 fwUpdate->require_subcommand(1);
966
967 auto getStatus = fwUpdate->add_subcommand("GetStatus", "Status of the FD");
968 commands.push_back(
969 std::make_unique<GetStatus>("fw_update", "GetStatus", getStatus));
Tom Joseph6f2a2482021-10-27 18:28:16 +0530970
971 auto getFwParams = fwUpdate->add_subcommand(
972 "GetFwParams", "To get the component details of the FD");
973 commands.push_back(
974 std::make_unique<GetFwParams>("fw_update", "GetFwParams", getFwParams));
Chinmay Shripad Hegde526461a2023-01-11 13:04:02 +0530975
976 auto queryDeviceIdentifiers = fwUpdate->add_subcommand(
977 "QueryDeviceIdentifiers", "To query device identifiers of the FD");
978 commands.push_back(std::make_unique<QueryDeviceIdentifiers>(
979 "fw_update", "QueryDeviceIdentifiers", queryDeviceIdentifiers));
rajeeranjan2bc3dd02025-03-25 15:22:24 +0530980
981 auto requestUpdate = fwUpdate->add_subcommand(
982 "RequestUpdate", "To initiate a firmware update");
983 commands.push_back(std::make_unique<RequestUpdate>(
984 "fw_update", "RequestUpdate", requestUpdate));
rajeeranjan6f67ca72025-04-08 00:21:56 +0530985
986 auto passCompTable = fwUpdate->add_subcommand("PassComponentTable",
987 "To pass component table");
988 commands.push_back(std::make_unique<PassComponentTable>(
989 "fw_update", "PassComponentTable", passCompTable));
Tom Josepheea835a2021-10-25 19:30:32 +0530990}
991
992} // namespace fw_update
993
Patrick Williams6da4f912023-05-10 07:50:53 -0500994} // namespace pldmtool