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