1 #include "bios_config.hpp"
2 
3 #include "bios_enum_attribute.hpp"
4 #include "bios_integer_attribute.hpp"
5 #include "bios_string_attribute.hpp"
6 #include "bios_table.hpp"
7 #include "common/bios_utils.hpp"
8 
9 #include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp>
10 
11 #include <fstream>
12 #include <iostream>
13 
14 #ifdef OEM_IBM
15 #include "oem/ibm/libpldmresponder/platform_oem_ibm.hpp"
16 #endif
17 
18 namespace pldm
19 {
20 namespace responder
21 {
22 namespace bios
23 {
24 namespace
25 {
26 
27 using BIOSConfigManager =
28     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager;
29 
30 constexpr auto enumJsonFile = "enum_attrs.json";
31 constexpr auto stringJsonFile = "string_attrs.json";
32 constexpr auto integerJsonFile = "integer_attrs.json";
33 
34 constexpr auto stringTableFile = "stringTable";
35 constexpr auto attrTableFile = "attributeTable";
36 constexpr auto attrValueTableFile = "attributeValueTable";
37 
38 } // namespace
39 
40 BIOSConfig::BIOSConfig(
41     const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler,
42     int fd, uint8_t eid, dbus_api::Requester* requester,
43     pldm::requester::Handler<pldm::requester::Request>* handler) :
44     jsonDir(jsonDir),
45     tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid),
46     requester(requester), handler(handler)
47 
48 {
49     fs::create_directories(tableDir);
50     constructAttributes();
51     listenPendingAttributes();
52 }
53 
54 void BIOSConfig::buildTables()
55 {
56     auto stringTable = buildAndStoreStringTable();
57     if (stringTable)
58     {
59         buildAndStoreAttrTables(*stringTable);
60     }
61 }
62 
63 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
64 {
65     fs::path tablePath;
66     switch (tableType)
67     {
68         case PLDM_BIOS_STRING_TABLE:
69             tablePath = tableDir / stringTableFile;
70             break;
71         case PLDM_BIOS_ATTR_TABLE:
72             tablePath = tableDir / attrTableFile;
73             break;
74         case PLDM_BIOS_ATTR_VAL_TABLE:
75             tablePath = tableDir / attrValueTableFile;
76             break;
77     }
78     return loadTable(tablePath);
79 }
80 
81 int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table,
82                              bool updateBaseBIOSTable)
83 {
84     fs::path stringTablePath(tableDir / stringTableFile);
85     fs::path attrTablePath(tableDir / attrTableFile);
86     fs::path attrValueTablePath(tableDir / attrValueTableFile);
87 
88     if (!pldm_bios_table_checksum(table.data(), table.size()))
89     {
90         return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK;
91     }
92 
93     if (tableType == PLDM_BIOS_STRING_TABLE)
94     {
95         storeTable(stringTablePath, table);
96     }
97     else if (tableType == PLDM_BIOS_ATTR_TABLE)
98     {
99         BIOSTable biosStringTable(stringTablePath.c_str());
100         if (biosStringTable.isEmpty())
101         {
102             return PLDM_INVALID_BIOS_TABLE_TYPE;
103         }
104 
105         auto rc = checkAttributeTable(table);
106         if (rc != PLDM_SUCCESS)
107         {
108             return rc;
109         }
110 
111         storeTable(attrTablePath, table);
112     }
113     else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE)
114     {
115         BIOSTable biosStringTable(stringTablePath.c_str());
116         BIOSTable biosStringValueTable(attrTablePath.c_str());
117         if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty())
118         {
119             return PLDM_INVALID_BIOS_TABLE_TYPE;
120         }
121 
122         auto rc = checkAttributeValueTable(table);
123         if (rc != PLDM_SUCCESS)
124         {
125             return rc;
126         }
127 
128         storeTable(attrValueTablePath, table);
129     }
130     else
131     {
132         return PLDM_INVALID_BIOS_TABLE_TYPE;
133     }
134 
135     if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable)
136     {
137         std::cout << "setBIOSTable:: updateBaseBIOSTableProperty() "
138                   << "\n";
139         updateBaseBIOSTableProperty();
140     }
141 
142     return PLDM_SUCCESS;
143 }
144 
145 int BIOSConfig::checkAttributeTable(const Table& table)
146 {
147     using namespace pldm::bios::utils;
148     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
149     for (auto entry :
150          BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size()))
151     {
152         auto attrNameHandle =
153             pldm_bios_table_attr_entry_decode_string_handle(entry);
154 
155         auto stringEnty = pldm_bios_table_string_find_by_handle(
156             stringTable->data(), stringTable->size(), attrNameHandle);
157         if (stringEnty == nullptr)
158         {
159             return PLDM_INVALID_BIOS_ATTR_HANDLE;
160         }
161 
162         auto attrType = static_cast<pldm_bios_attribute_type>(
163             pldm_bios_table_attr_entry_decode_attribute_type(entry));
164 
165         switch (attrType)
166         {
167             case PLDM_BIOS_ENUMERATION:
168             case PLDM_BIOS_ENUMERATION_READ_ONLY:
169             {
170                 auto pvNum =
171                     pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
172                 std::vector<uint16_t> pvHandls(pvNum);
173                 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
174                     entry, pvHandls.data(), pvHandls.size());
175                 auto defNum =
176                     pldm_bios_table_attr_entry_enum_decode_def_num(entry);
177                 std::vector<uint8_t> defIndices(defNum);
178                 pldm_bios_table_attr_entry_enum_decode_def_indices(
179                     entry, defIndices.data(), defIndices.size());
180 
181                 for (size_t i = 0; i < pvHandls.size(); i++)
182                 {
183                     auto stringEntry = pldm_bios_table_string_find_by_handle(
184                         stringTable->data(), stringTable->size(), pvHandls[i]);
185                     if (stringEntry == nullptr)
186                     {
187                         return PLDM_INVALID_BIOS_ATTR_HANDLE;
188                     }
189                 }
190 
191                 for (size_t i = 0; i < defIndices.size(); i++)
192                 {
193                     auto stringEntry = pldm_bios_table_string_find_by_handle(
194                         stringTable->data(), stringTable->size(),
195                         pvHandls[defIndices[i]]);
196                     if (stringEntry == nullptr)
197                     {
198                         return PLDM_INVALID_BIOS_ATTR_HANDLE;
199                     }
200                 }
201                 break;
202             }
203             case PLDM_BIOS_INTEGER:
204             case PLDM_BIOS_INTEGER_READ_ONLY:
205             case PLDM_BIOS_STRING:
206             case PLDM_BIOS_STRING_READ_ONLY:
207             case PLDM_BIOS_PASSWORD:
208             case PLDM_BIOS_PASSWORD_READ_ONLY:
209                 break;
210             default:
211                 return PLDM_INVALID_BIOS_ATTR_HANDLE;
212         }
213     }
214 
215     return PLDM_SUCCESS;
216 }
217 
218 int BIOSConfig::checkAttributeValueTable(const Table& table)
219 {
220     using namespace pldm::bios::utils;
221     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
222     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
223 
224     baseBIOSTableMaps.clear();
225 
226     for (auto tableEntry :
227          BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size()))
228     {
229         AttributeName attributeName{};
230         AttributeType attributeType{};
231         ReadonlyStatus readonlyStatus{};
232         DisplayName displayName{};
233         Description description{};
234         MenuPath menuPath{};
235         CurrentValue currentValue{};
236         DefaultValue defaultValue{};
237         Option options{};
238 
239         auto attrValueHandle =
240             pldm_bios_table_attr_value_entry_decode_attribute_handle(
241                 tableEntry);
242         auto attrType = static_cast<pldm_bios_attribute_type>(
243             pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
244 
245         auto attrEntry = pldm_bios_table_attr_find_by_handle(
246             attrTable->data(), attrTable->size(), attrValueHandle);
247         if (attrEntry == nullptr)
248         {
249             return PLDM_INVALID_BIOS_ATTR_HANDLE;
250         }
251         auto attrHandle =
252             pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry);
253         auto attrNameHandle =
254             pldm_bios_table_attr_entry_decode_string_handle(attrEntry);
255 
256         auto stringEntry = pldm_bios_table_string_find_by_handle(
257             stringTable->data(), stringTable->size(), attrNameHandle);
258         if (stringEntry == nullptr)
259         {
260             return PLDM_INVALID_BIOS_ATTR_HANDLE;
261         }
262         auto strLength =
263             pldm_bios_table_string_entry_decode_string_length(stringEntry);
264         std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
265         pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
266                                                    buffer.size());
267         attributeName = std::string(buffer.data(), buffer.data() + strLength);
268 
269         if (!biosAttributes.empty())
270         {
271             readonlyStatus =
272                 biosAttributes[attrHandle % biosAttributes.size()]->readOnly;
273             description =
274                 biosAttributes[attrHandle % biosAttributes.size()]->helpText;
275             displayName =
276                 biosAttributes[attrHandle % biosAttributes.size()]->displayName;
277         }
278 
279         switch (attrType)
280         {
281             case PLDM_BIOS_ENUMERATION:
282             case PLDM_BIOS_ENUMERATION_READ_ONLY:
283             {
284                 auto getValue = [](uint16_t handle,
285                                    const Table& table) -> std::string {
286                     auto stringEntry = pldm_bios_table_string_find_by_handle(
287                         table.data(), table.size(), handle);
288 
289                     auto strLength =
290                         pldm_bios_table_string_entry_decode_string_length(
291                             stringEntry);
292                     std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
293                     pldm_bios_table_string_entry_decode_string(
294                         stringEntry, buffer.data(), buffer.size());
295 
296                     return std::string(buffer.data(),
297                                        buffer.data() + strLength);
298                 };
299 
300                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
301                                 "AttributeType.Enumeration";
302 
303                 auto pvNum =
304                     pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
305                 std::vector<uint16_t> pvHandls(pvNum);
306                 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
307                     attrEntry, pvHandls.data(), pvHandls.size());
308 
309                 // get possible_value
310                 for (size_t i = 0; i < pvHandls.size(); i++)
311                 {
312                     options.push_back(
313                         std::make_tuple("xyz.openbmc_project.BIOSConfig."
314                                         "Manager.BoundType.OneOf",
315                                         getValue(pvHandls[i], *stringTable)));
316                 }
317 
318                 auto count =
319                     pldm_bios_table_attr_value_entry_enum_decode_number(
320                         tableEntry);
321                 std::vector<uint8_t> handles(count);
322                 pldm_bios_table_attr_value_entry_enum_decode_handles(
323                     tableEntry, handles.data(), handles.size());
324 
325                 // get current_value
326                 for (size_t i = 0; i < handles.size(); i++)
327                 {
328                     currentValue = getValue(pvHandls[handles[i]], *stringTable);
329                 }
330 
331                 auto defNum =
332                     pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry);
333                 std::vector<uint8_t> defIndices(defNum);
334                 pldm_bios_table_attr_entry_enum_decode_def_indices(
335                     attrEntry, defIndices.data(), defIndices.size());
336 
337                 // get default_value
338                 for (size_t i = 0; i < defIndices.size(); i++)
339                 {
340                     defaultValue =
341                         getValue(pvHandls[defIndices[i]], *stringTable);
342                 }
343 
344                 break;
345             }
346             case PLDM_BIOS_INTEGER:
347             case PLDM_BIOS_INTEGER_READ_ONLY:
348             {
349                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
350                                 "AttributeType.Integer";
351                 currentValue = static_cast<int64_t>(
352                     pldm_bios_table_attr_value_entry_integer_decode_cv(
353                         tableEntry));
354 
355                 uint64_t lower, upper, def;
356                 uint32_t scalar;
357                 pldm_bios_table_attr_entry_integer_decode(
358                     attrEntry, &lower, &upper, &scalar, &def);
359                 options.push_back(
360                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
361                                     "BoundType.LowerBound",
362                                     static_cast<int64_t>(lower)));
363                 options.push_back(
364                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
365                                     "BoundType.UpperBound",
366                                     static_cast<int64_t>(upper)));
367                 options.push_back(
368                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
369                                     "BoundType.ScalarIncrement",
370                                     static_cast<int64_t>(scalar)));
371                 defaultValue = static_cast<int64_t>(def);
372                 break;
373             }
374             case PLDM_BIOS_STRING:
375             case PLDM_BIOS_STRING_READ_ONLY:
376             {
377                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
378                                 "AttributeType.String";
379                 variable_field currentString;
380                 pldm_bios_table_attr_value_entry_string_decode_string(
381                     tableEntry, &currentString);
382                 currentValue = std::string(
383                     reinterpret_cast<const char*>(currentString.ptr),
384                     currentString.length);
385                 auto min = pldm_bios_table_attr_entry_string_decode_min_length(
386                     attrEntry);
387                 auto max = pldm_bios_table_attr_entry_string_decode_max_length(
388                     attrEntry);
389                 auto def =
390                     pldm_bios_table_attr_entry_string_decode_def_string_length(
391                         attrEntry);
392                 std::vector<char> defString(def + 1);
393                 pldm_bios_table_attr_entry_string_decode_def_string(
394                     attrEntry, defString.data(), defString.size());
395                 options.push_back(
396                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
397                                     "BoundType.MinStringLength",
398                                     static_cast<int64_t>(min)));
399                 options.push_back(
400                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
401                                     "BoundType.MaxStringLength",
402                                     static_cast<int64_t>(max)));
403                 defaultValue = defString.data();
404                 break;
405             }
406             case PLDM_BIOS_PASSWORD:
407             case PLDM_BIOS_PASSWORD_READ_ONLY:
408             {
409                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
410                                 "AttributeType.Password";
411                 break;
412             }
413             default:
414                 return PLDM_INVALID_BIOS_ATTR_HANDLE;
415         }
416         baseBIOSTableMaps.emplace(
417             std::move(attributeName),
418             std::make_tuple(attributeType, readonlyStatus, displayName,
419                             description, menuPath, currentValue, defaultValue,
420                             std::move(options)));
421     }
422 
423     return PLDM_SUCCESS;
424 }
425 
426 void BIOSConfig::updateBaseBIOSTableProperty()
427 {
428     constexpr static auto biosConfigPath =
429         "/xyz/openbmc_project/bios_config/manager";
430     constexpr static auto biosConfigInterface =
431         "xyz.openbmc_project.BIOSConfig.Manager";
432     constexpr static auto biosConfigPropertyName = "BaseBIOSTable";
433     constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties";
434 
435     if (baseBIOSTableMaps.empty())
436     {
437         return;
438     }
439 
440     try
441     {
442         auto& bus = dbusHandler->getBus();
443         auto service =
444             dbusHandler->getService(biosConfigPath, biosConfigInterface);
445         auto method = bus.new_method_call(service.c_str(), biosConfigPath,
446                                           dbusProperties, "Set");
447         std::variant<BaseBIOSTable> value = baseBIOSTableMaps;
448         method.append(biosConfigInterface, biosConfigPropertyName, value);
449         bus.call_noreply(method);
450     }
451     catch (const std::exception& e)
452     {
453         std::cerr << "failed to update BaseBIOSTable property, ERROR="
454                   << e.what() << "\n";
455     }
456 }
457 
458 void BIOSConfig::constructAttributes()
459 {
460     load(jsonDir / stringJsonFile, [this](const Json& entry) {
461         constructAttribute<BIOSStringAttribute>(entry);
462     });
463     load(jsonDir / integerJsonFile, [this](const Json& entry) {
464         constructAttribute<BIOSIntegerAttribute>(entry);
465     });
466     load(jsonDir / enumJsonFile, [this](const Json& entry) {
467         constructAttribute<BIOSEnumAttribute>(entry);
468     });
469 }
470 
471 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
472 {
473     BIOSStringTable biosStringTable(stringTable);
474 
475     if (biosAttributes.empty())
476     {
477         return;
478     }
479 
480     BaseBIOSTable biosTable{};
481     constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager";
482     constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager";
483 
484     try
485     {
486         auto& bus = dbusHandler->getBus();
487         auto service = dbusHandler->getService(biosObjPath, biosInterface);
488         auto method =
489             bus.new_method_call(service.c_str(), biosObjPath,
490                                 "org.freedesktop.DBus.Properties", "Get");
491         method.append(biosInterface, "BaseBIOSTable");
492         auto reply = bus.call(method);
493         std::variant<BaseBIOSTable> varBiosTable{};
494         reply.read(varBiosTable);
495         biosTable = std::get<BaseBIOSTable>(varBiosTable);
496     }
497     // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the
498     // default values populated from the BIOS JSONs to keep PLDM and
499     // bios-settings-manager in sync
500     catch (const std::exception& e)
501     {
502         std::cerr << "Failed to read BaseBIOSTable property, ERROR=" << e.what()
503                   << "\n";
504     }
505 
506     Table attrTable, attrValueTable;
507 
508     for (auto& attr : biosAttributes)
509     {
510         try
511         {
512             auto iter = biosTable.find(attr->name);
513             if (iter == biosTable.end())
514             {
515                 attr->constructEntry(biosStringTable, attrTable, attrValueTable,
516                                      std::nullopt);
517             }
518             else
519             {
520                 attr->constructEntry(
521                     biosStringTable, attrTable, attrValueTable,
522                     std::get<static_cast<uint8_t>(Index::currentValue)>(
523                         iter->second));
524             }
525         }
526         catch (const std::exception& e)
527         {
528             std::cerr << "Construct Table Entry Error, AttributeName = "
529                       << attr->name << std::endl;
530         }
531     }
532 
533     table::appendPadAndChecksum(attrTable);
534     table::appendPadAndChecksum(attrValueTable);
535     setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable);
536     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable);
537 }
538 
539 std::optional<Table> BIOSConfig::buildAndStoreStringTable()
540 {
541     std::set<std::string> strings;
542     auto handler = [&strings](const Json& entry) {
543         strings.emplace(entry.at("attribute_name"));
544     };
545 
546     load(jsonDir / stringJsonFile, handler);
547     load(jsonDir / integerJsonFile, handler);
548     load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
549         strings.emplace(entry.at("attribute_name"));
550         auto possibleValues = entry.at("possible_values");
551         for (auto& pv : possibleValues)
552         {
553             strings.emplace(pv);
554         }
555     });
556 
557     if (strings.empty())
558     {
559         return std::nullopt;
560     }
561 
562     Table table;
563     for (const auto& elem : strings)
564     {
565         table::string::constructEntry(table, elem);
566     }
567 
568     table::appendPadAndChecksum(table);
569     setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
570     return table;
571 }
572 
573 void BIOSConfig::storeTable(const fs::path& path, const Table& table)
574 {
575     BIOSTable biosTable(path.c_str());
576     biosTable.store(table);
577 }
578 
579 std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
580 {
581     BIOSTable biosTable(path.c_str());
582     if (biosTable.isEmpty())
583     {
584         return std::nullopt;
585     }
586 
587     Table table;
588     biosTable.load(table);
589     return table;
590 }
591 
592 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
593 {
594     std::ifstream file;
595     Json jsonConf;
596     if (fs::exists(filePath))
597     {
598         try
599         {
600             file.open(filePath);
601             jsonConf = Json::parse(file);
602             auto entries = jsonConf.at("entries");
603             for (auto& entry : entries)
604             {
605                 try
606                 {
607                     handler(entry);
608                 }
609                 catch (const std::exception& e)
610                 {
611                     std::cerr
612                         << "Failed to parse JSON config file(entry handler) : "
613                         << filePath.c_str() << ", " << e.what() << std::endl;
614                 }
615             }
616         }
617         catch (const std::exception& e)
618         {
619             std::cerr << "Failed to parse JSON config file : "
620                       << filePath.c_str() << std::endl;
621         }
622     }
623 }
624 
625 int BIOSConfig::checkAttrValueToUpdate(
626     const pldm_bios_attr_val_table_entry* attrValueEntry,
627     const pldm_bios_attr_table_entry* attrEntry, Table&)
628 
629 {
630     auto [attrHandle, attrType] =
631         table::attribute_value::decodeHeader(attrValueEntry);
632 
633     switch (attrType)
634     {
635         case PLDM_BIOS_ENUMERATION:
636         {
637             auto value =
638                 table::attribute_value::decodeEnumEntry(attrValueEntry);
639             auto [pvHdls, defIndex] =
640                 table::attribute::decodeEnumEntry(attrEntry);
641             assert(value.size() == 1);
642             if (value[0] >= pvHdls.size())
643             {
644                 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
645                           << std::endl;
646                 return PLDM_ERROR_INVALID_DATA;
647             }
648 
649             return PLDM_SUCCESS;
650         }
651         case PLDM_BIOS_INTEGER:
652         {
653             auto value =
654                 table::attribute_value::decodeIntegerEntry(attrValueEntry);
655             auto [lower, upper, scalar, def] =
656                 table::attribute::decodeIntegerEntry(attrEntry);
657 
658             if (value < lower || value > upper)
659             {
660                 std::cerr << "Integer: out of bound, value = " << value
661                           << std::endl;
662                 return PLDM_ERROR_INVALID_DATA;
663             }
664             return PLDM_SUCCESS;
665         }
666         case PLDM_BIOS_STRING:
667         {
668             auto stringConf = table::attribute::decodeStringEntry(attrEntry);
669             auto value =
670                 table::attribute_value::decodeStringEntry(attrValueEntry);
671             if (value.size() < stringConf.minLength ||
672                 value.size() > stringConf.maxLength)
673             {
674                 std::cerr << "String: Length error, string = " << value
675                           << " length = " << value.size() << std::endl;
676                 return PLDM_ERROR_INVALID_LENGTH;
677             }
678             return PLDM_SUCCESS;
679         }
680         default:
681             std::cerr << "ReadOnly or Unspported type, type = " << attrType
682                       << std::endl;
683             return PLDM_ERROR;
684     };
685 }
686 
687 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool updateDBus,
688                              bool updateBaseBIOSTable)
689 {
690     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
691     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
692     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
693     if (!attrValueTable || !attrTable || !stringTable)
694     {
695         return PLDM_BIOS_TABLE_UNAVAILABLE;
696     }
697 
698     auto attrValueEntry =
699         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
700 
701     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
702 
703     auto attrEntry =
704         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
705     if (!attrEntry)
706     {
707         return PLDM_ERROR;
708     }
709 
710     auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
711     if (rc != PLDM_SUCCESS)
712     {
713         return rc;
714     }
715 
716     auto destTable =
717         table::attribute_value::updateTable(*attrValueTable, entry, size);
718 
719     if (!destTable)
720     {
721         return PLDM_ERROR;
722     }
723 
724     try
725     {
726         auto attrHeader = table::attribute::decodeHeader(attrEntry);
727 
728         BIOSStringTable biosStringTable(*stringTable);
729         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
730 
731         auto iter = std::find_if(
732             biosAttributes.begin(), biosAttributes.end(),
733             [&attrName](const auto& attr) { return attr->name == attrName; });
734 
735         if (iter == biosAttributes.end())
736         {
737             return PLDM_ERROR;
738         }
739         if (updateDBus)
740         {
741             (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
742                                         biosStringTable);
743         }
744     }
745     catch (const std::exception& e)
746     {
747         std::cerr << "Set attribute value error: " << e.what() << std::endl;
748         return PLDM_ERROR;
749     }
750 
751     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
752 
753     return PLDM_SUCCESS;
754 }
755 
756 void BIOSConfig::removeTables()
757 {
758     try
759     {
760         fs::remove(tableDir / stringTableFile);
761         fs::remove(tableDir / attrTableFile);
762         fs::remove(tableDir / attrValueTableFile);
763     }
764     catch (const std::exception& e)
765     {
766         std::cerr << "Remove the tables error: " << e.what() << std::endl;
767     }
768 }
769 
770 void BIOSConfig::processBiosAttrChangeNotification(
771     const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
772 {
773     const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
774     const auto& propertyName = dBusMap->propertyName;
775     const auto& attrName = biosAttributes[biosAttrIndex]->name;
776 
777     const auto it = chProperties.find(propertyName);
778     if (it == chProperties.end())
779     {
780         return;
781     }
782 
783     PropertyValue newPropVal = it->second;
784     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
785     if (!stringTable.has_value())
786     {
787         std::cerr << "BIOS string table unavailable\n";
788         return;
789     }
790     BIOSStringTable biosStringTable(*stringTable);
791     uint16_t attrNameHdl{};
792     try
793     {
794         attrNameHdl = biosStringTable.findHandle(attrName);
795     }
796     catch (std::invalid_argument& e)
797     {
798         std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
799                   << attrName.c_str() << "\n";
800         return;
801     }
802 
803     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
804     if (!attrTable.has_value())
805     {
806         std::cerr << "Attribute table not present\n";
807         return;
808     }
809     const struct pldm_bios_attr_table_entry* tableEntry =
810         table::attribute::findByStringHandle(*attrTable, attrNameHdl);
811     if (tableEntry == nullptr)
812     {
813         std::cerr << "Attribute not found in attribute table, name= "
814                   << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
815         return;
816     }
817 
818     auto [attrHdl, attrType, stringHdl] =
819         table::attribute::decodeHeader(tableEntry);
820 
821     auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
822 
823     if (!attrValueSrcTable.has_value())
824     {
825         std::cerr << "Attribute value table not present\n";
826         return;
827     }
828 
829     Table newValue;
830     auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
831         newValue, attrHdl, attrType, newPropVal);
832     if (rc != PLDM_SUCCESS)
833     {
834         std::cerr << "Could not update the attribute value table for attribute "
835                      "handle="
836                   << attrHdl << " and type=" << (uint32_t)attrType << "\n";
837         return;
838     }
839     auto destTable = table::attribute_value::updateTable(
840         *attrValueSrcTable, newValue.data(), newValue.size());
841     if (destTable.has_value())
842     {
843         storeTable(tableDir / attrValueTableFile, *destTable);
844     }
845 
846     rc = setAttrValue(newValue.data(), newValue.size(), false);
847     if (rc != PLDM_SUCCESS)
848     {
849         std::cerr << "could not setAttrValue on base bios table and dbus, rc = "
850                   << rc << "\n";
851     }
852 }
853 
854 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
855 {
856     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
857     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
858 
859     BIOSStringTable biosStringTable(*stringTable);
860     pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
861         attrTable->data(), attrTable->size());
862     auto stringHandle = biosStringTable.findHandle(attrName);
863 
864     for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
865              attrTable->data(), attrTable->size()))
866     {
867         auto header = table::attribute::decodeHeader(entry);
868         if (header.stringHandle == stringHandle)
869         {
870             return header.attrHandle;
871         }
872     }
873 
874     throw std::invalid_argument("Unknow attribute Name");
875 }
876 
877 void BIOSConfig::constructPendingAttribute(
878     const PendingAttributes& pendingAttributes)
879 {
880     std::vector<uint16_t> listOfHandles{};
881 
882     for (auto& attribute : pendingAttributes)
883     {
884         std::string attributeName = attribute.first;
885         auto& [attributeType, attributevalue] = attribute.second;
886 
887         auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
888                                  [&attributeName](const auto& attr) {
889                                      return attr->name == attributeName;
890                                  });
891 
892         if (iter == biosAttributes.end())
893         {
894             std::cerr << "Wrong attribute name, attributeName = "
895                       << attributeName << std::endl;
896             continue;
897         }
898 
899         Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
900         auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
901             attrValueEntry.data());
902 
903         auto handler = findAttrHandle(attributeName);
904         auto type =
905             BIOSConfigManager::convertAttributeTypeFromString(attributeType);
906 
907         if (type != BIOSConfigManager::AttributeType::Enumeration &&
908             type != BIOSConfigManager::AttributeType::String &&
909             type != BIOSConfigManager::AttributeType::Integer)
910         {
911             std::cerr << "Attribute type not supported, attributeType = "
912                       << attributeType << std::endl;
913             continue;
914         }
915 
916         entry->attr_handle = htole16(handler);
917         listOfHandles.emplace_back(htole16(handler));
918 
919         (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
920 
921         setAttrValue(attrValueEntry.data(), attrValueEntry.size());
922     }
923 
924     if (listOfHandles.size())
925     {
926 #ifdef OEM_IBM
927         auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
928             eid, requester, listOfHandles, handler);
929         if (rc != PLDM_SUCCESS)
930         {
931             return;
932         }
933 #endif
934     }
935 }
936 
937 void BIOSConfig::listenPendingAttributes()
938 {
939     constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
940     constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
941 
942     using namespace sdbusplus::bus::match::rules;
943     auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>(
944         pldm::utils::DBusHandler::getBus(),
945         propertiesChanged(objPath, objInterface),
946         [this](sdbusplus::message::message& msg) {
947             constexpr auto propertyName = "PendingAttributes";
948 
949             using Value =
950                 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
951             using Properties = std::map<DbusProp, Value>;
952 
953             Properties props{};
954             std::string intf;
955             msg.read(intf, props);
956 
957             auto valPropMap = props.find(propertyName);
958             if (valPropMap == props.end())
959             {
960                 return;
961             }
962 
963             PendingAttributes pendingAttributes =
964                 std::get<PendingAttributes>(valPropMap->second);
965             this->constructPendingAttribute(pendingAttributes);
966         });
967 
968     biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
969 }
970 
971 } // namespace bios
972 } // namespace responder
973 } // namespace pldm
974