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