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