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