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