xref: /openbmc/pldm/libpldmresponder/bios_config.cpp (revision 19ea04c3824651c69fc3a3f20079e25b444c0f53)
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 <phosphor-logging/lg2.hpp>
10 #include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp>
11 
12 #include <fstream>
13 #include <iostream>
14 
15 #ifdef OEM_IBM
16 #include "oem/ibm/libpldmresponder/platform_oem_ibm.hpp"
17 #endif
18 
19 PHOSPHOR_LOG2_USING;
20 
21 using namespace pldm::dbus_api;
22 using namespace pldm::utils;
23 
24 namespace pldm
25 {
26 namespace responder
27 {
28 namespace bios
29 {
30 namespace
31 {
32 using BIOSConfigManager =
33     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager;
34 
35 constexpr auto enumJsonFile = "enum_attrs.json";
36 constexpr auto stringJsonFile = "string_attrs.json";
37 constexpr auto integerJsonFile = "integer_attrs.json";
38 
39 constexpr auto stringTableFile = "stringTable";
40 constexpr auto attrTableFile = "attributeTable";
41 constexpr auto attrValueTableFile = "attributeValueTable";
42 
43 } // namespace
44 
45 BIOSConfig::BIOSConfig(
46     const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler,
47     int fd, uint8_t eid, dbus_api::Requester* requester,
48     pldm::requester::Handler<pldm::requester::Request>* handler) :
49     jsonDir(jsonDir),
50     tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid),
51     requester(requester), handler(handler)
52 
53 {
54     fs::create_directories(tableDir);
55     constructAttributes();
56     listenPendingAttributes();
57 }
58 
59 void BIOSConfig::buildTables()
60 {
61     auto stringTable = buildAndStoreStringTable();
62     if (stringTable)
63     {
64         buildAndStoreAttrTables(*stringTable);
65     }
66 }
67 
68 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
69 {
70     fs::path tablePath;
71     switch (tableType)
72     {
73         case PLDM_BIOS_STRING_TABLE:
74             tablePath = tableDir / stringTableFile;
75             break;
76         case PLDM_BIOS_ATTR_TABLE:
77             tablePath = tableDir / attrTableFile;
78             break;
79         case PLDM_BIOS_ATTR_VAL_TABLE:
80             tablePath = tableDir / attrValueTableFile;
81             break;
82     }
83     return loadTable(tablePath);
84 }
85 
86 int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table,
87                              bool updateBaseBIOSTable)
88 {
89     fs::path stringTablePath(tableDir / stringTableFile);
90     fs::path attrTablePath(tableDir / attrTableFile);
91     fs::path attrValueTablePath(tableDir / attrValueTableFile);
92 
93     if (!pldm_bios_table_checksum(table.data(), table.size()))
94     {
95         return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK;
96     }
97 
98     if (tableType == PLDM_BIOS_STRING_TABLE)
99     {
100         storeTable(stringTablePath, table);
101     }
102     else if (tableType == PLDM_BIOS_ATTR_TABLE)
103     {
104         BIOSTable biosStringTable(stringTablePath.c_str());
105         if (biosStringTable.isEmpty())
106         {
107             return PLDM_INVALID_BIOS_TABLE_TYPE;
108         }
109 
110         auto rc = checkAttributeTable(table);
111         if (rc != PLDM_SUCCESS)
112         {
113             return rc;
114         }
115 
116         storeTable(attrTablePath, table);
117     }
118     else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE)
119     {
120         BIOSTable biosStringTable(stringTablePath.c_str());
121         BIOSTable biosStringValueTable(attrTablePath.c_str());
122         if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty())
123         {
124             return PLDM_INVALID_BIOS_TABLE_TYPE;
125         }
126 
127         auto rc = checkAttributeValueTable(table);
128         if (rc != PLDM_SUCCESS)
129         {
130             return rc;
131         }
132 
133         storeTable(attrValueTablePath, table);
134     }
135     else
136     {
137         return PLDM_INVALID_BIOS_TABLE_TYPE;
138     }
139 
140     if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable)
141     {
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         error("failed to update BaseBIOSTable property, ERROR={ERR_EXCEP}",
457               "ERR_EXCEP", e.what());
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         error("Failed to read BaseBIOSTable property, ERROR={ERR_EXCEP}",
506               "ERR_EXCEP", e.what());
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             error("Construct Table Entry Error, AttributeName = {ATTR_NAME}",
532                   "ATTR_NAME", attr->name);
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                     error(
615                         "Failed to parse JSON config file(entry handler) : {JSON_PATH}, {ERR_EXCEP}",
616                         "JSON_PATH", filePath.c_str(), "ERR_EXCEP", e.what());
617                 }
618             }
619         }
620         catch (const std::exception& e)
621         {
622             error("Failed to parse JSON config file : {JSON_PATH}", "JSON_PATH",
623                   filePath.c_str());
624         }
625     }
626 }
627 
628 std::string BIOSConfig::decodeStringFromStringEntry(
629     const pldm_bios_string_table_entry* stringEntry)
630 {
631     auto strLength =
632         pldm_bios_table_string_entry_decode_string_length(stringEntry);
633     std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
634     pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
635                                                buffer.size());
636     return std::string(buffer.data(), buffer.data() + strLength);
637 }
638 
639 std::string
640     BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index,
641                                     const std::optional<Table>& attrTable,
642                                     const std::optional<Table>& stringTable)
643 {
644     auto attrEntry = pldm_bios_table_attr_find_by_handle(
645         attrTable->data(), attrTable->size(), handle);
646     auto pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
647     std::vector<uint16_t> pvHandls(pvNum);
648     pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrEntry, pvHandls.data(),
649                                                    pvHandls.size());
650 
651     std::string displayString = std::to_string(pvHandls[index]);
652 
653     auto stringEntry = pldm_bios_table_string_find_by_handle(
654         stringTable->data(), stringTable->size(), pvHandls[index]);
655 
656     auto decodedStr = decodeStringFromStringEntry(stringEntry);
657 
658     return decodedStr + "(" + displayString + ")";
659 }
660 
661 void BIOSConfig::traceBIOSUpdate(
662     const pldm_bios_attr_val_table_entry* attrValueEntry,
663     const pldm_bios_attr_table_entry* attrEntry, bool isBMC)
664 {
665     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
666     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
667 
668     auto [attrHandle, attrType] =
669         table::attribute_value::decodeHeader(attrValueEntry);
670 
671     auto attrHeader = table::attribute::decodeHeader(attrEntry);
672     BIOSStringTable biosStringTable(*stringTable);
673     auto attrName = biosStringTable.findString(attrHeader.stringHandle);
674 
675     switch (attrType)
676     {
677         case PLDM_BIOS_ENUMERATION:
678         case PLDM_BIOS_ENUMERATION_READ_ONLY:
679         {
680             auto count = pldm_bios_table_attr_value_entry_enum_decode_number(
681                 attrValueEntry);
682             std::vector<uint8_t> handles(count);
683             pldm_bios_table_attr_value_entry_enum_decode_handles(
684                 attrValueEntry, handles.data(), handles.size());
685 
686             for (uint8_t handle : handles)
687             {
688                 auto nwVal = displayStringHandle(attrHandle, handle, attrTable,
689                                                  stringTable);
690                 auto chkBMC = isBMC ? "true" : "false";
691                 info(
692                     "BIOS:{ATTR_NAME}, updated to value: {NEW_VAL}, by BMC: {CHK_BMC} ",
693                     "ATTR_NAME", attrName, "NEW_VAL", nwVal, "CHK_BMC", chkBMC);
694             }
695             break;
696         }
697         case PLDM_BIOS_INTEGER:
698         case PLDM_BIOS_INTEGER_READ_ONLY:
699         {
700             auto value =
701                 table::attribute_value::decodeIntegerEntry(attrValueEntry);
702             auto chkBMC = isBMC ? "true" : "false";
703             info(
704                 "BIOS:  {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}",
705                 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC);
706             break;
707         }
708         case PLDM_BIOS_STRING:
709         case PLDM_BIOS_STRING_READ_ONLY:
710         {
711             auto value =
712                 table::attribute_value::decodeStringEntry(attrValueEntry);
713             auto chkBMC = isBMC ? "true" : "false";
714             info(
715                 "BIOS:  {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}",
716                 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC);
717             break;
718         }
719         default:
720             break;
721     };
722 }
723 
724 int BIOSConfig::checkAttrValueToUpdate(
725     const pldm_bios_attr_val_table_entry* attrValueEntry,
726     const pldm_bios_attr_table_entry* attrEntry, Table&)
727 
728 {
729     auto [attrHandle, attrType] =
730         table::attribute_value::decodeHeader(attrValueEntry);
731 
732     switch (attrType)
733     {
734         case PLDM_BIOS_ENUMERATION:
735         case PLDM_BIOS_ENUMERATION_READ_ONLY:
736         {
737             auto value =
738                 table::attribute_value::decodeEnumEntry(attrValueEntry);
739             auto [pvHdls, defIndex] =
740                 table::attribute::decodeEnumEntry(attrEntry);
741             if (!(value.size() == 1))
742             {
743                 return PLDM_ERROR_INVALID_LENGTH;
744             }
745             if (value[0] >= pvHdls.size())
746             {
747                 error("Enum: Illgeal index, Index = {ATTR_INDEX}", "ATTR_INDEX",
748                       (int)value[0]);
749                 return PLDM_ERROR_INVALID_DATA;
750             }
751             return PLDM_SUCCESS;
752         }
753         case PLDM_BIOS_INTEGER:
754         case PLDM_BIOS_INTEGER_READ_ONLY:
755         {
756             auto value =
757                 table::attribute_value::decodeIntegerEntry(attrValueEntry);
758             auto [lower, upper, scalar, def] =
759                 table::attribute::decodeIntegerEntry(attrEntry);
760 
761             if (value < lower || value > upper)
762             {
763                 error("Integer: out of bound, value = {ATTR_VALUE}",
764                       "ATTR_VALUE", value);
765                 return PLDM_ERROR_INVALID_DATA;
766             }
767             return PLDM_SUCCESS;
768         }
769         case PLDM_BIOS_STRING:
770         case PLDM_BIOS_STRING_READ_ONLY:
771         {
772             auto stringConf = table::attribute::decodeStringEntry(attrEntry);
773             auto value =
774                 table::attribute_value::decodeStringEntry(attrValueEntry);
775             if (value.size() < stringConf.minLength ||
776                 value.size() > stringConf.maxLength)
777             {
778                 error(
779                     "String: Length error, string = {ATTR_VALUE} length {LEN}",
780                     "ATTR_VALUE", value, "LEN", value.size());
781                 return PLDM_ERROR_INVALID_LENGTH;
782             }
783             return PLDM_SUCCESS;
784         }
785         default:
786             error("ReadOnly or Unspported type, type = {ATTR_TYPE}",
787                   "ATTR_TYPE", attrType);
788             return PLDM_ERROR;
789     };
790 }
791 
792 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC,
793                              bool updateDBus, bool updateBaseBIOSTable)
794 {
795     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
796     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
797     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
798     if (!attrValueTable || !attrTable || !stringTable)
799     {
800         return PLDM_BIOS_TABLE_UNAVAILABLE;
801     }
802 
803     auto attrValueEntry =
804         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
805 
806     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
807 
808     auto attrEntry =
809         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
810     if (!attrEntry)
811     {
812         return PLDM_ERROR;
813     }
814 
815     auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
816     if (rc != PLDM_SUCCESS)
817     {
818         return rc;
819     }
820 
821     auto destTable =
822         table::attribute_value::updateTable(*attrValueTable, entry, size);
823 
824     if (!destTable)
825     {
826         return PLDM_ERROR;
827     }
828 
829     try
830     {
831         auto attrHeader = table::attribute::decodeHeader(attrEntry);
832 
833         BIOSStringTable biosStringTable(*stringTable);
834         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
835         auto iter = std::find_if(
836             biosAttributes.begin(), biosAttributes.end(),
837             [&attrName](const auto& attr) { return attr->name == attrName; });
838 
839         if (iter == biosAttributes.end())
840         {
841             return PLDM_ERROR;
842         }
843         if (updateDBus)
844         {
845             (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
846                                         biosStringTable);
847         }
848     }
849     catch (const std::exception& e)
850     {
851         error("Set attribute value error: {ERR_EXCEP}", "ERR_EXCEP", e.what());
852         return PLDM_ERROR;
853     }
854 
855     setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
856 
857     traceBIOSUpdate(attrValueEntry, attrEntry, isBMC);
858 
859     return PLDM_SUCCESS;
860 }
861 
862 void BIOSConfig::removeTables()
863 {
864     try
865     {
866         fs::remove(tableDir / stringTableFile);
867         fs::remove(tableDir / attrTableFile);
868         fs::remove(tableDir / attrValueTableFile);
869     }
870     catch (const std::exception& e)
871     {
872         error("Remove the tables error: {ERR_EXCEP}", "ERR_EXCEP", e.what());
873     }
874 }
875 
876 void BIOSConfig::processBiosAttrChangeNotification(
877     const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
878 {
879     const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
880     const auto& propertyName = dBusMap->propertyName;
881     const auto& attrName = biosAttributes[biosAttrIndex]->name;
882 
883     const auto it = chProperties.find(propertyName);
884     if (it == chProperties.end())
885     {
886         return;
887     }
888 
889     PropertyValue newPropVal = it->second;
890     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
891     if (!stringTable.has_value())
892     {
893         error("BIOS string table unavailable");
894         return;
895     }
896     BIOSStringTable biosStringTable(*stringTable);
897     uint16_t attrNameHdl{};
898     try
899     {
900         attrNameHdl = biosStringTable.findHandle(attrName);
901     }
902     catch (const std::invalid_argument& e)
903     {
904         error("Could not find handle for BIOS string, ATTRIBUTE={ATTR_NAME}",
905               "ATTR_NAME", attrName.c_str());
906         return;
907     }
908 
909     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
910     if (!attrTable.has_value())
911     {
912         error("Attribute table not present");
913         return;
914     }
915     const struct pldm_bios_attr_table_entry* tableEntry =
916         table::attribute::findByStringHandle(*attrTable, attrNameHdl);
917     if (tableEntry == nullptr)
918     {
919         error(
920             "Attribute not found in attribute table, name= {ATTR_NAME} name handle={ATTR_HANDLE}",
921             "ATTR_NAME", attrName.c_str(), "ATTR_HANDLE", attrNameHdl);
922         return;
923     }
924 
925     auto [attrHdl, attrType, stringHdl] =
926         table::attribute::decodeHeader(tableEntry);
927 
928     auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
929 
930     if (!attrValueSrcTable.has_value())
931     {
932         error("Attribute value table not present");
933         return;
934     }
935 
936     Table newValue;
937     auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
938         newValue, attrHdl, attrType, newPropVal);
939     if (rc != PLDM_SUCCESS)
940     {
941         error(
942             "Could not update the attribute value table for attribute handle={ATTR_HANDLE} and type={ATTR_TYPE}",
943             "ATTR_HANDLE", attrHdl, "ATTR_TYPE", (uint32_t)attrType);
944         return;
945     }
946     auto destTable = table::attribute_value::updateTable(
947         *attrValueSrcTable, newValue.data(), newValue.size());
948     if (destTable.has_value())
949     {
950         storeTable(tableDir / attrValueTableFile, *destTable);
951     }
952 
953     rc = setAttrValue(newValue.data(), newValue.size(), true, false);
954     if (rc != PLDM_SUCCESS)
955     {
956         error("could not setAttrValue on base bios table and dbus, rc = {RC}",
957               "RC", rc);
958     }
959 }
960 
961 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
962 {
963     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
964     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
965 
966     BIOSStringTable biosStringTable(*stringTable);
967     pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
968         attrTable->data(), attrTable->size());
969     auto stringHandle = biosStringTable.findHandle(attrName);
970 
971     for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
972              attrTable->data(), attrTable->size()))
973     {
974         auto header = table::attribute::decodeHeader(entry);
975         if (header.stringHandle == stringHandle)
976         {
977             return header.attrHandle;
978         }
979     }
980 
981     throw std::invalid_argument("Unknow attribute Name");
982 }
983 
984 void BIOSConfig::constructPendingAttribute(
985     const PendingAttributes& pendingAttributes)
986 {
987     std::vector<uint16_t> listOfHandles{};
988 
989     for (auto& attribute : pendingAttributes)
990     {
991         std::string attributeName = attribute.first;
992         auto& [attributeType, attributevalue] = attribute.second;
993 
994         auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
995                                  [&attributeName](const auto& attr) {
996                                      return attr->name == attributeName;
997                                  });
998 
999         if (iter == biosAttributes.end())
1000         {
1001             error("Wrong attribute name, attributeName = {ATTR_NAME}",
1002                   "ATTR_NAME", attributeName);
1003             continue;
1004         }
1005 
1006         Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
1007         auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
1008             attrValueEntry.data());
1009 
1010         auto handler = findAttrHandle(attributeName);
1011         auto type =
1012             BIOSConfigManager::convertAttributeTypeFromString(attributeType);
1013 
1014         if (type != BIOSConfigManager::AttributeType::Enumeration &&
1015             type != BIOSConfigManager::AttributeType::String &&
1016             type != BIOSConfigManager::AttributeType::Integer)
1017         {
1018             error("Attribute type not supported, attributeType = {ATTR_TYPE}",
1019                   "ATTR_TYPE", attributeType);
1020             continue;
1021         }
1022 
1023         const auto [attrType, readonlyStatus, displayName, description,
1024                     menuPath, currentValue, defaultValue, option] =
1025             baseBIOSTableMaps.at(attributeName);
1026 
1027         entry->attr_handle = htole16(handler);
1028 
1029         // Need to verify that the current value has really changed
1030         if (attributeType == attrType && attributevalue != currentValue)
1031         {
1032             listOfHandles.emplace_back(htole16(handler));
1033         }
1034 
1035         (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
1036 
1037         setAttrValue(attrValueEntry.data(), attrValueEntry.size(), true);
1038     }
1039 
1040     if (listOfHandles.size())
1041     {
1042 #ifdef OEM_IBM
1043         auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
1044             eid, requester, listOfHandles, handler);
1045         if (rc != PLDM_SUCCESS)
1046         {
1047             return;
1048         }
1049 #endif
1050     }
1051 }
1052 
1053 void BIOSConfig::listenPendingAttributes()
1054 {
1055     constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
1056     constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
1057 
1058     using namespace sdbusplus::bus::match::rules;
1059     auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>(
1060         pldm::utils::DBusHandler::getBus(),
1061         propertiesChanged(objPath, objInterface),
1062         [this](sdbusplus::message_t& msg) {
1063             constexpr auto propertyName = "PendingAttributes";
1064 
1065             using Value =
1066                 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
1067             using Properties = std::map<DbusProp, Value>;
1068 
1069             Properties props{};
1070             std::string intf;
1071             msg.read(intf, props);
1072 
1073             auto valPropMap = props.find(propertyName);
1074             if (valPropMap == props.end())
1075             {
1076                 return;
1077             }
1078 
1079             PendingAttributes pendingAttributes =
1080                 std::get<PendingAttributes>(valPropMap->second);
1081             this->constructPendingAttribute(pendingAttributes);
1082         });
1083 
1084     biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
1085 }
1086 
1087 } // namespace bios
1088 } // namespace responder
1089 } // namespace pldm
1090