xref: /openbmc/pldm/pldmtool/pldm_bios_cmd.cpp (revision 772403b9)
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             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 
698             std::cerr << "Can not find the attribute " << attrName << std::endl;
699             return;
700         }
701 
702         std::vector<uint8_t> requestMsg(
703             sizeof(pldm_msg_hdr) +
704             PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES);
705         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
706 
707         auto rc = encode_get_bios_attribute_current_value_by_handle_req(
708             instanceId, 0, PLDM_GET_FIRSTPART, *handle, request);
709         if (rc != PLDM_SUCCESS)
710         {
711             std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
712             return;
713         }
714 
715         std::vector<uint8_t> responseMsg;
716         rc = pldmSendRecv(requestMsg, responseMsg);
717         if (rc != PLDM_SUCCESS)
718         {
719             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
720             return;
721         }
722 
723         uint8_t cc = 0, transferFlag = 0;
724         uint32_t nextTransferHandle = 0;
725         struct variable_field attributeData;
726         auto responsePtr =
727             reinterpret_cast<struct pldm_msg*>(responseMsg.data());
728         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
729 
730         rc = decode_get_bios_attribute_current_value_by_handle_resp(
731             responsePtr, payloadLength, &cc, &nextTransferHandle, &transferFlag,
732             &attributeData);
733         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
734         {
735             std::cerr << "Response Message Error: "
736                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
737             return;
738         }
739 
740         auto tableEntry =
741             reinterpret_cast<const struct pldm_bios_attr_val_table_entry*>(
742                 attributeData.ptr);
743 
744         ordered_json avdata;
745         displayAttributeValueEntry(tableEntry, attrTable, stringTable, false,
746                                    avdata);
747         pldmtool::helper::DisplayInJson(avdata);
748     }
749 
750   private:
751     std::string attrName;
752 };
753 
754 class SetBIOSAttributeCurrentValue : public GetBIOSTableHandler
755 {
756   public:
757     ~SetBIOSAttributeCurrentValue() = default;
758     SetBIOSAttributeCurrentValue() = delete;
759     SetBIOSAttributeCurrentValue(const SetBIOSAttributeCurrentValue&) = delete;
760     SetBIOSAttributeCurrentValue(SetBIOSAttributeCurrentValue&&) = default;
761     SetBIOSAttributeCurrentValue&
762         operator=(const SetBIOSAttributeCurrentValue&) = delete;
763     SetBIOSAttributeCurrentValue&
764         operator=(SetBIOSAttributeCurrentValue&&) = default;
765 
766     explicit SetBIOSAttributeCurrentValue(const char* type, const char* name,
767                                           CLI::App* app) :
768         GetBIOSTableHandler(type, name, app)
769     {
770         app->add_option("-a, --attribute", attrName, "pldm attribute name")
771             ->required();
772         app->add_option("-d, --data", attrValue, "pldm attribute value")
773             ->required();
774         // -v is conflict with --verbose in class CommandInterface, so used -d
775     }
776 
777     void exec()
778     {
779         auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
780         auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
781         auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
782 
783         if (!stringTable || !attrTable)
784         {
785             std::cout << "StringTable/AttrTable Unavaliable" << std::endl;
786             return;
787         }
788 
789         auto attrEntry =
790             findAttrEntryByName(attrName, *attrTable, *stringTable);
791         if (attrEntry == nullptr)
792         {
793             std::cout << "Could not find attribute :" << attrName << std::endl;
794             return;
795         }
796 
797         std::vector<uint8_t> requestMsg;
798 
799         int rc = 0;
800         auto attrType = attrEntry->attr_type;
801         size_t entryLength = 1;
802         std::vector<uint8_t> attrValueEntry(entryLength, 0);
803 
804         switch (attrType)
805         {
806             case PLDM_BIOS_ENUMERATION_READ_ONLY:
807             case PLDM_BIOS_STRING_READ_ONLY:
808             case PLDM_BIOS_INTEGER_READ_ONLY:
809             {
810                 std::cerr << "Set attribute error: " << attrName
811                           << "is read only." << std::endl;
812                 return;
813             }
814             case PLDM_BIOS_ENUMERATION:
815             {
816                 entryLength =
817                     pldm_bios_table_attr_value_entry_encode_enum_length(1);
818                 auto pvNum =
819                     pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
820                 std::vector<uint16_t> pvHdls(pvNum, 0);
821                 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
822                     attrEntry, pvHdls.data(), pvNum);
823                 auto stringEntry = pldm_bios_table_string_find_by_string(
824                     stringTable->data(), stringTable->size(),
825                     attrValue.c_str());
826                 if (stringEntry == nullptr)
827                 {
828                     std::cout
829                         << "Set Attribute Error: It's not a possible value"
830                         << std::endl;
831                     return;
832                 }
833                 auto valueHandle =
834                     pldm_bios_table_string_entry_decode_handle(stringEntry);
835 
836                 uint8_t i;
837                 for (i = 0; i < pvNum; i++)
838                 {
839                     if (valueHandle == pvHdls[i])
840                         break;
841                 }
842                 if (i == pvNum)
843                 {
844                     std::cout
845                         << "Set Attribute Error: It's not a possible value"
846                         << std::endl;
847                     return;
848                 }
849 
850                 attrValueEntry.resize(entryLength);
851                 std::vector<uint8_t> handles = {i};
852                 pldm_bios_table_attr_value_entry_encode_enum(
853                     attrValueEntry.data(), attrValueEntry.size(),
854                     attrEntry->attr_handle, attrType, 1, handles.data());
855                 break;
856             }
857             case PLDM_BIOS_STRING:
858             {
859                 entryLength =
860                     pldm_bios_table_attr_value_entry_encode_string_length(
861                         attrValue.size());
862 
863                 attrValueEntry.resize(entryLength);
864 
865                 pldm_bios_table_attr_value_entry_encode_string(
866                     attrValueEntry.data(), entryLength, attrEntry->attr_handle,
867                     attrType, attrValue.size(), attrValue.c_str());
868                 break;
869             }
870             case PLDM_BIOS_INTEGER:
871             {
872                 uint64_t value = std::stoll(attrValue);
873                 entryLength =
874                     pldm_bios_table_attr_value_entry_encode_integer_length();
875                 attrValueEntry.resize(entryLength);
876                 pldm_bios_table_attr_value_entry_encode_integer(
877                     attrValueEntry.data(), entryLength, attrEntry->attr_handle,
878                     attrType, value);
879                 break;
880             }
881         }
882 
883         requestMsg.resize(entryLength + sizeof(pldm_msg_hdr) +
884                           PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES);
885 
886         rc = encode_set_bios_attribute_current_value_req(
887             instanceId, 0, PLDM_START_AND_END, attrValueEntry.data(),
888             attrValueEntry.size(),
889             reinterpret_cast<pldm_msg*>(requestMsg.data()),
890             requestMsg.size() - sizeof(pldm_msg_hdr));
891 
892         if (rc != PLDM_SUCCESS)
893         {
894             std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
895             return;
896         }
897         std::vector<uint8_t> responseMsg;
898         rc = pldmSendRecv(requestMsg, responseMsg);
899         if (rc != PLDM_SUCCESS)
900         {
901             std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
902             return;
903         }
904         uint8_t cc = 0;
905         uint32_t nextTransferHandle = 0;
906         auto responsePtr =
907             reinterpret_cast<struct pldm_msg*>(responseMsg.data());
908         auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
909 
910         rc = decode_set_bios_attribute_current_value_resp(
911             responsePtr, payloadLength, &cc, &nextTransferHandle);
912         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
913         {
914             std::cerr << "Response Message Error: "
915                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
916             return;
917         }
918 
919         ordered_json data;
920         data["Response"] = "SUCCESS";
921         pldmtool::helper::DisplayInJson(data);
922     }
923 
924   private:
925     std::string attrName;
926     std::string attrValue;
927 };
928 
929 void registerCommand(CLI::App& app)
930 {
931     auto bios = app.add_subcommand("bios", "bios type command");
932     bios->require_subcommand(1);
933     auto getDateTime = bios->add_subcommand("GetDateTime", "get date time");
934     commands.push_back(
935         std::make_unique<GetDateTime>("bios", "GetDateTime", getDateTime));
936 
937     auto setDateTime =
938         bios->add_subcommand("SetDateTime", "set host date time");
939     commands.push_back(
940         std::make_unique<SetDateTime>("bios", "setDateTime", setDateTime));
941 
942     auto getBIOSTable = bios->add_subcommand("GetBIOSTable", "get bios table");
943     commands.push_back(
944         std::make_unique<GetBIOSTable>("bios", "GetBIOSTable", getBIOSTable));
945 
946     auto getBIOSAttributeCurrentValueByHandle =
947         bios->add_subcommand("GetBIOSAttributeCurrentValueByHandle",
948                              "get bios attribute current value by handle");
949     commands.push_back(std::make_unique<GetBIOSAttributeCurrentValueByHandle>(
950         "bios", "GetBIOSAttributeCurrentValueByHandle",
951         getBIOSAttributeCurrentValueByHandle));
952 
953     auto setBIOSAttributeCurrentValue = bios->add_subcommand(
954         "SetBIOSAttributeCurrentValue", "set bios attribute current value");
955     commands.push_back(std::make_unique<SetBIOSAttributeCurrentValue>(
956         "bios", "SetBIOSAttributeCurrentValue", setBIOSAttributeCurrentValue));
957 }
958 
959 } // namespace bios
960 
961 } // namespace pldmtool
962