xref: /openbmc/pldm/pldmtool/pldm_base_cmd.cpp (revision 6da4f91b)
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/file_io.h>
9 #include <libpldm/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     {"GetPDR", PLDM_GET_PDR},
53     {"GetNumericEffecterValue", PLDM_GET_NUMERIC_EFFECTER_VALUE},
54     {"SetEventReceiver", PLDM_SET_EVENT_RECEIVER},
55     {"GetSensorReading", PLDM_GET_SENSOR_READING},
56     {"GetStateSensorReadings", PLDM_GET_STATE_SENSOR_READINGS},
57     {"PlatformEventMessage", PLDM_PLATFORM_EVENT_MESSAGE}};
58 
59 const std::map<const char*, pldm_fru_commands> pldmFruCmds{
60     {"GetFRURecordTableMetadata", PLDM_GET_FRU_RECORD_TABLE_METADATA},
61     {"GetFRURecordTable", PLDM_GET_FRU_RECORD_TABLE},
62     {"GetFRURecordByOption", PLDM_GET_FRU_RECORD_BY_OPTION}};
63 
64 #ifdef OEM_IBM
65 const std::map<const char*, pldm_host_commands> pldmIBMHostCmds{
66     {"GetAlertStatus", PLDM_HOST_GET_ALERT_STATUS}};
67 
68 const std::map<const char*, pldm_fileio_commands> pldmIBMFileIOCmds{
69     {"GetFileTable", PLDM_GET_FILE_TABLE},
70     {"ReadFile", PLDM_READ_FILE},
71     {"WriteFile", PLDM_WRITE_FILE},
72     {"ReadFileInToMemory", PLDM_READ_FILE_INTO_MEMORY},
73     {"WriteFileFromMemory", PLDM_WRITE_FILE_FROM_MEMORY},
74     {"ReadFileByTypeIntoMemory", PLDM_READ_FILE_BY_TYPE_INTO_MEMORY},
75     {"WriteFileByTypeFromMemory", PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY},
76     {"NewFileAvailable", PLDM_NEW_FILE_AVAILABLE},
77     {"ReadFileByType", PLDM_READ_FILE_BY_TYPE},
78     {"WriteFileByType", PLDM_WRITE_FILE_BY_TYPE},
79     {"FileAck", PLDM_FILE_ACK}};
80 #endif
81 
82 } // namespace
83 
84 class GetPLDMTypes : public CommandInterface
85 {
86   public:
87     ~GetPLDMTypes() = default;
88     GetPLDMTypes() = delete;
89     GetPLDMTypes(const GetPLDMTypes&) = delete;
90     GetPLDMTypes(GetPLDMTypes&&) = default;
91     GetPLDMTypes& operator=(const GetPLDMTypes&) = delete;
92     GetPLDMTypes& operator=(GetPLDMTypes&&) = default;
93 
94     using CommandInterface::CommandInterface;
95 
96     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
97     {
98         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
99         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
100         auto rc = encode_get_types_req(instanceId, request);
101         return {rc, requestMsg};
102     }
103 
104     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
105     {
106         uint8_t cc = 0;
107         std::vector<bitfield8_t> types(8);
108         auto rc = decode_get_types_resp(responsePtr, payloadLength, &cc,
109                                         types.data());
110         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
111         {
112             std::cerr << "Response Message Error: "
113                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
114             return;
115         }
116 
117         printPldmTypes(types);
118     }
119 
120   private:
121     void printPldmTypes(std::vector<bitfield8_t>& types)
122     {
123         ordered_json data;
124         ordered_json jarray;
125         for (int i = 0; i < PLDM_MAX_TYPES; i++)
126         {
127             bitfield8_t b = types[i / 8];
128             if (b.byte & (1 << i % 8))
129             {
130                 auto it = std::find_if(pldmTypes.begin(), pldmTypes.end(),
131                                        [i](const auto& typePair) {
132                     return typePair.second == i;
133                 });
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&&) = default;
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(pldmTypes.begin(), pldmTypes.end(),
192                                [&](const auto& typePair) {
193             return typePair.second == pldmType;
194         });
195 
196         if (it != pldmTypes.end())
197         {
198             data["Response"] = buffer;
199         }
200         pldmtool::helper::DisplayInJson(data);
201     }
202 
203   private:
204     pldm_supported_types pldmType;
205 };
206 
207 class GetTID : public CommandInterface
208 {
209   public:
210     ~GetTID() = default;
211     GetTID() = delete;
212     GetTID(const GetTID&) = delete;
213     GetTID(GetTID&&) = default;
214     GetTID& operator=(const GetTID&) = delete;
215     GetTID& operator=(GetTID&&) = default;
216 
217     using CommandInterface::CommandInterface;
218 
219     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
220     {
221         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
222         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
223         auto rc = encode_get_tid_req(instanceId, request);
224         return {rc, requestMsg};
225     }
226 
227     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
228     {
229         uint8_t cc = 0;
230         uint8_t tid = 0;
231         std::vector<bitfield8_t> types(8);
232         auto rc = decode_get_tid_resp(responsePtr, payloadLength, &cc, &tid);
233         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
234         {
235             std::cerr << "Response Message Error: "
236                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
237             return;
238         }
239         ordered_json data;
240         data["Response"] = static_cast<uint32_t>(tid);
241         pldmtool::helper::DisplayInJson(data);
242     }
243 };
244 
245 class GetPLDMCommands : public CommandInterface
246 {
247   public:
248     ~GetPLDMCommands() = default;
249     GetPLDMCommands() = delete;
250     GetPLDMCommands(const GetPLDMCommands&) = delete;
251     GetPLDMCommands(GetPLDMCommands&&) = default;
252     GetPLDMCommands& operator=(const GetPLDMCommands&) = delete;
253     GetPLDMCommands& operator=(GetPLDMCommands&&) = default;
254 
255     explicit GetPLDMCommands(const char* type, const char* name,
256                              CLI::App* app) :
257         CommandInterface(type, name, app)
258     {
259         app->add_option("-t,--type", pldmType, "pldm supported type")
260             ->required()
261             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
262     }
263 
264     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
265     {
266         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
267                                         PLDM_GET_COMMANDS_REQ_BYTES);
268         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
269         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
270         auto rc = encode_get_commands_req(instanceId, pldmType, version,
271                                           request);
272         return {rc, requestMsg};
273     }
274 
275     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
276     {
277         uint8_t cc = 0;
278         std::vector<bitfield8_t> cmdTypes(32);
279         auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
280                                            cmdTypes.data());
281         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
282         {
283             std::cerr << "Response Message Error: "
284                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
285             return;
286         }
287         printPldmCommands(cmdTypes, pldmType);
288     }
289 
290   private:
291     pldm_supported_types pldmType;
292 
293     template <typename CommandMap>
294     void printCommand(CommandMap& commandMap, int i, ordered_json& jarray)
295     {
296         auto it = std::find_if(commandMap.begin(), commandMap.end(),
297                                [i](const auto& typePair) {
298             return typePair.second == i;
299         });
300         if (it != commandMap.end())
301         {
302             jarray["PLDM Command Code"] = i;
303             jarray["PLDM Command"] = it->first;
304         }
305     }
306 
307     void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
308                            pldm_supported_types pldmType)
309     {
310         ordered_json output;
311         for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
312         {
313             ordered_json cmdinfo;
314             bitfield8_t b = cmdTypes[i / 8];
315             if (b.byte & (1 << i % 8))
316             {
317                 switch (pldmType)
318                 {
319                     case PLDM_BASE:
320                         printCommand(pldmBaseCmds, i, cmdinfo);
321                         break;
322                     case PLDM_PLATFORM:
323                         printCommand(pldmPlatformCmds, i, cmdinfo);
324                         break;
325                     case PLDM_BIOS:
326                         printCommand(pldmBiosCmds, i, cmdinfo);
327                         break;
328                     case PLDM_FRU:
329                         printCommand(pldmFruCmds, i, cmdinfo);
330                         break;
331                     case PLDM_OEM:
332 #ifdef OEM_IBM
333                         printCommand(pldmIBMHostCmds, i, cmdinfo);
334                         printCommand(pldmIBMFileIOCmds, i, cmdinfo);
335 #endif
336                         break;
337                     default:
338                         break;
339                 }
340                 output.emplace_back(cmdinfo);
341             }
342         }
343         pldmtool::helper::DisplayInJson(output);
344     }
345 };
346 
347 void registerCommand(CLI::App& app)
348 {
349     auto base = app.add_subcommand("base", "base type command");
350     base->require_subcommand(1);
351 
352     auto getPLDMTypes = base->add_subcommand("GetPLDMTypes",
353                                              "get pldm supported types");
354     commands.push_back(
355         std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
356 
357     auto getPLDMVersion = base->add_subcommand("GetPLDMVersion",
358                                                "get version of a certain type");
359     commands.push_back(std::make_unique<GetPLDMVersion>(
360         "base", "GetPLDMVersion", getPLDMVersion));
361 
362     auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
363     commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
364 
365     auto getPLDMCommands = base->add_subcommand(
366         "GetPLDMCommands", "get supported commands of pldm type");
367     commands.push_back(std::make_unique<GetPLDMCommands>(
368         "base", "GetPLDMCommands", getPLDMCommands));
369 }
370 
371 } // namespace base
372 } // namespace pldmtool
373