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         }
273 
274         switch (attrType)
275         {
276             case PLDM_BIOS_ENUMERATION:
277             case PLDM_BIOS_ENUMERATION_READ_ONLY:
278             {
279                 auto getValue = [](uint16_t handle,
280                                    const Table& table) -> std::string {
281                     auto stringEntry = pldm_bios_table_string_find_by_handle(
282                         table.data(), table.size(), handle);
283 
284                     auto strLength =
285                         pldm_bios_table_string_entry_decode_string_length(
286                             stringEntry);
287                     std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
288                     pldm_bios_table_string_entry_decode_string(
289                         stringEntry, buffer.data(), buffer.size());
290 
291                     return std::string(buffer.data(),
292                                        buffer.data() + strLength);
293                 };
294 
295                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
296                                 "AttributeType.Enumeration";
297 
298                 auto pvNum =
299                     pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
300                 std::vector<uint16_t> pvHandls(pvNum);
301                 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
302                     attrEntry, pvHandls.data(), pvHandls.size());
303 
304                 // get possible_value
305                 for (size_t i = 0; i < pvHandls.size(); i++)
306                 {
307                     options.push_back(
308                         std::make_tuple("xyz.openbmc_project.BIOSConfig."
309                                         "Manager.BoundType.OneOf",
310                                         getValue(pvHandls[i], *stringTable)));
311                 }
312 
313                 auto count =
314                     pldm_bios_table_attr_value_entry_enum_decode_number(
315                         tableEntry);
316                 std::vector<uint8_t> handles(count);
317                 pldm_bios_table_attr_value_entry_enum_decode_handles(
318                     tableEntry, handles.data(), handles.size());
319 
320                 // get current_value
321                 for (size_t i = 0; i < handles.size(); i++)
322                 {
323                     currentValue = getValue(pvHandls[handles[i]], *stringTable);
324                 }
325 
326                 auto defNum =
327                     pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry);
328                 std::vector<uint8_t> defIndices(defNum);
329                 pldm_bios_table_attr_entry_enum_decode_def_indices(
330                     attrEntry, defIndices.data(), defIndices.size());
331 
332                 // get default_value
333                 for (size_t i = 0; i < defIndices.size(); i++)
334                 {
335                     defaultValue =
336                         getValue(pvHandls[defIndices[i]], *stringTable);
337                 }
338 
339                 break;
340             }
341             case PLDM_BIOS_INTEGER:
342             case PLDM_BIOS_INTEGER_READ_ONLY:
343             {
344                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
345                                 "AttributeType.Integer";
346                 currentValue = static_cast<int64_t>(
347                     pldm_bios_table_attr_value_entry_integer_decode_cv(
348                         tableEntry));
349 
350                 uint64_t lower, upper, def;
351                 uint32_t scalar;
352                 pldm_bios_table_attr_entry_integer_decode(
353                     attrEntry, &lower, &upper, &scalar, &def);
354                 options.push_back(
355                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
356                                     "BoundType.LowerBound",
357                                     static_cast<int64_t>(lower)));
358                 options.push_back(
359                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
360                                     "BoundType.UpperBound",
361                                     static_cast<int64_t>(upper)));
362                 options.push_back(
363                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
364                                     "BoundType.ScalarIncrement",
365                                     static_cast<int64_t>(scalar)));
366                 defaultValue = static_cast<int64_t>(def);
367                 break;
368             }
369             case PLDM_BIOS_STRING:
370             case PLDM_BIOS_STRING_READ_ONLY:
371             {
372                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
373                                 "AttributeType.String";
374                 variable_field currentString;
375                 pldm_bios_table_attr_value_entry_string_decode_string(
376                     tableEntry, &currentString);
377                 currentValue = std::string(
378                     reinterpret_cast<const char*>(currentString.ptr),
379                     currentString.length);
380                 auto min = pldm_bios_table_attr_entry_string_decode_min_length(
381                     attrEntry);
382                 auto max = pldm_bios_table_attr_entry_string_decode_max_length(
383                     attrEntry);
384                 auto def =
385                     pldm_bios_table_attr_entry_string_decode_def_string_length(
386                         attrEntry);
387                 std::vector<char> defString(def + 1);
388                 pldm_bios_table_attr_entry_string_decode_def_string(
389                     attrEntry, defString.data(), defString.size());
390                 options.push_back(
391                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
392                                     "BoundType.MinStringLength",
393                                     static_cast<int64_t>(min)));
394                 options.push_back(
395                     std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
396                                     "BoundType.MaxStringLength",
397                                     static_cast<int64_t>(max)));
398                 defaultValue = defString.data();
399                 break;
400             }
401             case PLDM_BIOS_PASSWORD:
402             case PLDM_BIOS_PASSWORD_READ_ONLY:
403             {
404                 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
405                                 "AttributeType.Password";
406                 break;
407             }
408             default:
409                 return PLDM_INVALID_BIOS_ATTR_HANDLE;
410         }
411         baseBIOSTableMaps.emplace(
412             std::move(attributeName),
413             std::make_tuple(attributeType, readonlyStatus, displayName,
414                             description, menuPath, currentValue, defaultValue,
415                             std::move(options)));
416     }
417 
418     return PLDM_SUCCESS;
419 }
420 
421 void BIOSConfig::updateBaseBIOSTableProperty()
422 {
423     constexpr static auto biosConfigPath =
424         "/xyz/openbmc_project/bios_config/manager";
425     constexpr static auto biosConfigInterface =
426         "xyz.openbmc_project.BIOSConfig.Manager";
427     constexpr static auto biosConfigPropertyName = "BaseBIOSTable";
428     constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties";
429 
430     if (baseBIOSTableMaps.empty())
431     {
432         return;
433     }
434 
435     try
436     {
437         auto& bus = dbusHandler->getBus();
438         auto service =
439             dbusHandler->getService(biosConfigPath, biosConfigInterface);
440         auto method = bus.new_method_call(service.c_str(), biosConfigPath,
441                                           dbusProperties, "Set");
442         std::variant<BaseBIOSTable> value = baseBIOSTableMaps;
443         method.append(biosConfigInterface, biosConfigPropertyName, value);
444         bus.call_noreply(method);
445     }
446     catch (const std::exception& e)
447     {
448         std::cerr << "failed to update BaseBIOSTable property, ERROR="
449                   << e.what() << "\n";
450     }
451 }
452 
453 void BIOSConfig::constructAttributes()
454 {
455     load(jsonDir / stringJsonFile, [this](const Json& entry) {
456         constructAttribute<BIOSStringAttribute>(entry);
457     });
458     load(jsonDir / integerJsonFile, [this](const Json& entry) {
459         constructAttribute<BIOSIntegerAttribute>(entry);
460     });
461     load(jsonDir / enumJsonFile, [this](const Json& entry) {
462         constructAttribute<BIOSEnumAttribute>(entry);
463     });
464 }
465 
466 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
467 {
468     BIOSStringTable biosStringTable(stringTable);
469 
470     if (biosAttributes.empty())
471     {
472         return;
473     }
474 
475     Table attrTable, attrValueTable;
476 
477     for (auto& attr : biosAttributes)
478     {
479         try
480         {
481             attr->constructEntry(biosStringTable, attrTable, attrValueTable);
482         }
483         catch (const std::exception& e)
484         {
485             std::cerr << "Construct Table Entry Error, AttributeName = "
486                       << attr->name << std::endl;
487         }
488     }
489 
490     table::appendPadAndChecksum(attrTable);
491     table::appendPadAndChecksum(attrValueTable);
492     setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable);
493     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable);
494 }
495 
496 std::optional<Table> BIOSConfig::buildAndStoreStringTable()
497 {
498     std::set<std::string> strings;
499     auto handler = [&strings](const Json& entry) {
500         strings.emplace(entry.at("attribute_name"));
501     };
502 
503     load(jsonDir / stringJsonFile, handler);
504     load(jsonDir / integerJsonFile, handler);
505     load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
506         strings.emplace(entry.at("attribute_name"));
507         auto possibleValues = entry.at("possible_values");
508         for (auto& pv : possibleValues)
509         {
510             strings.emplace(pv);
511         }
512     });
513 
514     if (strings.empty())
515     {
516         return std::nullopt;
517     }
518 
519     Table table;
520     for (const auto& elem : strings)
521     {
522         table::string::constructEntry(table, elem);
523     }
524 
525     table::appendPadAndChecksum(table);
526     setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
527     return table;
528 }
529 
530 void BIOSConfig::storeTable(const fs::path& path, const Table& table)
531 {
532     BIOSTable biosTable(path.c_str());
533     biosTable.store(table);
534 }
535 
536 std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
537 {
538     BIOSTable biosTable(path.c_str());
539     if (biosTable.isEmpty())
540     {
541         return std::nullopt;
542     }
543 
544     Table table;
545     biosTable.load(table);
546     return table;
547 }
548 
549 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
550 {
551     std::ifstream file;
552     Json jsonConf;
553     if (fs::exists(filePath))
554     {
555         try
556         {
557             file.open(filePath);
558             jsonConf = Json::parse(file);
559             auto entries = jsonConf.at("entries");
560             for (auto& entry : entries)
561             {
562                 try
563                 {
564                     handler(entry);
565                 }
566                 catch (const std::exception& e)
567                 {
568                     std::cerr
569                         << "Failed to parse JSON config file(entry handler) : "
570                         << filePath.c_str() << ", " << e.what() << std::endl;
571                 }
572             }
573         }
574         catch (const std::exception& e)
575         {
576             std::cerr << "Failed to parse JSON config file : "
577                       << filePath.c_str() << std::endl;
578         }
579     }
580 }
581 
582 int BIOSConfig::checkAttrValueToUpdate(
583     const pldm_bios_attr_val_table_entry* attrValueEntry,
584     const pldm_bios_attr_table_entry* attrEntry, Table&)
585 
586 {
587     auto [attrHandle, attrType] =
588         table::attribute_value::decodeHeader(attrValueEntry);
589 
590     switch (attrType)
591     {
592         case PLDM_BIOS_ENUMERATION:
593         {
594             auto value =
595                 table::attribute_value::decodeEnumEntry(attrValueEntry);
596             auto [pvHdls, defIndex] =
597                 table::attribute::decodeEnumEntry(attrEntry);
598             assert(value.size() == 1);
599             if (value[0] >= pvHdls.size())
600             {
601                 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
602                           << std::endl;
603                 return PLDM_ERROR_INVALID_DATA;
604             }
605 
606             return PLDM_SUCCESS;
607         }
608         case PLDM_BIOS_INTEGER:
609         {
610             auto value =
611                 table::attribute_value::decodeIntegerEntry(attrValueEntry);
612             auto [lower, upper, scalar, def] =
613                 table::attribute::decodeIntegerEntry(attrEntry);
614 
615             if (value < lower || value > upper)
616             {
617                 std::cerr << "Integer: out of bound, value = " << value
618                           << std::endl;
619                 return PLDM_ERROR_INVALID_DATA;
620             }
621             return PLDM_SUCCESS;
622         }
623         case PLDM_BIOS_STRING:
624         {
625             auto stringConf = table::attribute::decodeStringEntry(attrEntry);
626             auto value =
627                 table::attribute_value::decodeStringEntry(attrValueEntry);
628             if (value.size() < stringConf.minLength ||
629                 value.size() > stringConf.maxLength)
630             {
631                 std::cerr << "String: Length error, string = " << value
632                           << " length = " << value.size() << std::endl;
633                 return PLDM_ERROR_INVALID_LENGTH;
634             }
635             return PLDM_SUCCESS;
636         }
637         default:
638             std::cerr << "ReadOnly or Unspported type, type = " << attrType
639                       << std::endl;
640             return PLDM_ERROR;
641     };
642 }
643 
644 int BIOSConfig::setAttrValue(const void* entry, size_t size,
645                              bool updateBaseBIOSTable)
646 {
647     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
648     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
649     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
650     if (!attrValueTable || !attrTable || !stringTable)
651     {
652         return PLDM_BIOS_TABLE_UNAVAILABLE;
653     }
654 
655     auto attrValueEntry =
656         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
657 
658     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
659 
660     auto attrEntry =
661         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
662     if (!attrEntry)
663     {
664         return PLDM_ERROR;
665     }
666 
667     auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
668     if (rc != PLDM_SUCCESS)
669     {
670         return rc;
671     }
672 
673     auto destTable =
674         table::attribute_value::updateTable(*attrValueTable, entry, size);
675 
676     if (!destTable)
677     {
678         return PLDM_ERROR;
679     }
680 
681     try
682     {
683         auto attrHeader = table::attribute::decodeHeader(attrEntry);
684 
685         BIOSStringTable biosStringTable(*stringTable);
686         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
687 
688         auto iter = std::find_if(
689             biosAttributes.begin(), biosAttributes.end(),
690             [&attrName](const auto& attr) { return attr->name == attrName; });
691 
692         if (iter == biosAttributes.end())
693         {
694             return PLDM_ERROR;
695         }
696         (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable);
697     }
698     catch (const std::exception& e)
699     {
700         std::cerr << "Set attribute value error: " << e.what() << std::endl;
701         return PLDM_ERROR;
702     }
703 
704     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
705 
706     return PLDM_SUCCESS;
707 }
708 
709 void BIOSConfig::removeTables()
710 {
711     try
712     {
713         fs::remove(tableDir / stringTableFile);
714         fs::remove(tableDir / attrTableFile);
715         fs::remove(tableDir / attrValueTableFile);
716     }
717     catch (const std::exception& e)
718     {
719         std::cerr << "Remove the tables error: " << e.what() << std::endl;
720     }
721 }
722 
723 void BIOSConfig::processBiosAttrChangeNotification(
724     const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
725 {
726     const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
727     const auto& propertyName = dBusMap->propertyName;
728     const auto& attrName = biosAttributes[biosAttrIndex]->name;
729 
730     const auto it = chProperties.find(propertyName);
731     if (it == chProperties.end())
732     {
733         return;
734     }
735 
736     PropertyValue newPropVal = it->second;
737     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
738     if (!stringTable.has_value())
739     {
740         std::cerr << "BIOS string table unavailable\n";
741         return;
742     }
743     BIOSStringTable biosStringTable(*stringTable);
744     uint16_t attrNameHdl{};
745     try
746     {
747         attrNameHdl = biosStringTable.findHandle(attrName);
748     }
749     catch (std::invalid_argument& e)
750     {
751         std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
752                   << attrName.c_str() << "\n";
753         return;
754     }
755 
756     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
757     if (!attrTable.has_value())
758     {
759         std::cerr << "Attribute table not present\n";
760         return;
761     }
762     const struct pldm_bios_attr_table_entry* tableEntry =
763         table::attribute::findByStringHandle(*attrTable, attrNameHdl);
764     if (tableEntry == nullptr)
765     {
766         std::cerr << "Attribute not found in attribute table, name= "
767                   << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
768         return;
769     }
770 
771     auto [attrHdl, attrType, stringHdl] =
772         table::attribute::decodeHeader(tableEntry);
773 
774     auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
775 
776     if (!attrValueSrcTable.has_value())
777     {
778         std::cerr << "Attribute value table not present\n";
779         return;
780     }
781 
782     Table newValue;
783     auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
784         newValue, attrHdl, attrType, newPropVal);
785     if (rc != PLDM_SUCCESS)
786     {
787         std::cerr << "Could not update the attribute value table for attribute "
788                      "handle="
789                   << attrHdl << " and type=" << (uint32_t)attrType << "\n";
790         return;
791     }
792     auto destTable = table::attribute_value::updateTable(
793         *attrValueSrcTable, newValue.data(), newValue.size());
794     if (destTable.has_value())
795     {
796         storeTable(tableDir / attrValueTableFile, *destTable);
797     }
798 }
799 
800 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
801 {
802     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
803     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
804 
805     BIOSStringTable biosStringTable(*stringTable);
806     pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
807         attrTable->data(), attrTable->size());
808     auto stringHandle = biosStringTable.findHandle(attrName);
809 
810     for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
811              attrTable->data(), attrTable->size()))
812     {
813         auto header = table::attribute::decodeHeader(entry);
814         if (header.stringHandle == stringHandle)
815         {
816             return header.attrHandle;
817         }
818     }
819 
820     throw std::invalid_argument("Unknow attribute Name");
821 }
822 
823 void BIOSConfig::constructPendingAttribute(
824     const PendingAttributes& pendingAttributes)
825 {
826     std::vector<uint16_t> listOfHandles{};
827 
828     for (auto& attribute : pendingAttributes)
829     {
830         std::string attributeName = attribute.first;
831         auto& [attributeType, attributevalue] = attribute.second;
832 
833         auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
834                                  [&attributeName](const auto& attr) {
835                                      return attr->name == attributeName;
836                                  });
837 
838         if (iter == biosAttributes.end())
839         {
840             std::cerr << "Wrong attribute name, attributeName = "
841                       << attributeName << std::endl;
842             continue;
843         }
844 
845         Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
846         auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
847             attrValueEntry.data());
848 
849         auto handler = findAttrHandle(attributeName);
850         auto type =
851             BIOSConfigManager::convertAttributeTypeFromString(attributeType);
852 
853         if (type != BIOSConfigManager::AttributeType::Enumeration &&
854             type != BIOSConfigManager::AttributeType::String &&
855             type != BIOSConfigManager::AttributeType::Integer)
856         {
857             std::cerr << "Attribute type not supported, attributeType = "
858                       << attributeType << std::endl;
859             continue;
860         }
861 
862         entry->attr_handle = htole16(handler);
863         listOfHandles.emplace_back(htole16(handler));
864 
865         (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
866 
867         setAttrValue(attrValueEntry.data(), attrValueEntry.size(), false);
868     }
869 
870     if (listOfHandles.size())
871     {
872 #ifdef OEM_IBM
873         auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
874             fd, eid, requester, listOfHandles);
875         if (rc != PLDM_SUCCESS)
876         {
877             return;
878         }
879 #endif
880         updateBaseBIOSTableProperty();
881     }
882 }
883 
884 void BIOSConfig::listenPendingAttributes()
885 {
886     constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
887     constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
888 
889     using namespace sdbusplus::bus::match::rules;
890     auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>(
891         pldm::utils::DBusHandler::getBus(),
892         propertiesChanged(objPath, objInterface),
893         [this](sdbusplus::message::message& msg) {
894             constexpr auto propertyName = "PendingAttributes";
895 
896             using Value =
897                 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
898             using Properties = std::map<DbusProp, Value>;
899 
900             Properties props{};
901             std::string intf;
902             msg.read(intf, props);
903 
904             auto valPropMap = props.find(propertyName);
905             if (valPropMap == props.end())
906             {
907                 return;
908             }
909 
910             PendingAttributes pendingAttributes =
911                 std::get<PendingAttributes>(valPropMap->second);
912             this->constructPendingAttribute(pendingAttributes);
913         });
914 
915     biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
916 }
917 
918 } // namespace bios
919 } // namespace responder
920 } // namespace pldm
921