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