xref: /openbmc/pldm/pldmtool/pldm_base_cmd.cpp (revision ade5f9b1)
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(
131                     pldmTypes.begin(), pldmTypes.end(),
132                     [i](const auto& typePair) { return typePair.second == i; });
133                 if (it != pldmTypes.end())
134                 {
135                     jarray["PLDM Type"] = it->first;
136                     jarray["PLDM Type Code"] = i;
137                     data.emplace_back(jarray);
138                 }
139             }
140         }
141         pldmtool::helper::DisplayInJson(data);
142     }
143 };
144 
145 class GetPLDMVersion : public CommandInterface
146 {
147   public:
148     ~GetPLDMVersion() = default;
149     GetPLDMVersion() = delete;
150     GetPLDMVersion(const GetPLDMVersion&) = delete;
151     GetPLDMVersion(GetPLDMVersion&&) = default;
152     GetPLDMVersion& operator=(const GetPLDMVersion&) = delete;
153     GetPLDMVersion& operator=(GetPLDMVersion&&) = default;
154 
155     explicit GetPLDMVersion(const char* type, const char* name, CLI::App* app) :
156         CommandInterface(type, name, app)
157     {
158         app->add_option("-t,--type", pldmType, "pldm supported type")
159             ->required()
160             ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
161     }
162     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
163     {
164         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
165                                         PLDM_GET_VERSION_REQ_BYTES);
166         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
167 
168         auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
169                                          pldmType, request);
170         return {rc, requestMsg};
171     }
172 
173     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
174     {
175         uint8_t cc = 0, transferFlag = 0;
176         uint32_t transferHandle = 0;
177         ver32_t version;
178         auto rc =
179             decode_get_version_resp(responsePtr, payloadLength, &cc,
180                                     &transferHandle, &transferFlag, &version);
181         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
182         {
183             std::cerr << "Response Message Error: "
184                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
185             return;
186         }
187         char buffer[16] = {0};
188         ver2str(&version, buffer, sizeof(buffer));
189         ordered_json data;
190         auto it = std::find_if(
191             pldmTypes.begin(), pldmTypes.end(),
192             [&](const auto& typePair) { return typePair.second == pldmType; });
193 
194         if (it != pldmTypes.end())
195         {
196             data["Response"] = buffer;
197         }
198         pldmtool::helper::DisplayInJson(data);
199     }
200 
201   private:
202     pldm_supported_types pldmType;
203 };
204 
205 class GetTID : public CommandInterface
206 {
207   public:
208     ~GetTID() = default;
209     GetTID() = delete;
210     GetTID(const GetTID&) = delete;
211     GetTID(GetTID&&) = default;
212     GetTID& operator=(const GetTID&) = delete;
213     GetTID& operator=(GetTID&&) = default;
214 
215     using CommandInterface::CommandInterface;
216 
217     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
218     {
219         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
220         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
221         auto rc = encode_get_tid_req(instanceId, request);
222         return {rc, requestMsg};
223     }
224 
225     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
226     {
227         uint8_t cc = 0;
228         uint8_t tid = 0;
229         std::vector<bitfield8_t> types(8);
230         auto rc = decode_get_tid_resp(responsePtr, payloadLength, &cc, &tid);
231         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
232         {
233             std::cerr << "Response Message Error: "
234                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
235             return;
236         }
237         ordered_json data;
238         data["Response"] = static_cast<uint32_t>(tid);
239         pldmtool::helper::DisplayInJson(data);
240     }
241 };
242 
243 class GetPLDMCommands : public CommandInterface
244 {
245   public:
246     ~GetPLDMCommands() = default;
247     GetPLDMCommands() = delete;
248     GetPLDMCommands(const GetPLDMCommands&) = delete;
249     GetPLDMCommands(GetPLDMCommands&&) = default;
250     GetPLDMCommands& operator=(const GetPLDMCommands&) = delete;
251     GetPLDMCommands& operator=(GetPLDMCommands&&) = default;
252 
253     explicit GetPLDMCommands(const char* type, const char* name,
254                              CLI::App* app) :
255         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     }
261 
262     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
263     {
264         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
265                                         PLDM_GET_COMMANDS_REQ_BYTES);
266         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
267         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
268         auto rc =
269             encode_get_commands_req(instanceId, pldmType, version, request);
270         return {rc, requestMsg};
271     }
272 
273     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
274     {
275         uint8_t cc = 0;
276         std::vector<bitfield8_t> cmdTypes(32);
277         auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
278                                            cmdTypes.data());
279         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
280         {
281             std::cerr << "Response Message Error: "
282                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
283             return;
284         }
285         printPldmCommands(cmdTypes, pldmType);
286     }
287 
288   private:
289     pldm_supported_types pldmType;
290 
291     template <typename CommandMap>
292     void printCommand(CommandMap& commandMap, int i, ordered_json& jarray)
293     {
294         auto it = std::find_if(
295             commandMap.begin(), commandMap.end(),
296             [i](const auto& typePair) { return typePair.second == i; });
297         if (it != commandMap.end())
298         {
299             jarray["PLDM Command Code"] = i;
300             jarray["PLDM Command"] = it->first;
301         }
302     }
303 
304     void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
305                            pldm_supported_types pldmType)
306     {
307         ordered_json output;
308         for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
309         {
310             ordered_json cmdinfo;
311             bitfield8_t b = cmdTypes[i / 8];
312             if (b.byte & (1 << i % 8))
313             {
314                 switch (pldmType)
315                 {
316                     case PLDM_BASE:
317                         printCommand(pldmBaseCmds, i, cmdinfo);
318                         break;
319                     case PLDM_PLATFORM:
320                         printCommand(pldmPlatformCmds, i, cmdinfo);
321                         break;
322                     case PLDM_BIOS:
323                         printCommand(pldmBiosCmds, i, cmdinfo);
324                         break;
325                     case PLDM_FRU:
326                         printCommand(pldmFruCmds, i, cmdinfo);
327                         break;
328                     case PLDM_OEM:
329 #ifdef OEM_IBM
330                         printCommand(pldmIBMHostCmds, i, cmdinfo);
331                         printCommand(pldmIBMFileIOCmds, i, cmdinfo);
332 #endif
333                         break;
334                     default:
335                         break;
336                 }
337                 output.emplace_back(cmdinfo);
338             }
339         }
340         pldmtool::helper::DisplayInJson(output);
341     }
342 };
343 
344 void registerCommand(CLI::App& app)
345 {
346     auto base = app.add_subcommand("base", "base type command");
347     base->require_subcommand(1);
348 
349     auto getPLDMTypes =
350         base->add_subcommand("GetPLDMTypes", "get pldm supported types");
351     commands.push_back(
352         std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
353 
354     auto getPLDMVersion =
355         base->add_subcommand("GetPLDMVersion", "get version of a certain type");
356     commands.push_back(std::make_unique<GetPLDMVersion>(
357         "base", "GetPLDMVersion", getPLDMVersion));
358 
359     auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
360     commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
361 
362     auto getPLDMCommands = base->add_subcommand(
363         "GetPLDMCommands", "get supported commands of pldm type");
364     commands.push_back(std::make_unique<GetPLDMCommands>(
365         "base", "GetPLDMCommands", getPLDMCommands));
366 }
367 
368 } // namespace base
369 } // namespace pldmtool
370