xref: /openbmc/pldm/pldmtool/pldm_base_cmd.cpp (revision a34a64bb)
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},
28     {"bios", PLDM_BIOS},   {"fru", PLDM_FRU},
29 #ifdef OEM_IBM
30     {"oem-ibm", PLDM_OEM},
31 #endif
32 };
33 
34 const std::map<const char*, pldm_supported_commands> pldmBaseCmds{
35     {"GetTID", PLDM_GET_TID},
36     {"GetPLDMVersion", PLDM_GET_PLDM_VERSION},
37     {"GetPLDMTypes", PLDM_GET_PLDM_TYPES},
38     {"GetPLDMCommands", PLDM_GET_PLDM_COMMANDS}};
39 
40 const std::map<const char*, pldm_bios_commands> pldmBiosCmds{
41     {"GetBIOSTable", PLDM_GET_BIOS_TABLE},
42     {"SetBIOSTable", PLDM_SET_BIOS_TABLE},
43     {"SetBIOSAttributeCurrentValue", PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE},
44     {"GetBIOSAttributeCurrentValueByHandle",
45      PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE},
46     {"GetDateTime", PLDM_GET_DATE_TIME},
47     {"SetDateTime", PLDM_SET_DATE_TIME}};
48 
49 const std::map<const char*, pldm_platform_commands> pldmPlatformCmds{
50     {"SetNumericEffecterValue", PLDM_SET_NUMERIC_EFFECTER_VALUE},
51     {"SetStateEffecterStates", PLDM_SET_STATE_EFFECTER_STATES},
52     {"GetStateEffecterStates", PLDM_GET_STATE_EFFECTER_STATES},
53     {"GetPDR", PLDM_GET_PDR},
54     {"GetNumericEffecterValue", PLDM_GET_NUMERIC_EFFECTER_VALUE},
55     {"SetEventReceiver", PLDM_SET_EVENT_RECEIVER},
56     {"GetSensorReading", PLDM_GET_SENSOR_READING},
57     {"GetStateSensorReadings", PLDM_GET_STATE_SENSOR_READINGS},
58     {"PlatformEventMessage", PLDM_PLATFORM_EVENT_MESSAGE}};
59 
60 const std::map<const char*, pldm_fru_commands> pldmFruCmds{
61     {"GetFRURecordTableMetadata", PLDM_GET_FRU_RECORD_TABLE_METADATA},
62     {"GetFRURecordTable", PLDM_GET_FRU_RECORD_TABLE},
63     {"GetFRURecordByOption", PLDM_GET_FRU_RECORD_BY_OPTION}};
64 
65 #ifdef OEM_IBM
66 const std::map<const char*, pldm_host_commands> pldmIBMHostCmds{
67     {"GetAlertStatus", PLDM_HOST_GET_ALERT_STATUS}};
68 
69 const std::map<const char*, pldm_fileio_commands> pldmIBMFileIOCmds{
70     {"GetFileTable", PLDM_GET_FILE_TABLE},
71     {"ReadFile", PLDM_READ_FILE},
72     {"WriteFile", PLDM_WRITE_FILE},
73     {"ReadFileInToMemory", PLDM_READ_FILE_INTO_MEMORY},
74     {"WriteFileFromMemory", PLDM_WRITE_FILE_FROM_MEMORY},
75     {"ReadFileByTypeIntoMemory", PLDM_READ_FILE_BY_TYPE_INTO_MEMORY},
76     {"WriteFileByTypeFromMemory", PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY},
77     {"NewFileAvailable", PLDM_NEW_FILE_AVAILABLE},
78     {"ReadFileByType", PLDM_READ_FILE_BY_TYPE},
79     {"WriteFileByType", PLDM_WRITE_FILE_BY_TYPE},
80     {"FileAck", PLDM_FILE_ACK}};
81 #endif
82 
83 } // namespace
84 
85 class GetPLDMTypes : public CommandInterface
86 {
87   public:
88     ~GetPLDMTypes() = default;
89     GetPLDMTypes() = delete;
90     GetPLDMTypes(const GetPLDMTypes&) = delete;
91     GetPLDMTypes(GetPLDMTypes&&) = default;
92     GetPLDMTypes& operator=(const GetPLDMTypes&) = delete;
93     GetPLDMTypes& operator=(GetPLDMTypes&&) = delete;
94 
95     using CommandInterface::CommandInterface;
96 
97     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
98     {
99         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
100         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
101         auto rc = encode_get_types_req(instanceId, request);
102         return {rc, requestMsg};
103     }
104 
105     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
106     {
107         uint8_t cc = 0;
108         std::vector<bitfield8_t> types(8);
109         auto rc = decode_get_types_resp(responsePtr, payloadLength, &cc,
110                                         types.data());
111         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
112         {
113             std::cerr << "Response Message Error: "
114                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
115             return;
116         }
117 
118         printPldmTypes(types);
119     }
120 
121   private:
122     void printPldmTypes(std::vector<bitfield8_t>& types)
123     {
124         ordered_json data;
125         ordered_json jarray;
126         for (int i = 0; i < PLDM_MAX_TYPES; i++)
127         {
128             bitfield8_t b = types[i / 8];
129             if (b.byte & (1 << i % 8))
130             {
131                 auto it = std::find_if(
132                     pldmTypes.begin(), pldmTypes.end(),
133                     [i](const auto& typePair) { return typePair.second == i; });
134                 if (it != pldmTypes.end())
135                 {
136                     jarray["PLDM Type"] = it->first;
137                     jarray["PLDM Type Code"] = i;
138                     data.emplace_back(jarray);
139                 }
140             }
141         }
142         pldmtool::helper::DisplayInJson(data);
143     }
144 };
145 
146 class GetPLDMVersion : public CommandInterface
147 {
148   public:
149     ~GetPLDMVersion() = default;
150     GetPLDMVersion() = delete;
151     GetPLDMVersion(const GetPLDMVersion&) = delete;
152     GetPLDMVersion(GetPLDMVersion&&) = default;
153     GetPLDMVersion& operator=(const GetPLDMVersion&) = delete;
154     GetPLDMVersion& operator=(GetPLDMVersion&&) = delete;
155 
156     explicit GetPLDMVersion(const char* type, const char* name, CLI::App* app) :
157         CommandInterface(type, name, app)
158     {
159         app->add_option("-t,--type", pldmType, "pldm supported type")
160             ->required()
161             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
162     }
163     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
164     {
165         std::vector<uint8_t> requestMsg(
166             sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES);
167         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
168 
169         auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
170                                          pldmType, request);
171         return {rc, requestMsg};
172     }
173 
174     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
175     {
176         uint8_t cc = 0, transferFlag = 0;
177         uint32_t transferHandle = 0;
178         ver32_t version;
179         auto rc =
180             decode_get_version_resp(responsePtr, payloadLength, &cc,
181                                     &transferHandle, &transferFlag, &version);
182         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
183         {
184             std::cerr << "Response Message Error: "
185                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
186             return;
187         }
188         char buffer[16] = {0};
189         ver2str(&version, buffer, sizeof(buffer));
190         ordered_json data;
191         auto it = std::find_if(
192             pldmTypes.begin(), pldmTypes.end(),
193             [&](const auto& typePair) { return typePair.second == pldmType; });
194 
195         if (it != pldmTypes.end())
196         {
197             data["Response"] = buffer;
198         }
199         pldmtool::helper::DisplayInJson(data);
200     }
201 
202   private:
203     pldm_supported_types pldmType;
204 };
205 
206 class GetTID : public CommandInterface
207 {
208   public:
209     ~GetTID() = default;
210     GetTID() = delete;
211     GetTID(const GetTID&) = delete;
212     GetTID(GetTID&&) = default;
213     GetTID& operator=(const GetTID&) = delete;
214     GetTID& operator=(GetTID&&) = delete;
215 
216     using CommandInterface::CommandInterface;
217 
218     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
219     {
220         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
221         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
222         auto rc = encode_get_tid_req(instanceId, request);
223         return {rc, requestMsg};
224     }
225 
226     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
227     {
228         uint8_t cc = 0;
229         uint8_t tid = 0;
230         std::vector<bitfield8_t> types(8);
231         auto rc = decode_get_tid_resp(responsePtr, payloadLength, &cc, &tid);
232         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
233         {
234             std::cerr << "Response Message Error: "
235                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
236             return;
237         }
238         ordered_json data;
239         data["Response"] = static_cast<uint32_t>(tid);
240         pldmtool::helper::DisplayInJson(data);
241     }
242 };
243 
244 class GetPLDMCommands : public CommandInterface
245 {
246   public:
247     ~GetPLDMCommands() = default;
248     GetPLDMCommands() = delete;
249     GetPLDMCommands(const GetPLDMCommands&) = delete;
250     GetPLDMCommands(GetPLDMCommands&&) = default;
251     GetPLDMCommands& operator=(const GetPLDMCommands&) = delete;
252     GetPLDMCommands& operator=(GetPLDMCommands&&) = delete;
253 
254     explicit GetPLDMCommands(const char* type, const char* name,
255                              CLI::App* app) : CommandInterface(type, name, app)
256     {
257         app->add_option("-t,--type", pldmType, "pldm supported type")
258             ->required()
259             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
260         app->add_option(
261             "-d,--data", inputVersion,
262             "Set PLDM type version. Which is got from GetPLDMVersion\n"
263             "eg: version 1.1.0 then data will be `0xf1 0xf1 0xf0 0x00`");
264     }
265 
266     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
267     {
268         std::vector<uint8_t> requestMsg(
269             sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
270         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
271         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
272         if (inputVersion.size() != 0)
273         {
274             if (inputVersion.size() != 4)
275             {
276                 std::cerr << "Invalid version format. "
277                           << "\n";
278             }
279             else
280             {
281                 version.major = inputVersion[3];
282                 version.minor = inputVersion[2];
283                 version.update = inputVersion[1];
284                 version.alpha = inputVersion[0];
285             }
286         }
287         auto rc =
288             encode_get_commands_req(instanceId, pldmType, version, request);
289         return {rc, requestMsg};
290     }
291 
292     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
293     {
294         uint8_t cc = 0;
295         std::vector<bitfield8_t> cmdTypes(32);
296         auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
297                                            cmdTypes.data());
298         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
299         {
300             std::cerr << "Response Message Error: "
301                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
302             return;
303         }
304         printPldmCommands(cmdTypes, pldmType);
305     }
306 
307   private:
308     pldm_supported_types pldmType;
309     std::vector<uint8_t> inputVersion;
310 
311     template <typename CommandMap>
312     void printCommand(CommandMap& commandMap, int i, ordered_json& jarray)
313     {
314         auto it = std::find_if(
315             commandMap.begin(), commandMap.end(),
316             [i](const auto& typePair) { return typePair.second == i; });
317         if (it != commandMap.end())
318         {
319             jarray["PLDM Command Code"] = i;
320             jarray["PLDM Command"] = it->first;
321         }
322     }
323 
324     void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
325                            pldm_supported_types pldmType)
326     {
327         ordered_json output;
328         for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
329         {
330             ordered_json cmdinfo;
331             bitfield8_t b = cmdTypes[i / 8];
332             if (b.byte & (1 << i % 8))
333             {
334                 switch (pldmType)
335                 {
336                     case PLDM_BASE:
337                         printCommand(pldmBaseCmds, i, cmdinfo);
338                         break;
339                     case PLDM_PLATFORM:
340                         printCommand(pldmPlatformCmds, i, cmdinfo);
341                         break;
342                     case PLDM_BIOS:
343                         printCommand(pldmBiosCmds, i, cmdinfo);
344                         break;
345                     case PLDM_FRU:
346                         printCommand(pldmFruCmds, i, cmdinfo);
347                         break;
348                     case PLDM_OEM:
349 #ifdef OEM_IBM
350                         printCommand(pldmIBMHostCmds, i, cmdinfo);
351                         printCommand(pldmIBMFileIOCmds, i, cmdinfo);
352 #endif
353                         break;
354                     default:
355                         break;
356                 }
357                 output.emplace_back(cmdinfo);
358             }
359         }
360         pldmtool::helper::DisplayInJson(output);
361     }
362 };
363 
364 void registerCommand(CLI::App& app)
365 {
366     auto base = app.add_subcommand("base", "base type command");
367     base->require_subcommand(1);
368 
369     auto getPLDMTypes =
370         base->add_subcommand("GetPLDMTypes", "get pldm supported types");
371     commands.push_back(
372         std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
373 
374     auto getPLDMVersion =
375         base->add_subcommand("GetPLDMVersion", "get version of a certain type");
376     commands.push_back(std::make_unique<GetPLDMVersion>(
377         "base", "GetPLDMVersion", getPLDMVersion));
378 
379     auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
380     commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
381 
382     auto getPLDMCommands = base->add_subcommand(
383         "GetPLDMCommands", "get supported commands of pldm type");
384     commands.push_back(std::make_unique<GetPLDMCommands>(
385         "base", "GetPLDMCommands", getPLDMCommands));
386 }
387 
388 } // namespace base
389 } // namespace pldmtool
390