xref: /openbmc/pldm/pldmtool/pldm_base_cmd.cpp (revision 0352886b2f4c3e61a07b8d839d011e5f358ed201)
1 #include "pldm_base_cmd.hpp"
2 
3 #include "pldm_cmd_helper.hpp"
4 
5 #include <libpldm/utils.h>
6 
7 #ifdef OEM_IBM
8 #include <libpldm/oem/ibm/file_io.h>
9 #include <libpldm/oem/ibm/host.h>
10 #endif
11 
12 #include <string>
13 
14 namespace pldmtool
15 {
16 
17 namespace base
18 {
19 
20 namespace
21 {
22 
23 using namespace pldmtool::helper;
24 
25 std::vector<std::unique_ptr<CommandInterface>> commands;
26 const std::map<const char*, pldm_supported_types> pldmTypes{
27     {"base", PLDM_BASE},   {"platform", PLDM_PLATFORM},    {"bios", PLDM_BIOS},
28     {"fru", PLDM_FRU},     {"firmware update", PLDM_FWUP},
29 #ifdef OEM_IBM
30     {"oem-ibm", PLDM_OEM},
31 #endif
32 };
33 
34 const std::map<const char*, pldm_supported_commands> pldmBaseCmds{
35     {"SetTID", PLDM_SET_TID},
36     {"GetTID", PLDM_GET_TID},
37     {"GetPLDMVersion", PLDM_GET_PLDM_VERSION},
38     {"GetPLDMTypes", PLDM_GET_PLDM_TYPES},
39     {"GetPLDMCommands", PLDM_GET_PLDM_COMMANDS},
40     {"SelectPLDMVersion", PLDM_SELECT_PLDM_VERSION},
41     {"NegotiateTransferParameters", PLDM_NEGOTIATE_TRANSFER_PARAMETERS},
42     {"MultipartSend", PLDM_MULTIPART_SEND},
43     {"MultipartReceive", PLDM_MULTIPART_RECEIVE},
44     {"GetMultipartTransferSupport", PLDM_GET_MULTIPART_TRANSFER_SUPPORT}};
45 
46 const std::map<const char*, pldm_bios_commands> pldmBiosCmds{
47     {"GetBIOSTable", PLDM_GET_BIOS_TABLE},
48     {"SetBIOSTable", PLDM_SET_BIOS_TABLE},
49     {"SetBIOSAttributeCurrentValue", PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE},
50     {"GetBIOSAttributeCurrentValueByHandle",
51      PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE},
52     {"GetDateTime", PLDM_GET_DATE_TIME},
53     {"SetDateTime", PLDM_SET_DATE_TIME}};
54 
55 const std::map<const char*, pldm_platform_commands> pldmPlatformCmds{
56     {"GetTerminusUID", PLDM_GET_TERMINUS_UID},
57     {"SetEventReceiver", PLDM_SET_EVENT_RECEIVER},
58     {"GetEventReceiver", PLDM_GET_EVENT_RECEIVER},
59     {"PlatformEventMessage", PLDM_PLATFORM_EVENT_MESSAGE},
60     {"PollForPlatformEventMessage", PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE},
61     {"EventMessageSupported", PLDM_EVENT_MESSAGE_SUPPORTED},
62     {"EventMessageBufferSize", PLDM_EVENT_MESSAGE_BUFFER_SIZE},
63     {"SetNumericSensorEnable", PLDM_SET_NUMERIC_SENSOR_ENABLE},
64     {"GetSensorReading", PLDM_GET_SENSOR_READING},
65     {"GetSensorThresholds", PLDM_GET_SENSOR_THRESHOLDS},
66     {"SetSensorThresholds", PLDM_SET_SENSOR_THRESHOLDS},
67     {"RestoreSensorThresholds", PLDM_RESTORE_SENSOR_THRESHOLDS},
68     {"GetSensorHysteresis", PLDM_GET_SENSOR_HYSTERESIS},
69     {"SetSensorHysteresis", PLDM_SET_SENSOR_HYSTERESIS},
70     {"InitNumericSensor", PLDM_INIT_NUMERIC_SENSOR},
71     {"SetStateSensorEnables", PLDM_SET_STATE_SENSOR_ENABLES},
72     {"GetStateSensorReadings", PLDM_GET_STATE_SENSOR_READINGS},
73     {"InitStateSensor", PLDM_INIT_STATE_SENSOR},
74     {"SetNumericEffecterEnable", PLDM_SET_NUMERIC_EFFECTER_ENABLE},
75     {"SetNumericEffecterValue", PLDM_SET_NUMERIC_EFFECTER_VALUE},
76     {"GetNumericEffecterValue", PLDM_GET_NUMERIC_EFFECTER_VALUE},
77     {"SetStateEffecterEnables", PLDM_SET_STATE_EFFECTER_ENABLES},
78     {"SetStateEffecterStates", PLDM_SET_STATE_EFFECTER_STATES},
79     {"GetStateEffecterStates", PLDM_GET_STATE_EFFECTER_STATES},
80     {"GetPLDMEventLogInfo", PLDM_GET_PLDM_EVENT_LOG_INFO},
81     {"EnablePLDMEventLogging", PLDM_ENABLE_PLDM_EVENT_LOGGING},
82     {"ClearPLDMEventLog", PLDM_CLEAR_PLDM_EVENT_LOG},
83     {"GetPLDMEventLogTimestamp", PLDM_GET_PLDM_EVENT_LOG_TIMESTAMP},
84     {"SetPLDMEventLogTimestamp", PLDM_SET_PLDM_EVENT_LOG_TIMESTAMP},
85     {"ReadPLDMEventLog", PLDM_READ_PLDM_EVENT_LOG},
86     {"GetPLDMEventLogPolicyInfo", PLDM_GET_PLDM_EVENT_LOG_POLICY_INFO},
87     {"SetPLDMEventLogPolicy", PLDM_SET_PLDM_EVENT_LOG_POLICY},
88     {"FindPLDMEventLogEntry", PLDM_FIND_PLDM_EVENT_LOG_ENTRY},
89     {"GetPDRRepositoryInfo", PLDM_GET_PDR_REPOSITORY_INFO},
90     {"GetPDR", PLDM_GET_PDR},
91     {"FindPDR", PLDM_FIND_PDR},
92     {"RunInitAgent", PLDM_RUN_INIT_AGENT},
93     {"GetPDRRepositorySignature", PLDM_GET_PDR_REPOSITORY_SIGNATURE}};
94 
95 const std::map<const char*, pldm_fru_commands> pldmFruCmds{
96     {"GetFRURecordTableMetadata", PLDM_GET_FRU_RECORD_TABLE_METADATA},
97     {"GetFRURecordTable", PLDM_GET_FRU_RECORD_TABLE},
98     {"GetFRURecordByOption", PLDM_GET_FRU_RECORD_BY_OPTION}};
99 
100 #ifdef OEM_IBM
101 const std::map<const char*, pldm_host_commands> pldmIBMHostCmds{
102     {"GetAlertStatus", PLDM_HOST_GET_ALERT_STATUS}};
103 
104 const std::map<const char*, pldm_fileio_commands> pldmIBMFileIOCmds{
105     {"GetFileTable", PLDM_GET_FILE_TABLE},
106     {"ReadFile", PLDM_READ_FILE},
107     {"WriteFile", PLDM_WRITE_FILE},
108     {"ReadFileInToMemory", PLDM_READ_FILE_INTO_MEMORY},
109     {"WriteFileFromMemory", PLDM_WRITE_FILE_FROM_MEMORY},
110     {"ReadFileByTypeIntoMemory", PLDM_READ_FILE_BY_TYPE_INTO_MEMORY},
111     {"WriteFileByTypeFromMemory", PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY},
112     {"NewFileAvailable", PLDM_NEW_FILE_AVAILABLE},
113     {"ReadFileByType", PLDM_READ_FILE_BY_TYPE},
114     {"WriteFileByType", PLDM_WRITE_FILE_BY_TYPE},
115     {"FileAck", PLDM_FILE_ACK}};
116 #endif
117 
118 } // namespace
119 
120 class GetPLDMTypes : public CommandInterface
121 {
122   public:
123     ~GetPLDMTypes() = default;
124     GetPLDMTypes() = delete;
125     GetPLDMTypes(const GetPLDMTypes&) = delete;
126     GetPLDMTypes(GetPLDMTypes&&) = default;
127     GetPLDMTypes& operator=(const GetPLDMTypes&) = delete;
128     GetPLDMTypes& operator=(GetPLDMTypes&&) = delete;
129 
130     using CommandInterface::CommandInterface;
131 
createRequestMsg()132     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
133     {
134         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
135         auto request = new (requestMsg.data()) pldm_msg;
136         auto rc = encode_get_types_req(instanceId, request);
137         return {rc, requestMsg};
138     }
139 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)140     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
141     {
142         uint8_t cc = 0;
143         std::vector<bitfield8_t> types(8);
144         auto rc = decode_get_types_resp(responsePtr, payloadLength, &cc,
145                                         types.data());
146         if (rc != PLDM_SUCCESS)
147         {
148             std::cerr << "Response Message Error: "
149                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
150             return;
151         }
152 
153         ordered_json data;
154         fillCompletionCode(cc, data, PLDM_BASE);
155         if (cc == PLDM_SUCCESS)
156         {
157             printPLDMTypes(types, data);
158         }
159 
160         pldmtool::helper::DisplayInJson(data);
161     }
162 
163   private:
printPLDMTypes(std::vector<bitfield8_t> & types,ordered_json & data)164     void printPLDMTypes(std::vector<bitfield8_t>& types, ordered_json& data)
165     {
166         ordered_json jPldmTypes;
167         ordered_json jarray;
168         for (int i = 0; i < PLDM_MAX_TYPES; i++)
169         {
170             bitfield8_t b = types[i / 8];
171             if (b.byte & (1 << i % 8))
172             {
173                 auto it = std::find_if(
174                     pldmTypes.begin(), pldmTypes.end(),
175                     [i](const auto& typePair) { return typePair.second == i; });
176                 if (it != pldmTypes.end())
177                 {
178                     jarray["PLDM Type"] = it->first;
179                     jarray["PLDM Type Code"] = i;
180                     jPldmTypes.emplace_back(jarray);
181                 }
182             }
183         }
184         data["PLDMTypes"] = jPldmTypes;
185     }
186 };
187 
188 class GetPLDMVersion : public CommandInterface
189 {
190   public:
191     ~GetPLDMVersion() = default;
192     GetPLDMVersion() = delete;
193     GetPLDMVersion(const GetPLDMVersion&) = delete;
194     GetPLDMVersion(GetPLDMVersion&&) = default;
195     GetPLDMVersion& operator=(const GetPLDMVersion&) = delete;
196     GetPLDMVersion& operator=(GetPLDMVersion&&) = delete;
197 
GetPLDMVersion(const char * type,const char * name,CLI::App * app)198     explicit GetPLDMVersion(const char* type, const char* name, CLI::App* app) :
199         CommandInterface(type, name, app)
200     {
201         app->add_option("-t,--type", pldmType, "pldm supported type")
202             ->required()
203             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
204     }
createRequestMsg()205     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
206     {
207         std::vector<uint8_t> requestMsg(
208             sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES);
209         auto request = new (requestMsg.data()) pldm_msg;
210 
211         auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
212                                          pldmType, request);
213         return {rc, requestMsg};
214     }
215 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)216     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
217     {
218         uint8_t cc = 0, transferFlag = 0;
219         uint32_t transferHandle = 0;
220         ver32_t version;
221         auto rc =
222             decode_get_version_resp(responsePtr, payloadLength, &cc,
223                                     &transferHandle, &transferFlag, &version);
224         if (rc != PLDM_SUCCESS)
225         {
226             std::cerr << "Response Message Error: "
227                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
228             return;
229         }
230         ordered_json data;
231         fillCompletionCode(cc, data, PLDM_BASE);
232         if (cc == PLDM_SUCCESS)
233         {
234             char buffer[16] = {0};
235             ver2str(&version, buffer, sizeof(buffer));
236             auto it = std::find_if(pldmTypes.begin(), pldmTypes.end(),
237                                    [&](const auto& typePair) {
238                                        return typePair.second == pldmType;
239                                    });
240 
241             if (it != pldmTypes.end())
242             {
243                 data["Response"] = buffer;
244             }
245         }
246 
247         pldmtool::helper::DisplayInJson(data);
248     }
249 
250   private:
251     pldm_supported_types pldmType;
252 };
253 
254 class GetTID : public CommandInterface
255 {
256   public:
257     ~GetTID() = default;
258     GetTID() = delete;
259     GetTID(const GetTID&) = delete;
260     GetTID(GetTID&&) = default;
261     GetTID& operator=(const GetTID&) = delete;
262     GetTID& operator=(GetTID&&) = delete;
263 
264     using CommandInterface::CommandInterface;
265 
createRequestMsg()266     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
267     {
268         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
269         auto request = new (requestMsg.data()) pldm_msg;
270         auto rc = encode_get_tid_req(instanceId, request);
271         return {rc, requestMsg};
272     }
273 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)274     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
275     {
276         uint8_t cc = 0;
277         uint8_t tid = 0;
278         std::vector<bitfield8_t> types(8);
279         auto rc = decode_get_tid_resp(responsePtr, payloadLength, &cc, &tid);
280         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
281         {
282             std::cerr << "Response Message Error: "
283                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
284             return;
285         }
286         ordered_json data;
287         data["Response"] = static_cast<uint32_t>(tid);
288         pldmtool::helper::DisplayInJson(data);
289     }
290 };
291 
292 class GetPLDMCommands : public CommandInterface
293 {
294   public:
295     ~GetPLDMCommands() = default;
296     GetPLDMCommands() = delete;
297     GetPLDMCommands(const GetPLDMCommands&) = delete;
298     GetPLDMCommands(GetPLDMCommands&&) = default;
299     GetPLDMCommands& operator=(const GetPLDMCommands&) = delete;
300     GetPLDMCommands& operator=(GetPLDMCommands&&) = delete;
301 
GetPLDMCommands(const char * type,const char * name,CLI::App * app)302     explicit GetPLDMCommands(const char* type, const char* name,
303                              CLI::App* app) : CommandInterface(type, name, app)
304     {
305         app->add_option("-t,--type", pldmType, "pldm supported type")
306             ->required()
307             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
308         app->add_option(
309             "-d,--data", inputVersion,
310             "Set PLDM type version. Which is got from GetPLDMVersion\n"
311             "eg: version 1.1.0 then data will be `0x00 0xF0 0xF1 0xF1`\n"
312             "(format: alpha update minor major)");
313     }
314 
createRequestMsg()315     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
316     {
317         std::vector<uint8_t> requestMsg(
318             sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
319         auto request = new (requestMsg.data()) pldm_msg;
320         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
321         if (inputVersion.size() != 0)
322         {
323             if (inputVersion.size() != 4)
324             {
325                 std::cerr << "Invalid version format. "
326                           << "\n";
327             }
328             else
329             {
330                 version.major = inputVersion[3];
331                 version.minor = inputVersion[2];
332                 version.update = inputVersion[1];
333                 version.alpha = inputVersion[0];
334             }
335         }
336         auto rc =
337             encode_get_commands_req(instanceId, pldmType, version, request);
338         return {rc, requestMsg};
339     }
340 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)341     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
342     {
343         uint8_t cc = 0;
344         std::vector<bitfield8_t> cmdTypes(32);
345         auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
346                                            cmdTypes.data());
347         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
348         {
349             std::cerr << "Response Message Error: "
350                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
351             return;
352         }
353         printPldmCommands(cmdTypes, pldmType);
354     }
355 
356   private:
357     pldm_supported_types pldmType;
358     std::vector<uint8_t> inputVersion;
359 
360     template <typename CommandMap>
printCommand(CommandMap & commandMap,int i,ordered_json & jarray)361     void printCommand(CommandMap& commandMap, int i, ordered_json& jarray)
362     {
363         auto it = std::find_if(
364             commandMap.begin(), commandMap.end(),
365             [i](const auto& typePair) { return typePair.second == i; });
366         if (it != commandMap.end())
367         {
368             jarray["PLDM Command Code"] = i;
369             jarray["PLDM Command"] = it->first;
370         }
371     }
372 
printPldmCommands(std::vector<bitfield8_t> & cmdTypes,pldm_supported_types pldmType)373     void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
374                            pldm_supported_types pldmType)
375     {
376         ordered_json output;
377         for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
378         {
379             ordered_json cmdinfo;
380             bitfield8_t b = cmdTypes[i / 8];
381             if (b.byte & (1 << i % 8))
382             {
383                 switch (pldmType)
384                 {
385                     case PLDM_BASE:
386                         printCommand(pldmBaseCmds, i, cmdinfo);
387                         break;
388                     case PLDM_PLATFORM:
389                         printCommand(pldmPlatformCmds, i, cmdinfo);
390                         break;
391                     case PLDM_BIOS:
392                         printCommand(pldmBiosCmds, i, cmdinfo);
393                         break;
394                     case PLDM_FRU:
395                         printCommand(pldmFruCmds, i, cmdinfo);
396                         break;
397                     case PLDM_OEM:
398 #ifdef OEM_IBM
399                         printCommand(pldmIBMHostCmds, i, cmdinfo);
400                         printCommand(pldmIBMFileIOCmds, i, cmdinfo);
401 #endif
402                         break;
403                     default:
404                         break;
405                 }
406                 output.emplace_back(cmdinfo);
407             }
408         }
409         pldmtool::helper::DisplayInJson(output);
410     }
411 };
412 
413 class SetTID : public CommandInterface
414 {
415   public:
416     ~SetTID() = default;
417     SetTID() = delete;
418     SetTID(const SetTID&) = delete;
419     SetTID(SetTID&&) = default;
420     SetTID& operator=(const SetTID&) = delete;
421     SetTID& operator=(SetTID&&) = delete;
422 
SetTID(const char * type,const char * name,CLI::App * app)423     explicit SetTID(const char* type, const char* name, CLI::App* app) :
424         CommandInterface(type, name, app)
425     {
426         app->add_option("-t,--tid", tid,
427                         "The TID to be set.\n"
428                         "Special value: 0x00, 0xFF = reserved. \n")
429             ->required();
430     }
createRequestMsg()431     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
432     {
433         std::vector<uint8_t> requestMsg(
434             sizeof(pldm_msg_hdr) + PLDM_SET_TID_REQ_BYTES);
435         auto request = new (requestMsg.data()) pldm_msg;
436         auto rc = encode_set_tid_req(instanceId, tid, request);
437         if (rc != PLDM_SUCCESS)
438         {
439             std::cerr << "Failed to encode_set_tid_req, rc = " << rc
440                       << std::endl;
441         }
442         return {rc, requestMsg};
443     }
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)444     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
445     {
446         uint8_t completionCode = pldm_completion_codes::PLDM_SUCCESS;
447         if (payloadLength != PLDM_SET_TID_RESP_BYTES)
448         {
449             completionCode = pldm_completion_codes::PLDM_ERROR_INVALID_LENGTH;
450         }
451         else
452         {
453             completionCode = responsePtr->payload[0];
454         }
455         ordered_json data;
456         data["completionCode"] = completionCode;
457         pldmtool::helper::DisplayInJson(data);
458     }
459 
460   private:
461     uint8_t tid;
462 };
463 
registerCommand(CLI::App & app)464 void registerCommand(CLI::App& app)
465 {
466     auto base = app.add_subcommand("base", "base type command");
467     base->require_subcommand(1);
468 
469     auto getPLDMTypes =
470         base->add_subcommand("GetPLDMTypes", "get pldm supported types");
471     commands.push_back(
472         std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
473 
474     auto getPLDMVersion =
475         base->add_subcommand("GetPLDMVersion", "get version of a certain type");
476     commands.push_back(std::make_unique<GetPLDMVersion>(
477         "base", "GetPLDMVersion", getPLDMVersion));
478 
479     auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
480     commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
481 
482     auto getPLDMCommands = base->add_subcommand(
483         "GetPLDMCommands", "get supported commands of pldm type");
484     commands.push_back(std::make_unique<GetPLDMCommands>(
485         "base", "GetPLDMCommands", getPLDMCommands));
486 
487     auto setTID = base->add_subcommand(
488         "SetTID", "set the Terminus ID (TID) for a PLDM Terminus.");
489     commands.push_back(std::make_unique<SetTID>("base", "SetTID", setTID));
490 }
491 
492 } // namespace base
493 } // namespace pldmtool
494