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 
8 #include <fstream>
9 #include <iostream>
10 
11 namespace pldm
12 {
13 namespace responder
14 {
15 namespace bios
16 {
17 namespace
18 {
19 
20 constexpr auto enumJsonFile = "enum_attrs.json";
21 constexpr auto stringJsonFile = "string_attrs.json";
22 constexpr auto integerJsonFile = "integer_attrs.json";
23 
24 constexpr auto stringTableFile = "stringTable";
25 constexpr auto attrTableFile = "attributeTable";
26 constexpr auto attrValueTableFile = "attributeValueTable";
27 
28 } // namespace
29 
30 BIOSConfig::BIOSConfig(const char* jsonDir, const char* tableDir,
31                        DBusHandler* const dbusHandler) :
32     jsonDir(jsonDir),
33     tableDir(tableDir), dbusHandler(dbusHandler)
34 {
35     constructAttributes();
36 }
37 
38 void BIOSConfig::buildTables()
39 {
40     fs::create_directory(tableDir);
41     auto stringTable = buildAndStoreStringTable();
42     if (stringTable)
43     {
44         buildAndStoreAttrTables(*stringTable);
45     }
46 }
47 
48 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
49 {
50     fs::path tablePath;
51     switch (tableType)
52     {
53         case PLDM_BIOS_STRING_TABLE:
54             tablePath = tableDir / stringTableFile;
55             break;
56         case PLDM_BIOS_ATTR_TABLE:
57             tablePath = tableDir / attrTableFile;
58             break;
59         case PLDM_BIOS_ATTR_VAL_TABLE:
60             tablePath = tableDir / attrValueTableFile;
61             break;
62     }
63     return loadTable(tablePath);
64 }
65 
66 void BIOSConfig::constructAttributes()
67 {
68     load(jsonDir / stringJsonFile, [this](const Json& entry) {
69         constructAttribute<BIOSStringAttribute>(entry);
70     });
71     load(jsonDir / integerJsonFile, [this](const Json& entry) {
72         constructAttribute<BIOSIntegerAttribute>(entry);
73     });
74     load(jsonDir / enumJsonFile, [this](const Json& entry) {
75         constructAttribute<BIOSEnumAttribute>(entry);
76     });
77 }
78 
79 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
80 {
81     BIOSStringTable biosStringTable(stringTable);
82 
83     if (biosAttributes.empty())
84     {
85         return;
86     }
87 
88     Table attrTable, attrValueTable;
89 
90     for (auto& attr : biosAttributes)
91     {
92         try
93         {
94             attr->constructEntry(biosStringTable, attrTable, attrValueTable);
95         }
96         catch (const std::exception& e)
97         {
98             std::cerr << "Construct Table Entry Error, AttributeName = "
99                       << attr->name << std::endl;
100         }
101     }
102 
103     table::appendPadAndChecksum(attrTable);
104     table::appendPadAndChecksum(attrValueTable);
105 
106     storeTable(tableDir / attrTableFile, attrTable);
107     storeTable(tableDir / attrValueTableFile, attrValueTable);
108 }
109 
110 std::optional<Table> BIOSConfig::buildAndStoreStringTable()
111 {
112     std::set<std::string> strings;
113     auto handler = [&strings](const Json& entry) {
114         strings.emplace(entry.at("attribute_name"));
115     };
116 
117     load(jsonDir / stringJsonFile, handler);
118     load(jsonDir / integerJsonFile, handler);
119     load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
120         strings.emplace(entry.at("attribute_name"));
121         auto possibleValues = entry.at("possible_values");
122         for (auto& pv : possibleValues)
123         {
124             strings.emplace(pv);
125         }
126     });
127 
128     if (strings.empty())
129     {
130         return std::nullopt;
131     }
132 
133     Table table;
134     for (const auto& elem : strings)
135     {
136         table::string::constructEntry(table, elem);
137     }
138 
139     table::appendPadAndChecksum(table);
140     storeTable(tableDir / stringTableFile, table);
141     return table;
142 }
143 
144 void BIOSConfig::storeTable(const fs::path& path, const Table& table)
145 {
146     BIOSTable biosTable(path.c_str());
147     biosTable.store(table);
148 }
149 
150 std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
151 {
152     BIOSTable biosTable(path.c_str());
153     if (biosTable.isEmpty())
154     {
155         return std::nullopt;
156     }
157 
158     Table table;
159     biosTable.load(table);
160     return table;
161 }
162 
163 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
164 {
165     std::ifstream file;
166     Json jsonConf;
167     if (fs::exists(filePath))
168     {
169         try
170         {
171             file.open(filePath);
172             jsonConf = Json::parse(file);
173             auto entries = jsonConf.at("entries");
174             for (auto& entry : entries)
175             {
176                 try
177                 {
178                     handler(entry);
179                 }
180                 catch (const std::exception& e)
181                 {
182                     std::cerr
183                         << "Failed to parse JSON config file(entry handler) : "
184                         << filePath.c_str() << ", " << e.what() << std::endl;
185                 }
186             }
187         }
188         catch (const std::exception& e)
189         {
190             std::cerr << "Failed to parse JSON config file : "
191                       << filePath.c_str() << std::endl;
192         }
193     }
194 }
195 
196 int BIOSConfig::setAttrValue(const void* entry, size_t size)
197 {
198     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
199     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
200     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
201     if (!attrValueTable || !attrTable || !stringTable)
202     {
203         return PLDM_BIOS_TABLE_UNAVAILABLE;
204     }
205 
206     auto destTable =
207         table::attribute_value::updateTable(*attrValueTable, entry, size);
208 
209     if (!destTable)
210     {
211         return PLDM_ERROR;
212     }
213     auto attrValueEntry =
214         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
215 
216     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
217 
218     auto attrEntry =
219         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
220     if (!attrEntry)
221     {
222         return PLDM_ERROR;
223     }
224 
225     try
226     {
227         auto attrHeader = table::attribute::decodeHeader(attrEntry);
228 
229         BIOSStringTable biosStringTable(*stringTable);
230         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
231 
232         auto iter = std::find_if(
233             biosAttributes.begin(), biosAttributes.end(),
234             [&attrName](const auto& attr) { return attr->name == attrName; });
235 
236         if (iter == biosAttributes.end())
237         {
238             return PLDM_ERROR;
239         }
240         (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable);
241     }
242     catch (const std::exception& e)
243     {
244         std::cerr << "Set attribute value error: " << e.what() << std::endl;
245         return PLDM_ERROR;
246     }
247 
248     BIOSTable biosAttrValueTable((tableDir / attrValueTableFile).c_str());
249     biosAttrValueTable.store(*destTable);
250     return PLDM_SUCCESS;
251 }
252 
253 void BIOSConfig::removeTables()
254 {
255     try
256     {
257         fs::remove(tableDir / stringTableFile);
258         fs::remove(tableDir / attrTableFile);
259         fs::remove(tableDir / attrValueTableFile);
260     }
261     catch (const std::exception& e)
262     {
263         std::cerr << "Remove the tables error: " << e.what() << std::endl;
264     }
265 }
266 
267 void BIOSConfig::processBiosAttrChangeNotification(
268     const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
269 {
270     const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
271     const auto& propertyName = dBusMap->propertyName;
272     const auto& attrName = biosAttributes[biosAttrIndex]->name;
273 
274     const auto it = chProperties.find(propertyName);
275     if (it == chProperties.end())
276     {
277         return;
278     }
279 
280     PropertyValue newPropVal = it->second;
281     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
282     if (!stringTable.has_value())
283     {
284         std::cerr << "BIOS string table unavailable\n";
285         return;
286     }
287     BIOSStringTable biosStringTable(*stringTable);
288     uint16_t attrNameHdl{};
289     try
290     {
291         attrNameHdl = biosStringTable.findHandle(attrName);
292     }
293     catch (std::invalid_argument& e)
294     {
295         std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
296                   << attrName.c_str() << "\n";
297         return;
298     }
299 
300     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
301     if (!attrTable.has_value())
302     {
303         std::cerr << "Attribute table not present\n";
304         return;
305     }
306     const struct pldm_bios_attr_table_entry* tableEntry =
307         table::attribute::findByStringHandle(*attrTable, attrNameHdl);
308     if (tableEntry == nullptr)
309     {
310         std::cerr << "Attribute not found in attribute table, name= "
311                   << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
312         return;
313     }
314 
315     auto [attrHdl, attrType, stringHdl] =
316         table::attribute::decodeHeader(tableEntry);
317 
318     auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
319 
320     if (!attrValueSrcTable.has_value())
321     {
322         std::cerr << "Attribute value table not present\n";
323         return;
324     }
325 
326     Table newValue;
327     auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
328         newValue, attrHdl, attrType, newPropVal);
329     if (rc != PLDM_SUCCESS)
330     {
331         std::cerr << "Could not update the attribute value table for attribute "
332                      "handle="
333                   << attrHdl << " and type=" << (uint32_t)attrType << "\n";
334         return;
335     }
336     auto destTable = table::attribute_value::updateTable(
337         *attrValueSrcTable, newValue.data(), newValue.size());
338     if (destTable.has_value())
339     {
340         storeTable(tableDir / attrValueTableFile, *destTable);
341     }
342 }
343 
344 } // namespace bios
345 } // namespace responder
346 } // namespace pldm
347