xref: /openbmc/pldm/pldmtool/pldm_bios_cmd.cpp (revision 5c3f0d1b09bfbd206c33841b83938ef5f057a655)
1 #include "pldm_bios_cmd.hpp"
2 
3 #include "common/bios_utils.hpp"
4 #include "common/utils.hpp"
5 #include "pldm_cmd_helper.hpp"
6 
7 #include <libpldm/bios_table.h>
8 #include <libpldm/utils.h>
9 
10 #include <map>
11 #include <optional>
12 
13 namespace pldmtool
14 {
15 
16 namespace bios
17 {
18 
19 namespace
20 {
21 
22 using namespace pldmtool::helper;
23 using namespace pldm::bios::utils;
24 using namespace pldm::utils;
25 
26 std::vector<std::unique_ptr<CommandInterface>> commands;
27 
28 const std::map<const char*, pldm_bios_table_types> pldmBIOSTableTypes{
29     {"StringTable", PLDM_BIOS_STRING_TABLE},
30     {"AttributeTable", PLDM_BIOS_ATTR_TABLE},
31     {"AttributeValueTable", PLDM_BIOS_ATTR_VAL_TABLE},
32 };
33 
34 } // namespace
35 
36 class GetDateTime : public CommandInterface
37 {
38   public:
39     ~GetDateTime() = default;
40     GetDateTime() = delete;
41     GetDateTime(const GetDateTime&) = delete;
42     GetDateTime(GetDateTime&&) = default;
43     GetDateTime& operator=(const GetDateTime&) = delete;
44     GetDateTime& operator=(GetDateTime&&) = delete;
45 
46     using CommandInterface::CommandInterface;
47 
createRequestMsg()48     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
49     {
50         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
51         auto request = new (requestMsg.data()) pldm_msg;
52 
53         auto rc = encode_get_date_time_req(instanceId, request);
54         return {rc, requestMsg};
55     }
56 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)57     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
58     {
59         uint8_t cc = 0;
60 
61         uint8_t seconds, minutes, hours, day, month;
62         uint16_t year;
63         auto rc =
64             decode_get_date_time_resp(responsePtr, payloadLength, &cc, &seconds,
65                                       &minutes, &hours, &day, &month, &year);
66         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
67         {
68             std::cerr << "Response Message Error: "
69                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
70             return;
71         }
72 
73         std::stringstream dt;
74         ordered_json data;
75         dt << bcd2dec16(year) << "-" << setWidth(month) << "-" << setWidth(day)
76            << " " << setWidth(hours) << ":" << setWidth(minutes) << ":"
77            << setWidth(seconds);
78         data["Response"] = dt.str();
79         pldmtool::helper::DisplayInJson(data);
80     }
81 
82   private:
setWidth(uint8_t data)83     static std::string setWidth(uint8_t data)
84     {
85         std::stringstream s;
86         s << std::setfill('0') << std::setw(2)
87           << static_cast<uint32_t>(bcd2dec8(data));
88         return s.str();
89     }
90 };
91 
92 class SetDateTime : public CommandInterface
93 {
94   public:
95     ~SetDateTime() = default;
96     SetDateTime() = delete;
97     SetDateTime(const SetDateTime&) = delete;
98     SetDateTime(SetDateTime&&) = default;
99     SetDateTime& operator=(const SetDateTime&) = delete;
100     SetDateTime& operator=(SetDateTime&&) = delete;
101 
SetDateTime(const char * type,const char * name,CLI::App * app)102     explicit SetDateTime(const char* type, const char* name, CLI::App* app) :
103         CommandInterface(type, name, app)
104     {
105         app->add_option("-d,--data", tmData,
106                         "set date time data\n"
107                         "eg: YYYYMMDDHHMMSS")
108             ->required();
109     }
110 
createRequestMsg()111     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
112     {
113         std::vector<uint8_t> requestMsg(
114             sizeof(pldm_msg_hdr) + sizeof(struct pldm_set_date_time_req));
115         auto request = new (requestMsg.data()) pldm_msg;
116         uint16_t year = 0;
117         uint8_t month = 0;
118         uint8_t day = 0;
119         uint8_t hours = 0;
120         uint8_t minutes = 0;
121         uint8_t seconds = 0;
122 
123         if (!uintToDate(tmData, &year, &month, &day, &hours, &minutes,
124                         &seconds))
125         {
126             std::cerr << "decode date Error: "
127                       << "tmData=" << tmData << std::endl;
128 
129             return {PLDM_ERROR_INVALID_DATA, requestMsg};
130         }
131 
132         auto rc = encode_set_date_time_req(
133             instanceId, seconds, minutes, hours, day, month, year, request,
134             sizeof(struct pldm_set_date_time_req));
135 
136         return {rc, requestMsg};
137     }
138 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)139     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
140     {
141         uint8_t completionCode = 0;
142         auto rc = decode_set_date_time_resp(responsePtr, payloadLength,
143                                             &completionCode);
144 
145         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
146         {
147             std::cerr << "Response Message Error: "
148                       << "rc=" << rc << ",cc=" << (int)completionCode
149                       << std::endl;
150             return;
151         }
152 
153         ordered_json data;
154         data["Response"] = "SUCCESS";
155         pldmtool::helper::DisplayInJson(data);
156     }
157 
158   private:
159     uint64_t tmData;
160 };
161 
162 class GetBIOSTableHandler : public CommandInterface
163 {
164   public:
165     ~GetBIOSTableHandler() = default;
166     GetBIOSTableHandler() = delete;
167     GetBIOSTableHandler(const GetBIOSTableHandler&) = delete;
168     GetBIOSTableHandler(GetBIOSTableHandler&&) = delete;
169     GetBIOSTableHandler& operator=(const GetBIOSTableHandler&) = delete;
170     GetBIOSTableHandler& operator=(GetBIOSTableHandler&&) = delete;
171 
172     using Table = std::vector<uint8_t>;
173 
174     using CommandInterface::CommandInterface;
175 
176     static inline const std::map<pldm_bios_attribute_type, const char*>
177         attrTypeMap = {
178             {PLDM_BIOS_ENUMERATION, "BIOSEnumeration"},
179             {PLDM_BIOS_ENUMERATION_READ_ONLY, "BIOSEnumerationReadOnly"},
180             {PLDM_BIOS_STRING, "BIOSString"},
181             {PLDM_BIOS_STRING_READ_ONLY, "BIOSStringReadOnly"},
182             {PLDM_BIOS_PASSWORD, "BIOSPassword"},
183             {PLDM_BIOS_PASSWORD_READ_ONLY, "BIOSPasswordReadOnly"},
184             {PLDM_BIOS_INTEGER, "BIOSInteger"},
185             {PLDM_BIOS_INTEGER_READ_ONLY, "BIOSIntegerReadOnly"},
186 
187         };
188 
createRequestMsg()189     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
190     {
191         return {PLDM_ERROR, {}};
192     }
193 
parseResponseMsg(pldm_msg *,size_t)194     void parseResponseMsg(pldm_msg*, size_t) override {}
195 
getBIOSTable(pldm_bios_table_types tableType)196     std::optional<Table> getBIOSTable(pldm_bios_table_types tableType)
197     {
198         std::vector<uint8_t> requestMsg(
199             sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES);
200         auto request = new (requestMsg.data()) pldm_msg;
201 
202         auto rc = encode_get_bios_table_req(instanceId, 0, PLDM_GET_FIRSTPART,
203                                             tableType, request);
204         if (rc != PLDM_SUCCESS)
205         {
206             std::cerr << "Encode GetBIOSTable Error, tableType=," << tableType
207                       << " ,rc=" << rc << std::endl;
208             return std::nullopt;
209         }
210         std::vector<uint8_t> responseMsg;
211         rc = pldmSendRecv(requestMsg, responseMsg);
212         if (rc != PLDM_SUCCESS)
213         {
214             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
215             return std::nullopt;
216         }
217 
218         uint8_t cc = 0, transferFlag = 0;
219         uint32_t nextTransferHandle = 0;
220         size_t bios_table_offset;
221         auto responsePtr = new (responseMsg.data()) pldm_msg;
222         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
223 
224         rc = decode_get_bios_table_resp(responsePtr, payloadLength, &cc,
225                                         &nextTransferHandle, &transferFlag,
226                                         &bios_table_offset);
227 
228         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
229         {
230             std::cerr << "GetBIOSTable Response Error: tableType=" << tableType
231                       << ", rc=" << rc << ", cc=" << (int)cc << std::endl;
232             return std::nullopt;
233         }
234         auto tableData =
235             reinterpret_cast<char*>((responsePtr->payload) + bios_table_offset);
236         auto tableSize = payloadLength - sizeof(nextTransferHandle) -
237                          sizeof(transferFlag) - sizeof(cc);
238         return std::make_optional<Table>(tableData, tableData + tableSize);
239     }
240 
findAttrEntryByName(const std::string & name,const Table & attrTable,const Table & stringTable)241     const pldm_bios_attr_table_entry* findAttrEntryByName(
242         const std::string& name, const Table& attrTable,
243         const Table& stringTable)
244     {
245         auto stringEntry = pldm_bios_table_string_find_by_string(
246             stringTable.data(), stringTable.size(), name.c_str());
247         if (stringEntry == nullptr)
248         {
249             return nullptr;
250         }
251 
252         auto nameHandle =
253             pldm_bios_table_string_entry_decode_handle(stringEntry);
254 
255         for (auto attr : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable.data(),
256                                                              attrTable.size()))
257         {
258             auto attrNameHandle =
259                 pldm_bios_table_attr_entry_decode_string_handle(attr);
260             if (attrNameHandle == nameHandle)
261             {
262                 return attr;
263             }
264         }
265         return nullptr;
266     }
267 
findAttrHandleByName(const std::string & name,const Table & attrTable,const Table & stringTable)268     std::optional<uint16_t> findAttrHandleByName(const std::string& name,
269                                                  const Table& attrTable,
270                                                  const Table& stringTable)
271     {
272         auto attribute = findAttrEntryByName(name, attrTable, stringTable);
273         if (attribute == nullptr)
274         {
275             return std::nullopt;
276         }
277 
278         return pldm_bios_table_attr_entry_decode_attribute_handle(attribute);
279     }
280 
decodeStringFromStringEntry(const pldm_bios_string_table_entry * stringEntry)281     std::string decodeStringFromStringEntry(
282         const pldm_bios_string_table_entry* stringEntry)
283     {
284         auto strLength =
285             pldm_bios_table_string_entry_decode_string_length(stringEntry);
286         std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
287         // Preconditions are upheld therefore no error check necessary
288         pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
289                                                    buffer.size());
290 
291         return std::string(buffer.data(), buffer.data() + strLength);
292     }
293 
displayStringHandle(uint16_t handle,const std::optional<Table> & stringTable,bool displayHandle=true)294     std::string displayStringHandle(uint16_t handle,
295                                     const std::optional<Table>& stringTable,
296                                     bool displayHandle = true)
297     {
298         std::string displayString = std::to_string(handle);
299         if (!stringTable)
300         {
301             return displayString;
302         }
303         auto stringEntry = pldm_bios_table_string_find_by_handle(
304             stringTable->data(), stringTable->size(), handle);
305         if (stringEntry == nullptr)
306         {
307             return displayString;
308         }
309 
310         auto decodedStr = decodeStringFromStringEntry(stringEntry);
311         if (!displayHandle)
312         {
313             return decodedStr;
314         }
315 
316         return displayString + "(" + decodedStr + ")";
317     }
318 
displayEnumValueByIndex(uint16_t attrHandle,uint8_t index,const std::optional<Table> & attrTable,const std::optional<Table> & stringTable)319     std::string displayEnumValueByIndex(uint16_t attrHandle, uint8_t index,
320                                         const std::optional<Table>& attrTable,
321                                         const std::optional<Table>& stringTable)
322     {
323         std::string displayString;
324         if (!attrTable)
325         {
326             return displayString;
327         }
328 
329         auto attrEntry = pldm_bios_table_attr_find_by_handle(
330             attrTable->data(), attrTable->size(), attrHandle);
331         if (attrEntry == nullptr)
332         {
333             return displayString;
334         }
335         uint8_t pvNum;
336         int rc =
337             pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry, &pvNum);
338         if (rc != PLDM_SUCCESS)
339         {
340             return displayString;
341         }
342         std::vector<uint16_t> pvHandls(pvNum);
343         // Preconditions are upheld therefore no error check necessary
344         pldm_bios_table_attr_entry_enum_decode_pv_hdls(
345             attrEntry, pvHandls.data(), pvHandls.size());
346         return displayStringHandle(pvHandls[index], stringTable, false);
347     }
348 
displayAttributeValueEntry(const pldm_bios_attr_val_table_entry * tableEntry,const std::optional<Table> & attrTable,const std::optional<Table> & stringTable,bool verbose,ordered_json & output)349     void displayAttributeValueEntry(
350         const pldm_bios_attr_val_table_entry* tableEntry,
351         const std::optional<Table>& attrTable,
352         const std::optional<Table>& stringTable, bool verbose,
353         ordered_json& output)
354     {
355         auto attrHandle =
356             pldm_bios_table_attr_value_entry_decode_attribute_handle(
357                 tableEntry);
358         auto attrType = static_cast<pldm_bios_attribute_type>(
359             pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
360 
361         if (verbose)
362         {
363             output["AttributeHandle"] = attrHandle;
364             if (attrTypeMap.contains(attrType))
365             {
366                 output["AttributeType"] = attrTypeMap.at(attrType);
367             }
368             else
369             {
370                 std::cout << "Get AttributeType failed.\n";
371             }
372         }
373         switch (attrType)
374         {
375             case PLDM_BIOS_ENUMERATION:
376             case PLDM_BIOS_ENUMERATION_READ_ONLY:
377             {
378                 auto count =
379                     pldm_bios_table_attr_value_entry_enum_decode_number(
380                         tableEntry);
381                 std::vector<uint8_t> handles(count);
382                 pldm_bios_table_attr_value_entry_enum_decode_handles(
383                     tableEntry, handles.data(), handles.size());
384                 if (verbose)
385                 {
386                     output["NumberOfCurrentValues"] = (int)count;
387                 }
388                 for (size_t i = 0; i < handles.size(); i++)
389                 {
390                     if (verbose)
391                     {
392                         output["CurrentValueStringHandleIndex[" +
393                                std::to_string(i) + "]"] =
394                             displayEnumValueByIndex(attrHandle, handles[i],
395                                                     attrTable, stringTable);
396                     }
397                     else
398                     {
399                         output["CurrentValue"] = displayEnumValueByIndex(
400                             attrHandle, handles[i], attrTable, stringTable);
401                     }
402                 }
403                 break;
404             }
405             case PLDM_BIOS_INTEGER:
406             case PLDM_BIOS_INTEGER_READ_ONLY:
407             {
408                 auto cv = pldm_bios_table_attr_value_entry_integer_decode_cv(
409                     tableEntry);
410                 output["CurrentValue"] = cv;
411                 break;
412             }
413             case PLDM_BIOS_STRING:
414             case PLDM_BIOS_STRING_READ_ONLY:
415             {
416                 variable_field currentString;
417                 pldm_bios_table_attr_value_entry_string_decode_string(
418                     tableEntry, &currentString);
419                 if (verbose)
420                 {
421                     output["CurrentStringLength"] = currentString.length;
422                     output["CurrentString"] = std::string(
423                         reinterpret_cast<const char*>(currentString.ptr),
424                         currentString.length);
425                 }
426                 else
427                 {
428                     output["CurrentValue"] = std::string(
429                         reinterpret_cast<const char*>(currentString.ptr),
430                         currentString.length);
431                 }
432 
433                 break;
434             }
435             case PLDM_BIOS_PASSWORD:
436             case PLDM_BIOS_PASSWORD_READ_ONLY:
437             {
438                 std::cout << "Password attribute: Not Supported" << std::endl;
439                 break;
440             }
441         }
442     }
443 };
444 
445 class GetBIOSTable : public GetBIOSTableHandler
446 {
447   public:
448     ~GetBIOSTable() = default;
449     GetBIOSTable() = delete;
450     GetBIOSTable(const GetBIOSTable&) = delete;
451     GetBIOSTable(GetBIOSTable&&) = delete;
452     GetBIOSTable& operator=(const GetBIOSTable&) = delete;
453     GetBIOSTable& operator=(GetBIOSTable&&) = delete;
454 
455     using Table = std::vector<uint8_t>;
456 
GetBIOSTable(const char * type,const char * name,CLI::App * app)457     explicit GetBIOSTable(const char* type, const char* name, CLI::App* app) :
458         GetBIOSTableHandler(type, name, app)
459     {
460         app->add_option("-t,--type", pldmBIOSTableType, "pldm bios table type")
461             ->required()
462             ->transform(
463                 CLI::CheckedTransformer(pldmBIOSTableTypes, CLI::ignore_case));
464     }
465 
exec()466     void exec() override
467     {
468         switch (pldmBIOSTableType)
469         {
470             case PLDM_BIOS_STRING_TABLE:
471             {
472                 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
473                 decodeStringTable(stringTable);
474                 break;
475             }
476             case PLDM_BIOS_ATTR_TABLE:
477             {
478                 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
479                 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
480 
481                 decodeAttributeTable(attrTable, stringTable);
482                 break;
483             }
484             case PLDM_BIOS_ATTR_VAL_TABLE:
485             {
486                 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
487                 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
488                 auto attrValTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
489 
490                 decodeAttributeValueTable(attrValTable, attrTable, stringTable);
491                 break;
492             }
493         }
494     }
495 
496   private:
497     pldm_bios_table_types pldmBIOSTableType;
498 
decodeStringTable(const std::optional<Table> & stringTable)499     void decodeStringTable(const std::optional<Table>& stringTable)
500     {
501         if (!stringTable)
502         {
503             std::cerr << "GetBIOSStringTable Error" << std::endl;
504             return;
505         }
506         ordered_json stringdata;
507 
508         for (auto tableEntry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>(
509                  stringTable->data(), stringTable->size()))
510         {
511             auto strHandle =
512                 pldm_bios_table_string_entry_decode_handle(tableEntry);
513             auto strTableData = decodeStringFromStringEntry(tableEntry);
514             stringdata[std::to_string(strHandle)] = strTableData;
515         }
516         pldmtool::helper::DisplayInJson(stringdata);
517     }
decodeAttributeTable(const std::optional<Table> & attrTable,const std::optional<Table> & stringTable)518     void decodeAttributeTable(const std::optional<Table>& attrTable,
519                               const std::optional<Table>& stringTable)
520     {
521         if (!stringTable)
522         {
523             std::cerr << "GetBIOSAttributeTable Error" << std::endl;
524             return;
525         }
526         ordered_json output;
527 
528         for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
529                  attrTable->data(), attrTable->size()))
530         {
531             ordered_json attrdata;
532 
533             auto attrHandle =
534                 pldm_bios_table_attr_entry_decode_attribute_handle(entry);
535             auto attrNameHandle =
536                 pldm_bios_table_attr_entry_decode_string_handle(entry);
537             auto attrType = static_cast<pldm_bios_attribute_type>(
538                 pldm_bios_table_attr_entry_decode_attribute_type(entry));
539 
540             attrdata["AttributeHandle"] = attrHandle;
541             attrdata["AttributeNameHandle"] =
542                 displayStringHandle(attrNameHandle, stringTable);
543             if (attrTypeMap.contains(attrType))
544             {
545                 attrdata["AttributeType"] = attrTypeMap.at(attrType);
546             }
547             else
548             {
549                 std::cout << "Get AttributeType failed.\n";
550             }
551 
552             switch (attrType)
553             {
554                 case PLDM_BIOS_ENUMERATION:
555                 case PLDM_BIOS_ENUMERATION_READ_ONLY:
556                 {
557                     uint8_t pvNum;
558                     // Preconditions are upheld therefore no error check
559                     // necessary
560                     pldm_bios_table_attr_entry_enum_decode_pv_num(entry,
561                                                                   &pvNum);
562                     std::vector<uint16_t> pvHandls(pvNum);
563                     // Preconditions are upheld therefore no error check
564                     // necessary
565                     pldm_bios_table_attr_entry_enum_decode_pv_hdls(
566                         entry, pvHandls.data(), pvHandls.size());
567                     uint8_t defNum;
568                     // Preconditions are upheld therefore no error check
569                     // necessary
570                     pldm_bios_table_attr_entry_enum_decode_def_num(entry,
571                                                                    &defNum);
572                     std::vector<uint8_t> defIndices(defNum);
573                     pldm_bios_table_attr_entry_enum_decode_def_indices(
574                         entry, defIndices.data(), defIndices.size());
575 
576                     attrdata["NumberOfPossibleValues"] = (int)pvNum;
577 
578                     for (size_t i = 0; i < pvHandls.size(); i++)
579                     {
580                         attrdata["PossibleValueStringHandle[" +
581                                  std::to_string(i) + "]"] =
582                             displayStringHandle(pvHandls[i], stringTable);
583                     }
584                     attrdata["NumberOfDefaultValues"] = (int)defNum;
585                     for (size_t i = 0; i < defIndices.size(); i++)
586                     {
587                         attrdata["DefaultValueStringHandleIndex[" +
588                                  std::to_string(i) + "]"] = (int)defIndices[i];
589                         attrdata["DefaultValueStringHandle"] =
590                             displayStringHandle(pvHandls[defIndices[i]],
591                                                 stringTable);
592                     }
593                     break;
594                 }
595                 case PLDM_BIOS_INTEGER:
596                 case PLDM_BIOS_INTEGER_READ_ONLY:
597                 {
598                     uint64_t lower, upper, def;
599                     uint32_t scalar;
600                     pldm_bios_table_attr_entry_integer_decode(
601                         entry, &lower, &upper, &scalar, &def);
602                     attrdata["LowerBound"] = lower;
603                     attrdata["UpperBound"] = upper;
604                     attrdata["ScalarIncrement"] = scalar;
605                     attrdata["DefaultValue"] = def;
606                     break;
607                 }
608                 case PLDM_BIOS_STRING:
609                 case PLDM_BIOS_STRING_READ_ONLY:
610                 {
611                     auto strType =
612                         pldm_bios_table_attr_entry_string_decode_string_type(
613                             entry);
614                     auto min =
615                         pldm_bios_table_attr_entry_string_decode_min_length(
616                             entry);
617                     auto max =
618                         pldm_bios_table_attr_entry_string_decode_max_length(
619                             entry);
620                     uint16_t def;
621                     // Preconditions are upheld therefore no error check
622                     // necessary
623                     pldm_bios_table_attr_entry_string_decode_def_string_length(
624                         entry, &def);
625                     std::vector<char> defString(def + 1);
626                     pldm_bios_table_attr_entry_string_decode_def_string(
627                         entry, defString.data(), defString.size());
628 
629                     std::stringstream stringtype;
630                     stringtype
631                         << "0x" << std::hex << std::setw(2) << std::setfill('0')
632                         << (int)strType << std::dec << std::setw(0);
633                     attrdata["StringType"] = stringtype.str();
634                     attrdata["MinimumStringLength"] = (int)min;
635                     attrdata["MaximumStringLength"] = (int)max;
636                     attrdata["DefaultStringLength"] = (int)def;
637                     attrdata["DefaultString"] = defString.data();
638                     break;
639                 }
640                 case PLDM_BIOS_PASSWORD:
641                 case PLDM_BIOS_PASSWORD_READ_ONLY:
642                     std::cout
643                         << "Password attribute: Not Supported" << std::endl;
644             }
645             output.emplace_back(std::move(attrdata));
646         }
647         pldmtool::helper::DisplayInJson(output);
648     }
decodeAttributeValueTable(const std::optional<Table> & attrValTable,const std::optional<Table> & attrTable,const std::optional<Table> & stringTable)649     void decodeAttributeValueTable(const std::optional<Table>& attrValTable,
650                                    const std::optional<Table>& attrTable,
651                                    const std::optional<Table>& stringTable)
652     {
653         if (!attrValTable)
654         {
655             std::cerr << "GetBIOSAttributeValueTable Error" << std::endl;
656             return;
657         }
658         ordered_json output;
659         for (auto tableEntry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
660                  attrValTable->data(), attrValTable->size()))
661         {
662             ordered_json attrValueData;
663             displayAttributeValueEntry(tableEntry, attrTable, stringTable, true,
664                                        attrValueData);
665             output.emplace_back(attrValueData);
666         }
667         pldmtool::helper::DisplayInJson(output);
668     }
669 };
670 
671 class GetBIOSAttributeCurrentValueByHandle : public GetBIOSTableHandler
672 {
673   public:
674     ~GetBIOSAttributeCurrentValueByHandle() = default;
675     GetBIOSAttributeCurrentValueByHandle(
676         const GetBIOSAttributeCurrentValueByHandle&) = delete;
677     GetBIOSAttributeCurrentValueByHandle(
678         GetBIOSAttributeCurrentValueByHandle&&) = delete;
679     GetBIOSAttributeCurrentValueByHandle& operator=(
680         const GetBIOSAttributeCurrentValueByHandle&) = delete;
681     GetBIOSAttributeCurrentValueByHandle& operator=(
682         GetBIOSAttributeCurrentValueByHandle&&) = delete;
683 
GetBIOSAttributeCurrentValueByHandle(const char * type,const char * name,CLI::App * app)684     explicit GetBIOSAttributeCurrentValueByHandle(
685         const char* type, const char* name, CLI::App* app) :
686         GetBIOSTableHandler(type, name, app)
687     {
688         app->add_option("-a, --attribute", attrName, "pldm BIOS attribute name")
689             ->required();
690     }
691 
exec()692     void exec()
693     {
694         auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
695         auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
696 
697         if (!stringTable || !attrTable)
698         {
699             std::cout << "StringTable/AttrTable Unavailable" << std::endl;
700             return;
701         }
702 
703         auto handle = findAttrHandleByName(attrName, *attrTable, *stringTable);
704         if (!handle)
705         {
706             std::cerr << "Can not find the attribute " << attrName << std::endl;
707             return;
708         }
709 
710         std::vector<uint8_t> requestMsg(
711             sizeof(pldm_msg_hdr) +
712             PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES);
713         auto request = new (requestMsg.data()) pldm_msg;
714 
715         auto rc = encode_get_bios_attribute_current_value_by_handle_req(
716             instanceId, 0, PLDM_GET_FIRSTPART, *handle, request);
717         if (rc != PLDM_SUCCESS)
718         {
719             std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
720             return;
721         }
722 
723         std::vector<uint8_t> responseMsg;
724         rc = pldmSendRecv(requestMsg, responseMsg);
725         if (rc != PLDM_SUCCESS)
726         {
727             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
728             return;
729         }
730 
731         uint8_t cc = 0, transferFlag = 0;
732         uint32_t nextTransferHandle = 0;
733         struct variable_field attributeData;
734         auto responsePtr = new (responseMsg.data()) pldm_msg;
735         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
736 
737         rc = decode_get_bios_attribute_current_value_by_handle_resp(
738             responsePtr, payloadLength, &cc, &nextTransferHandle, &transferFlag,
739             &attributeData);
740         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
741         {
742             std::cerr << "Response Message Error: "
743                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
744             return;
745         }
746 
747         auto tableEntry =
748             reinterpret_cast<const struct pldm_bios_attr_val_table_entry*>(
749                 attributeData.ptr);
750 
751         ordered_json avdata;
752         displayAttributeValueEntry(tableEntry, attrTable, stringTable, false,
753                                    avdata);
754         pldmtool::helper::DisplayInJson(avdata);
755     }
756 
757   private:
758     std::string attrName;
759 };
760 
761 class SetBIOSAttributeCurrentValue : public GetBIOSTableHandler
762 {
763   public:
764     ~SetBIOSAttributeCurrentValue() = default;
765     SetBIOSAttributeCurrentValue() = delete;
766     SetBIOSAttributeCurrentValue(const SetBIOSAttributeCurrentValue&) = delete;
767     SetBIOSAttributeCurrentValue(SetBIOSAttributeCurrentValue&&) = delete;
768     SetBIOSAttributeCurrentValue& operator=(
769         const SetBIOSAttributeCurrentValue&) = delete;
770     SetBIOSAttributeCurrentValue& operator=(SetBIOSAttributeCurrentValue&&) =
771         delete;
772 
SetBIOSAttributeCurrentValue(const char * type,const char * name,CLI::App * app)773     explicit SetBIOSAttributeCurrentValue(const char* type, const char* name,
774                                           CLI::App* app) :
775         GetBIOSTableHandler(type, name, app)
776     {
777         app->add_option("-a, --attribute", attrName, "pldm attribute name")
778             ->required();
779         app->add_option("-d, --data", attrValue, "pldm attribute value")
780             ->required();
781         // -v is conflict with --verbose in class CommandInterface, so used -d
782     }
783 
exec()784     void exec()
785     {
786         auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
787         auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
788         auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
789 
790         if (!stringTable || !attrTable)
791         {
792             std::cout << "StringTable/AttrTable Unavailable" << std::endl;
793             return;
794         }
795 
796         auto attrEntry =
797             findAttrEntryByName(attrName, *attrTable, *stringTable);
798         if (attrEntry == nullptr)
799         {
800             std::cout << "Could not find attribute :" << attrName << std::endl;
801             return;
802         }
803 
804         std::vector<uint8_t> requestMsg;
805 
806         int rc = 0;
807         auto attrType = attrEntry->attr_type;
808         size_t entryLength = 1;
809         std::vector<uint8_t> attrValueEntry(entryLength, 0);
810 
811         switch (attrType)
812         {
813             case PLDM_BIOS_ENUMERATION:
814             case PLDM_BIOS_ENUMERATION_READ_ONLY:
815             {
816                 entryLength =
817                     pldm_bios_table_attr_value_entry_encode_enum_length(1);
818                 uint8_t pvNum;
819                 // Preconditions are upheld therefore no error check necessary
820                 pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry,
821                                                               &pvNum);
822                 std::vector<uint16_t> pvHdls(pvNum, 0);
823                 // Preconditions are upheld therefore no error check necessary
824                 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
825                     attrEntry, pvHdls.data(), pvNum);
826                 auto stringEntry = pldm_bios_table_string_find_by_string(
827                     stringTable->data(), stringTable->size(),
828                     attrValue.c_str());
829                 if (stringEntry == nullptr)
830                 {
831                     std::cout
832                         << "Set Attribute Error: It's not a possible value"
833                         << std::endl;
834                     return;
835                 }
836                 auto valueHandle =
837                     pldm_bios_table_string_entry_decode_handle(stringEntry);
838 
839                 uint8_t i;
840                 for (i = 0; i < pvNum; i++)
841                 {
842                     if (valueHandle == pvHdls[i])
843                         break;
844                 }
845                 if (i == pvNum)
846                 {
847                     std::cout
848                         << "Set Attribute Error: It's not a possible value"
849                         << std::endl;
850                     return;
851                 }
852 
853                 attrValueEntry.resize(entryLength);
854                 std::vector<uint8_t> handles = {i};
855                 int rc = pldm_bios_table_attr_value_entry_encode_enum(
856                     attrValueEntry.data(), attrValueEntry.size(),
857                     attrEntry->attr_handle, attrType, 1, handles.data());
858                 if (rc != PLDM_SUCCESS)
859                 {
860                     std::cout
861                         << "Failed to encode BIOS table attribute enum: " << rc
862                         << std::endl;
863                     return;
864                 }
865                 break;
866             }
867             case PLDM_BIOS_STRING:
868             case PLDM_BIOS_STRING_READ_ONLY:
869             {
870                 entryLength =
871                     pldm_bios_table_attr_value_entry_encode_string_length(
872                         attrValue.size());
873 
874                 attrValueEntry.resize(entryLength);
875 
876                 int rc = pldm_bios_table_attr_value_entry_encode_string(
877                     attrValueEntry.data(), entryLength, attrEntry->attr_handle,
878                     attrType, attrValue.size(), attrValue.c_str());
879                 if (rc != PLDM_SUCCESS)
880                 {
881                     std::cout
882                         << "Failed to encode BIOS table attribute string: "
883                         << rc << std::endl;
884                     return;
885                 }
886                 break;
887             }
888             case PLDM_BIOS_INTEGER:
889             case PLDM_BIOS_INTEGER_READ_ONLY:
890             {
891                 uint64_t value = std::stoll(attrValue);
892                 entryLength =
893                     pldm_bios_table_attr_value_entry_encode_integer_length();
894                 attrValueEntry.resize(entryLength);
895                 int rc = pldm_bios_table_attr_value_entry_encode_integer(
896                     attrValueEntry.data(), entryLength, attrEntry->attr_handle,
897                     attrType, value);
898                 if (rc != PLDM_SUCCESS)
899                 {
900                     std::cout
901                         << "Failed to encode BIOS table attribute integer: "
902                         << rc << std::endl;
903                     return;
904                 }
905                 break;
906             }
907         }
908 
909         requestMsg.resize(entryLength + sizeof(pldm_msg_hdr) +
910                           PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES);
911 
912         rc = encode_set_bios_attribute_current_value_req(
913             instanceId, 0, PLDM_START_AND_END, attrValueEntry.data(),
914             attrValueEntry.size(), new (requestMsg.data()) pldm_msg,
915             requestMsg.size() - sizeof(pldm_msg_hdr));
916 
917         if (rc != PLDM_SUCCESS)
918         {
919             std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
920             return;
921         }
922         std::vector<uint8_t> responseMsg;
923         rc = pldmSendRecv(requestMsg, responseMsg);
924         if (rc != PLDM_SUCCESS)
925         {
926             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
927             return;
928         }
929         uint8_t cc = 0;
930         uint32_t nextTransferHandle = 0;
931         auto responsePtr = new (responseMsg.data()) pldm_msg;
932         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
933 
934         rc = decode_set_bios_attribute_current_value_resp(
935             responsePtr, payloadLength, &cc, &nextTransferHandle);
936         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
937         {
938             std::cerr << "Response Message Error: "
939                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
940             return;
941         }
942 
943         ordered_json data;
944         data["Response"] = "SUCCESS";
945         pldmtool::helper::DisplayInJson(data);
946     }
947 
948   private:
949     std::string attrName;
950     std::string attrValue;
951 };
952 
registerCommand(CLI::App & app)953 void registerCommand(CLI::App& app)
954 {
955     auto bios = app.add_subcommand("bios", "bios type command");
956     bios->require_subcommand(1);
957     auto getDateTime = bios->add_subcommand("GetDateTime", "get date time");
958     commands.push_back(
959         std::make_unique<GetDateTime>("bios", "GetDateTime", getDateTime));
960 
961     auto setDateTime =
962         bios->add_subcommand("SetDateTime", "set host date time");
963     commands.push_back(
964         std::make_unique<SetDateTime>("bios", "setDateTime", setDateTime));
965 
966     auto getBIOSTable = bios->add_subcommand("GetBIOSTable", "get bios table");
967     commands.push_back(
968         std::make_unique<GetBIOSTable>("bios", "GetBIOSTable", getBIOSTable));
969 
970     auto getBIOSAttributeCurrentValueByHandle =
971         bios->add_subcommand("GetBIOSAttributeCurrentValueByHandle",
972                              "get bios attribute current value by handle");
973     commands.push_back(std::make_unique<GetBIOSAttributeCurrentValueByHandle>(
974         "bios", "GetBIOSAttributeCurrentValueByHandle",
975         getBIOSAttributeCurrentValueByHandle));
976 
977     auto setBIOSAttributeCurrentValue = bios->add_subcommand(
978         "SetBIOSAttributeCurrentValue", "set bios attribute current value");
979     commands.push_back(std::make_unique<SetBIOSAttributeCurrentValue>(
980         "bios", "SetBIOSAttributeCurrentValue", setBIOSAttributeCurrentValue));
981 }
982 
983 } // namespace bios
984 
985 } // namespace pldmtool
986