xref: /openbmc/pldm/pldmtool/pldm_base_cmd.cpp (revision c14fb4bd)
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(sizeof(pldm_msg_hdr) +
166                                         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 = decode_get_version_resp(responsePtr, payloadLength, &cc,
180                                           &transferHandle, &transferFlag,
181                                           &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) :
256         CommandInterface(type, name, app)
257     {
258         app->add_option("-t,--type", pldmType, "pldm supported type")
259             ->required()
260             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
261         app->add_option(
262             "-d,--data", inputVersion,
263             "Set PLDM type version. Which is got from GetPLDMVersion\n"
264             "eg: version 1.1.0 then data will be `0xf1 0xf1 0xf0 0x00`");
265     }
266 
267     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
268     {
269         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
270                                         PLDM_GET_COMMANDS_REQ_BYTES);
271         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
272         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
273         if (inputVersion.size() != 0)
274         {
275             if (inputVersion.size() != 4)
276             {
277                 std::cerr << "Invalid version format. "
278                           << "\n";
279             }
280             else
281             {
282                 version.major = inputVersion[3];
283                 version.minor = inputVersion[2];
284                 version.update = inputVersion[1];
285                 version.alpha = inputVersion[0];
286             }
287         }
288         auto rc = encode_get_commands_req(instanceId, pldmType, version,
289                                           request);
290         return {rc, requestMsg};
291     }
292 
293     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
294     {
295         uint8_t cc = 0;
296         std::vector<bitfield8_t> cmdTypes(32);
297         auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
298                                            cmdTypes.data());
299         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
300         {
301             std::cerr << "Response Message Error: "
302                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
303             return;
304         }
305         printPldmCommands(cmdTypes, pldmType);
306     }
307 
308   private:
309     pldm_supported_types pldmType;
310     std::vector<uint8_t> inputVersion;
311 
312     template <typename CommandMap>
313     void printCommand(CommandMap& commandMap, int i, ordered_json& jarray)
314     {
315         auto it = std::find_if(
316             commandMap.begin(), commandMap.end(),
317             [i](const auto& typePair) { return typePair.second == i; });
318         if (it != commandMap.end())
319         {
320             jarray["PLDM Command Code"] = i;
321             jarray["PLDM Command"] = it->first;
322         }
323     }
324 
325     void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
326                            pldm_supported_types pldmType)
327     {
328         ordered_json output;
329         for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
330         {
331             ordered_json cmdinfo;
332             bitfield8_t b = cmdTypes[i / 8];
333             if (b.byte & (1 << i % 8))
334             {
335                 switch (pldmType)
336                 {
337                     case PLDM_BASE:
338                         printCommand(pldmBaseCmds, i, cmdinfo);
339                         break;
340                     case PLDM_PLATFORM:
341                         printCommand(pldmPlatformCmds, i, cmdinfo);
342                         break;
343                     case PLDM_BIOS:
344                         printCommand(pldmBiosCmds, i, cmdinfo);
345                         break;
346                     case PLDM_FRU:
347                         printCommand(pldmFruCmds, i, cmdinfo);
348                         break;
349                     case PLDM_OEM:
350 #ifdef OEM_IBM
351                         printCommand(pldmIBMHostCmds, i, cmdinfo);
352                         printCommand(pldmIBMFileIOCmds, i, cmdinfo);
353 #endif
354                         break;
355                     default:
356                         break;
357                 }
358                 output.emplace_back(cmdinfo);
359             }
360         }
361         pldmtool::helper::DisplayInJson(output);
362     }
363 };
364 
365 void registerCommand(CLI::App& app)
366 {
367     auto base = app.add_subcommand("base", "base type command");
368     base->require_subcommand(1);
369 
370     auto getPLDMTypes = base->add_subcommand("GetPLDMTypes",
371                                              "get pldm supported types");
372     commands.push_back(
373         std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
374 
375     auto getPLDMVersion = base->add_subcommand("GetPLDMVersion",
376                                                "get version of a certain type");
377     commands.push_back(std::make_unique<GetPLDMVersion>(
378         "base", "GetPLDMVersion", getPLDMVersion));
379 
380     auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
381     commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
382 
383     auto getPLDMCommands = base->add_subcommand(
384         "GetPLDMCommands", "get supported commands of pldm type");
385     commands.push_back(std::make_unique<GetPLDMCommands>(
386         "base", "GetPLDMCommands", getPLDMCommands));
387 }
388 
389 } // namespace base
390 } // namespace pldmtool
391