xref: /openbmc/pldm/pldmtool/pldm_bios_cmd.cpp (revision 6da4f91b)
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&&) = default;
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&&) = default;
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         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 
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 
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         auto pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
336         std::vector<uint16_t> pvHandls(pvNum);
337         pldm_bios_table_attr_entry_enum_decode_pv_hdls(
338             attrEntry, pvHandls.data(), pvHandls.size());
339         return displayStringHandle(pvHandls[index], stringTable, false);
340     }
341 
342     void displayAttributeValueEntry(
343         const pldm_bios_attr_val_table_entry* tableEntry,
344         const std::optional<Table>& attrTable,
345         const std::optional<Table>& stringTable, bool verbose,
346         ordered_json& output)
347     {
348         auto attrHandle =
349             pldm_bios_table_attr_value_entry_decode_attribute_handle(
350                 tableEntry);
351         auto attrType = static_cast<pldm_bios_attribute_type>(
352             pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
353 
354         if (verbose)
355         {
356             output["AttributeHandle"] = attrHandle;
357             if (attrTypeMap.contains(attrType))
358             {
359                 output["AttributeType"] = attrTypeMap.at(attrType);
360             }
361             else
362             {
363                 std::cout << "Get AttributeType failed.\n";
364             }
365         }
366         switch (attrType)
367         {
368             case PLDM_BIOS_ENUMERATION:
369             case PLDM_BIOS_ENUMERATION_READ_ONLY:
370             {
371                 auto count =
372                     pldm_bios_table_attr_value_entry_enum_decode_number(
373                         tableEntry);
374                 std::vector<uint8_t> handles(count);
375                 pldm_bios_table_attr_value_entry_enum_decode_handles(
376                     tableEntry, handles.data(), handles.size());
377                 if (verbose)
378                 {
379                     output["NumberOfCurrentValues"] = (int)count;
380                 }
381                 for (size_t i = 0; i < handles.size(); i++)
382                 {
383                     if (verbose)
384                     {
385                         output["CurrentValueStringHandleIndex[" +
386                                std::to_string(i) + "]"] =
387                             displayEnumValueByIndex(attrHandle, handles[i],
388                                                     attrTable, stringTable);
389                     }
390                     else
391                     {
392                         output["CurrentValue"] = displayEnumValueByIndex(
393                             attrHandle, handles[i], attrTable, stringTable);
394                     }
395                 }
396                 break;
397             }
398             case PLDM_BIOS_INTEGER:
399             case PLDM_BIOS_INTEGER_READ_ONLY:
400             {
401                 auto cv = pldm_bios_table_attr_value_entry_integer_decode_cv(
402                     tableEntry);
403                 if (verbose)
404                 {
405                     output["CurrentValue"] = cv;
406                 }
407                 else
408                 {
409                     output["CurrentValue"] = cv;
410                 }
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&&) = default;
452     GetBIOSTable& operator=(const GetBIOSTable&) = delete;
453     GetBIOSTable& operator=(GetBIOSTable&&) = default;
454 
455     using Table = std::vector<uint8_t>;
456 
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 
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 
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     }
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                     auto pvNum =
558                         pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
559                     std::vector<uint16_t> pvHandls(pvNum);
560                     pldm_bios_table_attr_entry_enum_decode_pv_hdls(
561                         entry, pvHandls.data(), pvHandls.size());
562                     auto defNum =
563                         pldm_bios_table_attr_entry_enum_decode_def_num(entry);
564                     std::vector<uint8_t> defIndices(defNum);
565                     pldm_bios_table_attr_entry_enum_decode_def_indices(
566                         entry, defIndices.data(), defIndices.size());
567 
568                     attrdata["NumberOfPossibleValues"] = (int)pvNum;
569 
570                     for (size_t i = 0; i < pvHandls.size(); i++)
571                     {
572                         attrdata["PossibleValueStringHandle[" +
573                                  std::to_string(i) + "]"] =
574                             displayStringHandle(pvHandls[i], stringTable);
575                     }
576                     attrdata["NumberOfDefaultValues"] = (int)defNum;
577                     for (size_t i = 0; i < defIndices.size(); i++)
578                     {
579                         attrdata["DefaultValueStringHandleIndex[" +
580                                  std::to_string(i) + "]"] = (int)defIndices[i];
581                         attrdata["DefaultValueStringHandle"] =
582                             displayStringHandle(pvHandls[defIndices[i]],
583                                                 stringTable);
584                     }
585                     break;
586                 }
587                 case PLDM_BIOS_INTEGER:
588                 case PLDM_BIOS_INTEGER_READ_ONLY:
589                 {
590                     uint64_t lower, upper, def;
591                     uint32_t scalar;
592                     pldm_bios_table_attr_entry_integer_decode(
593                         entry, &lower, &upper, &scalar, &def);
594                     attrdata["LowerBound"] = lower;
595                     attrdata["UpperBound"] = upper;
596                     attrdata["ScalarIncrement"] = scalar;
597                     attrdata["DefaultValue"] = def;
598                     break;
599                 }
600                 case PLDM_BIOS_STRING:
601                 case PLDM_BIOS_STRING_READ_ONLY:
602                 {
603                     auto strType =
604                         pldm_bios_table_attr_entry_string_decode_string_type(
605                             entry);
606                     auto min =
607                         pldm_bios_table_attr_entry_string_decode_min_length(
608                             entry);
609                     auto max =
610                         pldm_bios_table_attr_entry_string_decode_max_length(
611                             entry);
612                     auto def =
613                         pldm_bios_table_attr_entry_string_decode_def_string_length(
614                             entry);
615                     std::vector<char> defString(def + 1);
616                     pldm_bios_table_attr_entry_string_decode_def_string(
617                         entry, defString.data(), defString.size());
618 
619                     std::stringstream stringtype;
620                     stringtype << "0x" << std::hex << std::setw(2)
621                                << std::setfill('0') << (int)strType << std::dec
622                                << std::setw(0);
623                     attrdata["StringType"] = stringtype.str();
624                     attrdata["MinimumStringLength"] = (int)min;
625                     attrdata["MaximumStringLength"] = (int)max;
626                     attrdata["DefaultStringLength"] = (int)def;
627                     attrdata["DefaultString"] = defString.data();
628                     break;
629                 }
630                 case PLDM_BIOS_PASSWORD:
631                 case PLDM_BIOS_PASSWORD_READ_ONLY:
632                     std::cout << "Password attribute: Not Supported"
633                               << std::endl;
634             }
635             output.emplace_back(std::move(attrdata));
636         }
637         pldmtool::helper::DisplayInJson(output);
638     }
639     void decodeAttributeValueTable(const std::optional<Table>& attrValTable,
640                                    const std::optional<Table>& attrTable,
641                                    const std::optional<Table>& stringTable)
642     {
643         if (!attrValTable)
644         {
645             std::cerr << "GetBIOSAttributeValueTable Error" << std::endl;
646             return;
647         }
648         ordered_json output;
649         for (auto tableEntry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
650                  attrValTable->data(), attrValTable->size()))
651         {
652             ordered_json attrValueData;
653             displayAttributeValueEntry(tableEntry, attrTable, stringTable, true,
654                                        attrValueData);
655             output.emplace_back(attrValueData);
656         }
657         pldmtool::helper::DisplayInJson(output);
658     }
659 };
660 
661 class GetBIOSAttributeCurrentValueByHandle : public GetBIOSTableHandler
662 {
663   public:
664     ~GetBIOSAttributeCurrentValueByHandle() = default;
665     GetBIOSAttributeCurrentValueByHandle(
666         const GetBIOSAttributeCurrentValueByHandle&) = delete;
667     GetBIOSAttributeCurrentValueByHandle(
668         GetBIOSAttributeCurrentValueByHandle&&) = delete;
669     GetBIOSAttributeCurrentValueByHandle&
670         operator=(const GetBIOSAttributeCurrentValueByHandle&) = delete;
671     GetBIOSAttributeCurrentValueByHandle&
672         operator=(GetBIOSAttributeCurrentValueByHandle&&) = delete;
673 
674     explicit GetBIOSAttributeCurrentValueByHandle(const char* type,
675                                                   const char* name,
676                                                   CLI::App* app) :
677         GetBIOSTableHandler(type, name, app)
678     {
679         app->add_option("-a, --attribute", attrName, "pldm BIOS attribute name")
680             ->required();
681     }
682 
683     void exec()
684     {
685         auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
686         auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
687 
688         if (!stringTable || !attrTable)
689         {
690             std::cout << "StringTable/AttrTable Unavaliable" << std::endl;
691             return;
692         }
693 
694         auto handle = findAttrHandleByName(attrName, *attrTable, *stringTable);
695         if (!handle)
696         {
697             std::cerr << "Can not find the attribute " << attrName << std::endl;
698             return;
699         }
700 
701         std::vector<uint8_t> requestMsg(
702             sizeof(pldm_msg_hdr) +
703             PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES);
704         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
705 
706         auto rc = encode_get_bios_attribute_current_value_by_handle_req(
707             instanceId, 0, PLDM_GET_FIRSTPART, *handle, request);
708         if (rc != PLDM_SUCCESS)
709         {
710             std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
711             return;
712         }
713 
714         std::vector<uint8_t> responseMsg;
715         rc = pldmSendRecv(requestMsg, responseMsg);
716         if (rc != PLDM_SUCCESS)
717         {
718             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
719             return;
720         }
721 
722         uint8_t cc = 0, transferFlag = 0;
723         uint32_t nextTransferHandle = 0;
724         struct variable_field attributeData;
725         auto responsePtr =
726             reinterpret_cast<struct pldm_msg*>(responseMsg.data());
727         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
728 
729         rc = decode_get_bios_attribute_current_value_by_handle_resp(
730             responsePtr, payloadLength, &cc, &nextTransferHandle, &transferFlag,
731             &attributeData);
732         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
733         {
734             std::cerr << "Response Message Error: "
735                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
736             return;
737         }
738 
739         auto tableEntry =
740             reinterpret_cast<const struct pldm_bios_attr_val_table_entry*>(
741                 attributeData.ptr);
742 
743         ordered_json avdata;
744         displayAttributeValueEntry(tableEntry, attrTable, stringTable, false,
745                                    avdata);
746         pldmtool::helper::DisplayInJson(avdata);
747     }
748 
749   private:
750     std::string attrName;
751 };
752 
753 class SetBIOSAttributeCurrentValue : public GetBIOSTableHandler
754 {
755   public:
756     ~SetBIOSAttributeCurrentValue() = default;
757     SetBIOSAttributeCurrentValue() = delete;
758     SetBIOSAttributeCurrentValue(const SetBIOSAttributeCurrentValue&) = delete;
759     SetBIOSAttributeCurrentValue(SetBIOSAttributeCurrentValue&&) = default;
760     SetBIOSAttributeCurrentValue&
761         operator=(const SetBIOSAttributeCurrentValue&) = delete;
762     SetBIOSAttributeCurrentValue&
763         operator=(SetBIOSAttributeCurrentValue&&) = default;
764 
765     explicit SetBIOSAttributeCurrentValue(const char* type, const char* name,
766                                           CLI::App* app) :
767         GetBIOSTableHandler(type, name, app)
768     {
769         app->add_option("-a, --attribute", attrName, "pldm attribute name")
770             ->required();
771         app->add_option("-d, --data", attrValue, "pldm attribute value")
772             ->required();
773         // -v is conflict with --verbose in class CommandInterface, so used -d
774     }
775 
776     void exec()
777     {
778         auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
779         auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
780         auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
781 
782         if (!stringTable || !attrTable)
783         {
784             std::cout << "StringTable/AttrTable Unavaliable" << std::endl;
785             return;
786         }
787 
788         auto attrEntry = findAttrEntryByName(attrName, *attrTable,
789                                              *stringTable);
790         if (attrEntry == nullptr)
791         {
792             std::cout << "Could not find attribute :" << attrName << std::endl;
793             return;
794         }
795 
796         std::vector<uint8_t> requestMsg;
797 
798         int rc = 0;
799         auto attrType = attrEntry->attr_type;
800         size_t entryLength = 1;
801         std::vector<uint8_t> attrValueEntry(entryLength, 0);
802 
803         switch (attrType)
804         {
805             case PLDM_BIOS_ENUMERATION:
806             case PLDM_BIOS_ENUMERATION_READ_ONLY:
807             {
808                 entryLength =
809                     pldm_bios_table_attr_value_entry_encode_enum_length(1);
810                 auto pvNum =
811                     pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
812                 std::vector<uint16_t> pvHdls(pvNum, 0);
813                 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
814                     attrEntry, pvHdls.data(), pvNum);
815                 auto stringEntry = pldm_bios_table_string_find_by_string(
816                     stringTable->data(), stringTable->size(),
817                     attrValue.c_str());
818                 if (stringEntry == nullptr)
819                 {
820                     std::cout
821                         << "Set Attribute Error: It's not a possible value"
822                         << std::endl;
823                     return;
824                 }
825                 auto valueHandle =
826                     pldm_bios_table_string_entry_decode_handle(stringEntry);
827 
828                 uint8_t i;
829                 for (i = 0; i < pvNum; i++)
830                 {
831                     if (valueHandle == pvHdls[i])
832                         break;
833                 }
834                 if (i == pvNum)
835                 {
836                     std::cout
837                         << "Set Attribute Error: It's not a possible value"
838                         << std::endl;
839                     return;
840                 }
841 
842                 attrValueEntry.resize(entryLength);
843                 std::vector<uint8_t> handles = {i};
844                 pldm_bios_table_attr_value_entry_encode_enum(
845                     attrValueEntry.data(), attrValueEntry.size(),
846                     attrEntry->attr_handle, attrType, 1, handles.data());
847                 break;
848             }
849             case PLDM_BIOS_STRING:
850             case PLDM_BIOS_STRING_READ_ONLY:
851             {
852                 entryLength =
853                     pldm_bios_table_attr_value_entry_encode_string_length(
854                         attrValue.size());
855 
856                 attrValueEntry.resize(entryLength);
857 
858                 pldm_bios_table_attr_value_entry_encode_string(
859                     attrValueEntry.data(), entryLength, attrEntry->attr_handle,
860                     attrType, attrValue.size(), attrValue.c_str());
861                 break;
862             }
863             case PLDM_BIOS_INTEGER:
864             case PLDM_BIOS_INTEGER_READ_ONLY:
865             {
866                 uint64_t value = std::stoll(attrValue);
867                 entryLength =
868                     pldm_bios_table_attr_value_entry_encode_integer_length();
869                 attrValueEntry.resize(entryLength);
870                 pldm_bios_table_attr_value_entry_encode_integer(
871                     attrValueEntry.data(), entryLength, attrEntry->attr_handle,
872                     attrType, value);
873                 break;
874             }
875         }
876 
877         requestMsg.resize(entryLength + sizeof(pldm_msg_hdr) +
878                           PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES);
879 
880         rc = encode_set_bios_attribute_current_value_req(
881             instanceId, 0, PLDM_START_AND_END, attrValueEntry.data(),
882             attrValueEntry.size(),
883             reinterpret_cast<pldm_msg*>(requestMsg.data()),
884             requestMsg.size() - sizeof(pldm_msg_hdr));
885 
886         if (rc != PLDM_SUCCESS)
887         {
888             std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
889             return;
890         }
891         std::vector<uint8_t> responseMsg;
892         rc = pldmSendRecv(requestMsg, responseMsg);
893         if (rc != PLDM_SUCCESS)
894         {
895             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
896             return;
897         }
898         uint8_t cc = 0;
899         uint32_t nextTransferHandle = 0;
900         auto responsePtr =
901             reinterpret_cast<struct pldm_msg*>(responseMsg.data());
902         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
903 
904         rc = decode_set_bios_attribute_current_value_resp(
905             responsePtr, payloadLength, &cc, &nextTransferHandle);
906         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
907         {
908             std::cerr << "Response Message Error: "
909                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
910             return;
911         }
912 
913         ordered_json data;
914         data["Response"] = "SUCCESS";
915         pldmtool::helper::DisplayInJson(data);
916     }
917 
918   private:
919     std::string attrName;
920     std::string attrValue;
921 };
922 
923 void registerCommand(CLI::App& app)
924 {
925     auto bios = app.add_subcommand("bios", "bios type command");
926     bios->require_subcommand(1);
927     auto getDateTime = bios->add_subcommand("GetDateTime", "get date time");
928     commands.push_back(
929         std::make_unique<GetDateTime>("bios", "GetDateTime", getDateTime));
930 
931     auto setDateTime = bios->add_subcommand("SetDateTime",
932                                             "set host date time");
933     commands.push_back(
934         std::make_unique<SetDateTime>("bios", "setDateTime", setDateTime));
935 
936     auto getBIOSTable = bios->add_subcommand("GetBIOSTable", "get bios table");
937     commands.push_back(
938         std::make_unique<GetBIOSTable>("bios", "GetBIOSTable", getBIOSTable));
939 
940     auto getBIOSAttributeCurrentValueByHandle =
941         bios->add_subcommand("GetBIOSAttributeCurrentValueByHandle",
942                              "get bios attribute current value by handle");
943     commands.push_back(std::make_unique<GetBIOSAttributeCurrentValueByHandle>(
944         "bios", "GetBIOSAttributeCurrentValueByHandle",
945         getBIOSAttributeCurrentValueByHandle));
946 
947     auto setBIOSAttributeCurrentValue = bios->add_subcommand(
948         "SetBIOSAttributeCurrentValue", "set bios attribute current value");
949     commands.push_back(std::make_unique<SetBIOSAttributeCurrentValue>(
950         "bios", "SetBIOSAttributeCurrentValue", setBIOSAttributeCurrentValue));
951 }
952 
953 } // namespace bios
954 
955 } // namespace pldmtool
956