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