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     Table attrTable, attrValueTable;
480 
481     for (auto& attr : biosAttributes)
482     {
483         try
484         {
485             attr->constructEntry(biosStringTable, attrTable, attrValueTable);
486         }
487         catch (const std::exception& e)
488         {
489             std::cerr << "Construct Table Entry Error, AttributeName = "
490                       << attr->name << std::endl;
491         }
492     }
493 
494     table::appendPadAndChecksum(attrTable);
495     table::appendPadAndChecksum(attrValueTable);
496     setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable);
497     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable);
498 }
499 
500 std::optional<Table> BIOSConfig::buildAndStoreStringTable()
501 {
502     std::set<std::string> strings;
503     auto handler = [&strings](const Json& entry) {
504         strings.emplace(entry.at("attribute_name"));
505     };
506 
507     load(jsonDir / stringJsonFile, handler);
508     load(jsonDir / integerJsonFile, handler);
509     load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
510         strings.emplace(entry.at("attribute_name"));
511         auto possibleValues = entry.at("possible_values");
512         for (auto& pv : possibleValues)
513         {
514             strings.emplace(pv);
515         }
516     });
517 
518     if (strings.empty())
519     {
520         return std::nullopt;
521     }
522 
523     Table table;
524     for (const auto& elem : strings)
525     {
526         table::string::constructEntry(table, elem);
527     }
528 
529     table::appendPadAndChecksum(table);
530     setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
531     return table;
532 }
533 
534 void BIOSConfig::storeTable(const fs::path& path, const Table& table)
535 {
536     BIOSTable biosTable(path.c_str());
537     biosTable.store(table);
538 }
539 
540 std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
541 {
542     BIOSTable biosTable(path.c_str());
543     if (biosTable.isEmpty())
544     {
545         return std::nullopt;
546     }
547 
548     Table table;
549     biosTable.load(table);
550     return table;
551 }
552 
553 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
554 {
555     std::ifstream file;
556     Json jsonConf;
557     if (fs::exists(filePath))
558     {
559         try
560         {
561             file.open(filePath);
562             jsonConf = Json::parse(file);
563             auto entries = jsonConf.at("entries");
564             for (auto& entry : entries)
565             {
566                 try
567                 {
568                     handler(entry);
569                 }
570                 catch (const std::exception& e)
571                 {
572                     std::cerr
573                         << "Failed to parse JSON config file(entry handler) : "
574                         << filePath.c_str() << ", " << e.what() << std::endl;
575                 }
576             }
577         }
578         catch (const std::exception& e)
579         {
580             std::cerr << "Failed to parse JSON config file : "
581                       << filePath.c_str() << std::endl;
582         }
583     }
584 }
585 
586 int BIOSConfig::checkAttrValueToUpdate(
587     const pldm_bios_attr_val_table_entry* attrValueEntry,
588     const pldm_bios_attr_table_entry* attrEntry, Table&)
589 
590 {
591     auto [attrHandle, attrType] =
592         table::attribute_value::decodeHeader(attrValueEntry);
593 
594     switch (attrType)
595     {
596         case PLDM_BIOS_ENUMERATION:
597         {
598             auto value =
599                 table::attribute_value::decodeEnumEntry(attrValueEntry);
600             auto [pvHdls, defIndex] =
601                 table::attribute::decodeEnumEntry(attrEntry);
602             assert(value.size() == 1);
603             if (value[0] >= pvHdls.size())
604             {
605                 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
606                           << std::endl;
607                 return PLDM_ERROR_INVALID_DATA;
608             }
609 
610             return PLDM_SUCCESS;
611         }
612         case PLDM_BIOS_INTEGER:
613         {
614             auto value =
615                 table::attribute_value::decodeIntegerEntry(attrValueEntry);
616             auto [lower, upper, scalar, def] =
617                 table::attribute::decodeIntegerEntry(attrEntry);
618 
619             if (value < lower || value > upper)
620             {
621                 std::cerr << "Integer: out of bound, value = " << value
622                           << std::endl;
623                 return PLDM_ERROR_INVALID_DATA;
624             }
625             return PLDM_SUCCESS;
626         }
627         case PLDM_BIOS_STRING:
628         {
629             auto stringConf = table::attribute::decodeStringEntry(attrEntry);
630             auto value =
631                 table::attribute_value::decodeStringEntry(attrValueEntry);
632             if (value.size() < stringConf.minLength ||
633                 value.size() > stringConf.maxLength)
634             {
635                 std::cerr << "String: Length error, string = " << value
636                           << " length = " << value.size() << std::endl;
637                 return PLDM_ERROR_INVALID_LENGTH;
638             }
639             return PLDM_SUCCESS;
640         }
641         default:
642             std::cerr << "ReadOnly or Unspported type, type = " << attrType
643                       << std::endl;
644             return PLDM_ERROR;
645     };
646 }
647 
648 int BIOSConfig::setAttrValue(const void* entry, size_t size,
649                              bool updateBaseBIOSTable)
650 {
651     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
652     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
653     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
654     if (!attrValueTable || !attrTable || !stringTable)
655     {
656         return PLDM_BIOS_TABLE_UNAVAILABLE;
657     }
658 
659     auto attrValueEntry =
660         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
661 
662     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
663 
664     auto attrEntry =
665         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
666     if (!attrEntry)
667     {
668         return PLDM_ERROR;
669     }
670 
671     auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
672     if (rc != PLDM_SUCCESS)
673     {
674         return rc;
675     }
676 
677     auto destTable =
678         table::attribute_value::updateTable(*attrValueTable, entry, size);
679 
680     if (!destTable)
681     {
682         return PLDM_ERROR;
683     }
684 
685     try
686     {
687         auto attrHeader = table::attribute::decodeHeader(attrEntry);
688 
689         BIOSStringTable biosStringTable(*stringTable);
690         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
691 
692         auto iter = std::find_if(
693             biosAttributes.begin(), biosAttributes.end(),
694             [&attrName](const auto& attr) { return attr->name == attrName; });
695 
696         if (iter == biosAttributes.end())
697         {
698             return PLDM_ERROR;
699         }
700         (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable);
701     }
702     catch (const std::exception& e)
703     {
704         std::cerr << "Set attribute value error: " << e.what() << std::endl;
705         return PLDM_ERROR;
706     }
707 
708     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
709 
710     return PLDM_SUCCESS;
711 }
712 
713 void BIOSConfig::removeTables()
714 {
715     try
716     {
717         fs::remove(tableDir / stringTableFile);
718         fs::remove(tableDir / attrTableFile);
719         fs::remove(tableDir / attrValueTableFile);
720     }
721     catch (const std::exception& e)
722     {
723         std::cerr << "Remove the tables error: " << e.what() << std::endl;
724     }
725 }
726 
727 void BIOSConfig::processBiosAttrChangeNotification(
728     const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
729 {
730     const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
731     const auto& propertyName = dBusMap->propertyName;
732     const auto& attrName = biosAttributes[biosAttrIndex]->name;
733 
734     const auto it = chProperties.find(propertyName);
735     if (it == chProperties.end())
736     {
737         return;
738     }
739 
740     PropertyValue newPropVal = it->second;
741     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
742     if (!stringTable.has_value())
743     {
744         std::cerr << "BIOS string table unavailable\n";
745         return;
746     }
747     BIOSStringTable biosStringTable(*stringTable);
748     uint16_t attrNameHdl{};
749     try
750     {
751         attrNameHdl = biosStringTable.findHandle(attrName);
752     }
753     catch (std::invalid_argument& e)
754     {
755         std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
756                   << attrName.c_str() << "\n";
757         return;
758     }
759 
760     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
761     if (!attrTable.has_value())
762     {
763         std::cerr << "Attribute table not present\n";
764         return;
765     }
766     const struct pldm_bios_attr_table_entry* tableEntry =
767         table::attribute::findByStringHandle(*attrTable, attrNameHdl);
768     if (tableEntry == nullptr)
769     {
770         std::cerr << "Attribute not found in attribute table, name= "
771                   << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
772         return;
773     }
774 
775     auto [attrHdl, attrType, stringHdl] =
776         table::attribute::decodeHeader(tableEntry);
777 
778     auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
779 
780     if (!attrValueSrcTable.has_value())
781     {
782         std::cerr << "Attribute value table not present\n";
783         return;
784     }
785 
786     Table newValue;
787     auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
788         newValue, attrHdl, attrType, newPropVal);
789     if (rc != PLDM_SUCCESS)
790     {
791         std::cerr << "Could not update the attribute value table for attribute "
792                      "handle="
793                   << attrHdl << " and type=" << (uint32_t)attrType << "\n";
794         return;
795     }
796     auto destTable = table::attribute_value::updateTable(
797         *attrValueSrcTable, newValue.data(), newValue.size());
798     if (destTable.has_value())
799     {
800         storeTable(tableDir / attrValueTableFile, *destTable);
801     }
802 }
803 
804 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
805 {
806     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
807     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
808 
809     BIOSStringTable biosStringTable(*stringTable);
810     pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
811         attrTable->data(), attrTable->size());
812     auto stringHandle = biosStringTable.findHandle(attrName);
813 
814     for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
815              attrTable->data(), attrTable->size()))
816     {
817         auto header = table::attribute::decodeHeader(entry);
818         if (header.stringHandle == stringHandle)
819         {
820             return header.attrHandle;
821         }
822     }
823 
824     throw std::invalid_argument("Unknow attribute Name");
825 }
826 
827 void BIOSConfig::constructPendingAttribute(
828     const PendingAttributes& pendingAttributes)
829 {
830     std::vector<uint16_t> listOfHandles{};
831 
832     for (auto& attribute : pendingAttributes)
833     {
834         std::string attributeName = attribute.first;
835         auto& [attributeType, attributevalue] = attribute.second;
836 
837         auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
838                                  [&attributeName](const auto& attr) {
839                                      return attr->name == attributeName;
840                                  });
841 
842         if (iter == biosAttributes.end())
843         {
844             std::cerr << "Wrong attribute name, attributeName = "
845                       << attributeName << std::endl;
846             continue;
847         }
848 
849         Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
850         auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
851             attrValueEntry.data());
852 
853         auto handler = findAttrHandle(attributeName);
854         auto type =
855             BIOSConfigManager::convertAttributeTypeFromString(attributeType);
856 
857         if (type != BIOSConfigManager::AttributeType::Enumeration &&
858             type != BIOSConfigManager::AttributeType::String &&
859             type != BIOSConfigManager::AttributeType::Integer)
860         {
861             std::cerr << "Attribute type not supported, attributeType = "
862                       << attributeType << std::endl;
863             continue;
864         }
865 
866         entry->attr_handle = htole16(handler);
867         listOfHandles.emplace_back(htole16(handler));
868 
869         (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
870 
871         setAttrValue(attrValueEntry.data(), attrValueEntry.size(), false);
872     }
873 
874     if (listOfHandles.size())
875     {
876 #ifdef OEM_IBM
877         auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
878             fd, eid, requester, listOfHandles);
879         if (rc != PLDM_SUCCESS)
880         {
881             return;
882         }
883 #endif
884         updateBaseBIOSTableProperty();
885     }
886 }
887 
888 void BIOSConfig::listenPendingAttributes()
889 {
890     constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
891     constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
892 
893     using namespace sdbusplus::bus::match::rules;
894     auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>(
895         pldm::utils::DBusHandler::getBus(),
896         propertiesChanged(objPath, objInterface),
897         [this](sdbusplus::message::message& msg) {
898             constexpr auto propertyName = "PendingAttributes";
899 
900             using Value =
901                 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
902             using Properties = std::map<DbusProp, Value>;
903 
904             Properties props{};
905             std::string intf;
906             msg.read(intf, props);
907 
908             auto valPropMap = props.find(propertyName);
909             if (valPropMap == props.end())
910             {
911                 return;
912             }
913 
914             PendingAttributes pendingAttributes =
915                 std::get<PendingAttributes>(valPropMap->second);
916             this->constructPendingAttribute(pendingAttributes);
917         });
918 
919     biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
920 }
921 
922 } // namespace bios
923 } // namespace responder
924 } // namespace pldm
925