xref: /openbmc/pldm/pldmtool/pldm_base_cmd.cpp (revision 8570fcc6)
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     }
262 
263     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
264     {
265         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
266                                         PLDM_GET_COMMANDS_REQ_BYTES);
267         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
268         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
269         auto rc = encode_get_commands_req(instanceId, pldmType, version,
270                                           request);
271         return {rc, requestMsg};
272     }
273 
274     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
275     {
276         uint8_t cc = 0;
277         std::vector<bitfield8_t> cmdTypes(32);
278         auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
279                                            cmdTypes.data());
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         printPldmCommands(cmdTypes, pldmType);
287     }
288 
289   private:
290     pldm_supported_types pldmType;
291 
292     template <typename CommandMap>
293     void printCommand(CommandMap& commandMap, int i, ordered_json& jarray)
294     {
295         auto it = std::find_if(
296             commandMap.begin(), commandMap.end(),
297             [i](const auto& typePair) { return typePair.second == i; });
298         if (it != commandMap.end())
299         {
300             jarray["PLDM Command Code"] = i;
301             jarray["PLDM Command"] = it->first;
302         }
303     }
304 
305     void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
306                            pldm_supported_types pldmType)
307     {
308         ordered_json output;
309         for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
310         {
311             ordered_json cmdinfo;
312             bitfield8_t b = cmdTypes[i / 8];
313             if (b.byte & (1 << i % 8))
314             {
315                 switch (pldmType)
316                 {
317                     case PLDM_BASE:
318                         printCommand(pldmBaseCmds, i, cmdinfo);
319                         break;
320                     case PLDM_PLATFORM:
321                         printCommand(pldmPlatformCmds, i, cmdinfo);
322                         break;
323                     case PLDM_BIOS:
324                         printCommand(pldmBiosCmds, i, cmdinfo);
325                         break;
326                     case PLDM_FRU:
327                         printCommand(pldmFruCmds, i, cmdinfo);
328                         break;
329                     case PLDM_OEM:
330 #ifdef OEM_IBM
331                         printCommand(pldmIBMHostCmds, i, cmdinfo);
332                         printCommand(pldmIBMFileIOCmds, i, cmdinfo);
333 #endif
334                         break;
335                     default:
336                         break;
337                 }
338                 output.emplace_back(cmdinfo);
339             }
340         }
341         pldmtool::helper::DisplayInJson(output);
342     }
343 };
344 
345 void registerCommand(CLI::App& app)
346 {
347     auto base = app.add_subcommand("base", "base type command");
348     base->require_subcommand(1);
349 
350     auto getPLDMTypes = base->add_subcommand("GetPLDMTypes",
351                                              "get pldm supported types");
352     commands.push_back(
353         std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
354 
355     auto getPLDMVersion = base->add_subcommand("GetPLDMVersion",
356                                                "get version of a certain type");
357     commands.push_back(std::make_unique<GetPLDMVersion>(
358         "base", "GetPLDMVersion", getPLDMVersion));
359 
360     auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
361     commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
362 
363     auto getPLDMCommands = base->add_subcommand(
364         "GetPLDMCommands", "get supported commands of pldm type");
365     commands.push_back(std::make_unique<GetPLDMCommands>(
366         "base", "GetPLDMCommands", getPLDMCommands));
367 }
368 
369 } // namespace base
370 } // namespace pldmtool
371