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         case PLDM_BIOS_ENUMERATION_READ_ONLY:
640         {
641             auto value =
642                 table::attribute_value::decodeEnumEntry(attrValueEntry);
643             auto [pvHdls, defIndex] =
644                 table::attribute::decodeEnumEntry(attrEntry);
645             if (!(value.size() == 1))
646             {
647                 return PLDM_ERROR_INVALID_LENGTH;
648             }
649             if (value[0] >= pvHdls.size())
650             {
651                 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
652                           << std::endl;
653                 return PLDM_ERROR_INVALID_DATA;
654             }
655 
656             return PLDM_SUCCESS;
657         }
658         case PLDM_BIOS_INTEGER:
659         case PLDM_BIOS_INTEGER_READ_ONLY:
660         {
661             auto value =
662                 table::attribute_value::decodeIntegerEntry(attrValueEntry);
663             auto [lower, upper, scalar, def] =
664                 table::attribute::decodeIntegerEntry(attrEntry);
665 
666             if (value < lower || value > upper)
667             {
668                 std::cerr << "Integer: out of bound, value = " << value
669                           << std::endl;
670                 return PLDM_ERROR_INVALID_DATA;
671             }
672             return PLDM_SUCCESS;
673         }
674         case PLDM_BIOS_STRING:
675         case PLDM_BIOS_STRING_READ_ONLY:
676         {
677             auto stringConf = table::attribute::decodeStringEntry(attrEntry);
678             auto value =
679                 table::attribute_value::decodeStringEntry(attrValueEntry);
680             if (value.size() < stringConf.minLength ||
681                 value.size() > stringConf.maxLength)
682             {
683                 std::cerr << "String: Length error, string = " << value
684                           << " length = " << value.size() << std::endl;
685                 return PLDM_ERROR_INVALID_LENGTH;
686             }
687             return PLDM_SUCCESS;
688         }
689         default:
690             std::cerr << "ReadOnly or Unspported type, type = " << attrType
691                       << std::endl;
692             return PLDM_ERROR;
693     };
694 }
695 
696 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool updateDBus,
697                              bool updateBaseBIOSTable)
698 {
699     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
700     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
701     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
702     if (!attrValueTable || !attrTable || !stringTable)
703     {
704         return PLDM_BIOS_TABLE_UNAVAILABLE;
705     }
706 
707     auto attrValueEntry =
708         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
709 
710     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
711 
712     auto attrEntry =
713         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
714     if (!attrEntry)
715     {
716         return PLDM_ERROR;
717     }
718 
719     auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
720     if (rc != PLDM_SUCCESS)
721     {
722         return rc;
723     }
724 
725     auto destTable =
726         table::attribute_value::updateTable(*attrValueTable, entry, size);
727 
728     if (!destTable)
729     {
730         return PLDM_ERROR;
731     }
732 
733     try
734     {
735         auto attrHeader = table::attribute::decodeHeader(attrEntry);
736 
737         BIOSStringTable biosStringTable(*stringTable);
738         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
739 
740         auto iter = std::find_if(
741             biosAttributes.begin(), biosAttributes.end(),
742             [&attrName](const auto& attr) { return attr->name == attrName; });
743 
744         if (iter == biosAttributes.end())
745         {
746             return PLDM_ERROR;
747         }
748         if (updateDBus)
749         {
750             (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
751                                         biosStringTable);
752         }
753     }
754     catch (const std::exception& e)
755     {
756         std::cerr << "Set attribute value error: " << e.what() << std::endl;
757         return PLDM_ERROR;
758     }
759 
760     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
761 
762     return PLDM_SUCCESS;
763 }
764 
765 void BIOSConfig::removeTables()
766 {
767     try
768     {
769         fs::remove(tableDir / stringTableFile);
770         fs::remove(tableDir / attrTableFile);
771         fs::remove(tableDir / attrValueTableFile);
772     }
773     catch (const std::exception& e)
774     {
775         std::cerr << "Remove the tables error: " << e.what() << std::endl;
776     }
777 }
778 
779 void BIOSConfig::processBiosAttrChangeNotification(
780     const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
781 {
782     const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
783     const auto& propertyName = dBusMap->propertyName;
784     const auto& attrName = biosAttributes[biosAttrIndex]->name;
785 
786     const auto it = chProperties.find(propertyName);
787     if (it == chProperties.end())
788     {
789         return;
790     }
791 
792     PropertyValue newPropVal = it->second;
793     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
794     if (!stringTable.has_value())
795     {
796         std::cerr << "BIOS string table unavailable\n";
797         return;
798     }
799     BIOSStringTable biosStringTable(*stringTable);
800     uint16_t attrNameHdl{};
801     try
802     {
803         attrNameHdl = biosStringTable.findHandle(attrName);
804     }
805     catch (const std::invalid_argument& e)
806     {
807         std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
808                   << attrName.c_str() << "\n";
809         return;
810     }
811 
812     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
813     if (!attrTable.has_value())
814     {
815         std::cerr << "Attribute table not present\n";
816         return;
817     }
818     const struct pldm_bios_attr_table_entry* tableEntry =
819         table::attribute::findByStringHandle(*attrTable, attrNameHdl);
820     if (tableEntry == nullptr)
821     {
822         std::cerr << "Attribute not found in attribute table, name= "
823                   << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
824         return;
825     }
826 
827     auto [attrHdl, attrType, stringHdl] =
828         table::attribute::decodeHeader(tableEntry);
829 
830     auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
831 
832     if (!attrValueSrcTable.has_value())
833     {
834         std::cerr << "Attribute value table not present\n";
835         return;
836     }
837 
838     Table newValue;
839     auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
840         newValue, attrHdl, attrType, newPropVal);
841     if (rc != PLDM_SUCCESS)
842     {
843         std::cerr << "Could not update the attribute value table for attribute "
844                      "handle="
845                   << attrHdl << " and type=" << (uint32_t)attrType << "\n";
846         return;
847     }
848     auto destTable = table::attribute_value::updateTable(
849         *attrValueSrcTable, newValue.data(), newValue.size());
850     if (destTable.has_value())
851     {
852         storeTable(tableDir / attrValueTableFile, *destTable);
853     }
854 
855     rc = setAttrValue(newValue.data(), newValue.size(), false);
856     if (rc != PLDM_SUCCESS)
857     {
858         std::cerr << "could not setAttrValue on base bios table and dbus, rc = "
859                   << rc << "\n";
860     }
861 }
862 
863 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
864 {
865     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
866     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
867 
868     BIOSStringTable biosStringTable(*stringTable);
869     pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
870         attrTable->data(), attrTable->size());
871     auto stringHandle = biosStringTable.findHandle(attrName);
872 
873     for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
874              attrTable->data(), attrTable->size()))
875     {
876         auto header = table::attribute::decodeHeader(entry);
877         if (header.stringHandle == stringHandle)
878         {
879             return header.attrHandle;
880         }
881     }
882 
883     throw std::invalid_argument("Unknow attribute Name");
884 }
885 
886 void BIOSConfig::constructPendingAttribute(
887     const PendingAttributes& pendingAttributes)
888 {
889     std::vector<uint16_t> listOfHandles{};
890 
891     for (auto& attribute : pendingAttributes)
892     {
893         std::string attributeName = attribute.first;
894         auto& [attributeType, attributevalue] = attribute.second;
895 
896         auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
897                                  [&attributeName](const auto& attr) {
898                                      return attr->name == attributeName;
899                                  });
900 
901         if (iter == biosAttributes.end())
902         {
903             std::cerr << "Wrong attribute name, attributeName = "
904                       << attributeName << std::endl;
905             continue;
906         }
907 
908         Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
909         auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
910             attrValueEntry.data());
911 
912         auto handler = findAttrHandle(attributeName);
913         auto type =
914             BIOSConfigManager::convertAttributeTypeFromString(attributeType);
915 
916         if (type != BIOSConfigManager::AttributeType::Enumeration &&
917             type != BIOSConfigManager::AttributeType::String &&
918             type != BIOSConfigManager::AttributeType::Integer)
919         {
920             std::cerr << "Attribute type not supported, attributeType = "
921                       << attributeType << std::endl;
922             continue;
923         }
924 
925         entry->attr_handle = htole16(handler);
926         listOfHandles.emplace_back(htole16(handler));
927 
928         (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
929 
930         setAttrValue(attrValueEntry.data(), attrValueEntry.size());
931     }
932 
933     if (listOfHandles.size())
934     {
935 #ifdef OEM_IBM
936         auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
937             eid, requester, listOfHandles, handler);
938         if (rc != PLDM_SUCCESS)
939         {
940             return;
941         }
942 #endif
943     }
944 }
945 
946 void BIOSConfig::listenPendingAttributes()
947 {
948     constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
949     constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
950 
951     using namespace sdbusplus::bus::match::rules;
952     auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>(
953         pldm::utils::DBusHandler::getBus(),
954         propertiesChanged(objPath, objInterface),
955         [this](sdbusplus::message::message& msg) {
956             constexpr auto propertyName = "PendingAttributes";
957 
958             using Value =
959                 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
960             using Properties = std::map<DbusProp, Value>;
961 
962             Properties props{};
963             std::string intf;
964             msg.read(intf, props);
965 
966             auto valPropMap = props.find(propertyName);
967             if (valPropMap == props.end())
968             {
969                 return;
970             }
971 
972             PendingAttributes pendingAttributes =
973                 std::get<PendingAttributes>(valPropMap->second);
974             this->constructPendingAttribute(pendingAttributes);
975         });
976 
977     biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
978 }
979 
980 } // namespace bios
981 } // namespace responder
982 } // namespace pldm
983