pldmtool: Add PassComponentTable command support
Add support for PLDM PassComponentTable command defined in the
PLDM Firmware Update specification.
Test Results:
```
./pldmtool fw_update PassComponentTable --transfer_flag START --comp_classification 0x0A --comp_identifier 65280 --comp_classification_idx 0 --comp_compare_stamp 1 --comp_ver_str_type ASCII --comp_ver_str_len 4 --comp_ver_str ver1 -m 13
{
"CompletionCode": "SUCCESS",
"ComponentResponse": "Component may be updateable",
"ComponentResponseCode": "0x02"
}
```
Change-Id: Id5285267d884ca27788a1eae13397bf38eb45f12
Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
diff --git a/pldmtool/pldm_fw_update_cmd.cpp b/pldmtool/pldm_fw_update_cmd.cpp
index 4c740d5..d550fa6 100644
--- a/pldmtool/pldm_fw_update_cmd.cpp
+++ b/pldmtool/pldm_fw_update_cmd.cpp
@@ -74,6 +74,13 @@
{PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER, "ACPI Product Identifier"},
{PLDM_FWUP_VENDOR_DEFINED, "Vendor Defined"}};
+const std::map<std::string, transfer_resp_flag> transferRespFlag{
+ {"START", PLDM_START},
+ {"MIDDLE", PLDM_MIDDLE},
+ {"END", PLDM_END},
+ {"STARTANDEND", PLDM_START_AND_END},
+};
+
/*
* Convert PLDM Firmware String Type to uint8_t
*
@@ -791,6 +798,166 @@
std::string compImgSetVerStr;
};
+class PassComponentTable : public CommandInterface
+{
+ public:
+ ~PassComponentTable() = default;
+ PassComponentTable() = delete;
+ PassComponentTable(const PassComponentTable&) = delete;
+ PassComponentTable(PassComponentTable&&) = delete;
+ PassComponentTable& operator=(const PassComponentTable&) = delete;
+ PassComponentTable& operator=(PassComponentTable&&) = delete;
+
+ explicit PassComponentTable(const char* type, const char* name,
+ CLI::App* app) :
+ CommandInterface(type, name, app)
+ {
+ app->add_option(
+ "--transfer_flag", transferFlag,
+ "The transfer flag that indicates what part of the Component Table\n"
+ "this request represents.\nPossible values\n"
+ "{Start = 0x1, Middle = 0x2, End = 0x4, StartAndEnd = 0x5}")
+ ->required()
+ ->transform(
+ CLI::CheckedTransformer(transferRespFlag, CLI::ignore_case));
+
+ app->add_option(
+ "--comp_classification", compClassification,
+ "Vendor specific component classification information.\n"
+ "Special values: 0x0000, 0xFFFF = reserved")
+ ->required();
+
+ app->add_option("--comp_identifier", compIdentifier,
+ "FD vendor selected unique value "
+ "to distinguish between component images")
+ ->required();
+
+ app->add_option("--comp_classification_idx", compClassificationIdx,
+ "The component classification index which was obtained "
+ "from the GetFirmwareParameters command to indicate \n"
+ "which firmware component the information contained "
+ "within this command is applicable for")
+ ->required();
+
+ app->add_option(
+ "--comp_compare_stamp", compCompareStamp,
+ "FD vendor selected value to use as a comparison value in determining if a firmware\n"
+ "component is down-level or up-level. For the same component identifier,\n"
+ "the greater of two component comparison stamps is considered up-level compared\n"
+ "to the other when performing an unsigned integer comparison")
+ ->required();
+
+ app->add_option(
+ "--comp_ver_str_type", compVerStrType,
+ "The type of strings used in the ComponentVersionString\n"
+ "Possible values\n"
+ "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
+ "OR {0,1,2,3,4,5}")
+ ->required()
+ ->check([](const std::string& value) -> std::string {
+ static const std::set<std::string> validStrings{
+ "UNKNOWN", "ASCII", "UTF_8",
+ "UTF_16", "UTF_16LE", "UTF_16BE"};
+
+ if (validStrings.contains(value))
+ {
+ return "";
+ }
+
+ try
+ {
+ int intValue = std::stoi(value);
+ if (intValue >= 0 && intValue <= 255)
+ {
+ return "";
+ }
+ return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
+ }
+ catch (const std::exception&)
+ {
+ return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
+ }
+ });
+
+ app->add_option("--comp_ver_str_len", compVerStrLen,
+ "The length, in bytes, of the ComponentVersionString")
+ ->required();
+
+ app->add_option(
+ "--comp_ver_str", compVerStr,
+ "Firmware component version information up to 255 bytes. \n"
+ "Contains a variable type string describing the component version")
+ ->required();
+ }
+
+ std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+ {
+ variable_field compVerStrInfo{};
+ std::vector<uint8_t> compVerStrData(compVerStr.begin(),
+ compVerStr.end());
+ compVerStrInfo.ptr = compVerStrData.data();
+ compVerStrInfo.length = static_cast<uint8_t>(compVerStrData.size());
+
+ std::vector<uint8_t> requestMsg(
+ sizeof(pldm_msg_hdr) +
+ sizeof(struct pldm_pass_component_table_req) +
+ compVerStrInfo.length);
+
+ auto request = new (requestMsg.data()) pldm_msg;
+
+ auto rc = encode_pass_component_table_req(
+ instanceId, transferFlag, compClassification, compIdentifier,
+ compClassificationIdx, compCompareStamp,
+ convertStringTypeToUInt8(compVerStrType), compVerStrInfo.length,
+ &compVerStrInfo, request,
+ sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
+
+ return {rc, requestMsg};
+ }
+
+ void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+ {
+ uint8_t cc = 0;
+ uint8_t compResponse = 0;
+ uint8_t compResponseCode = 0;
+
+ auto rc = decode_pass_component_table_resp(
+ responsePtr, payloadLength, &cc, &compResponse, &compResponseCode);
+
+ if (rc != PLDM_SUCCESS)
+ {
+ std::cerr << "Response Message Error: "
+ << "rc=" << rc << ",cc=" << (int)cc << "\n";
+ return;
+ }
+
+ ordered_json data;
+ fillCompletionCode(cc, data, PLDM_FWUP);
+
+ if (cc == PLDM_SUCCESS)
+ {
+ data["ComponentResponse"] =
+ compResponse ? "Component may be updateable"
+ : "Component can be updated";
+
+ data["ComponentResponseCode"] =
+ std::format("0x{:02X}", compResponseCode);
+ }
+
+ pldmtool::helper::DisplayInJson(data);
+ }
+
+ private:
+ uint8_t transferFlag;
+ uint16_t compClassification;
+ uint16_t compIdentifier;
+ uint8_t compClassificationIdx;
+ uint32_t compCompareStamp;
+ std::string compVerStrType;
+ uint8_t compVerStrLen;
+ std::string compVerStr;
+};
+
void registerCommand(CLI::App& app)
{
auto fwUpdate =
@@ -815,6 +982,11 @@
"RequestUpdate", "To initiate a firmware update");
commands.push_back(std::make_unique<RequestUpdate>(
"fw_update", "RequestUpdate", requestUpdate));
+
+ auto passCompTable = fwUpdate->add_subcommand("PassComponentTable",
+ "To pass component table");
+ commands.push_back(std::make_unique<PassComponentTable>(
+ "fw_update", "PassComponentTable", passCompTable));
}
} // namespace fw_update