1 #include "bios_config.hpp"
2 
3 #include "bios_integer_attribute.hpp"
4 #include "bios_string_attribute.hpp"
5 
6 #include <fstream>
7 #include <iostream>
8 
9 namespace pldm
10 {
11 namespace responder
12 {
13 namespace bios
14 {
15 namespace
16 {
17 
18 constexpr auto enumJsonFile = "enum_attrs.json";
19 constexpr auto stringJsonFile = "string_attrs.json";
20 constexpr auto integerJsonFile = "integer_attrs.json";
21 
22 constexpr auto stringTableFile = "stringTable";
23 constexpr auto attrTableFile = "attributeTable";
24 constexpr auto attrValueTableFile = "attributeValueTable";
25 
26 } // namespace
27 
28 BIOSConfig::BIOSConfig(const char* jsonDir, const char* tableDir,
29                        DBusHandler* const dbusHandler) :
30     jsonDir(jsonDir),
31     tableDir(tableDir), dbusHandler(dbusHandler)
32 {
33     constructAttributes();
34 }
35 
36 void BIOSConfig::buildTables()
37 {
38     fs::create_directory(tableDir);
39     auto stringTable = buildAndStoreStringTable();
40     if (stringTable)
41     {
42         buildAndStoreAttrTables(*stringTable);
43     }
44 }
45 
46 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
47 {
48     fs::path tablePath;
49     switch (tableType)
50     {
51         case PLDM_BIOS_STRING_TABLE:
52             tablePath = tableDir / stringTableFile;
53             break;
54         case PLDM_BIOS_ATTR_TABLE:
55             tablePath = tableDir / attrTableFile;
56             break;
57         case PLDM_BIOS_ATTR_VAL_TABLE:
58             tablePath = tableDir / attrValueTableFile;
59             break;
60     }
61     return loadTable(tablePath);
62 }
63 
64 void BIOSConfig::constructAttributes()
65 {
66     load(jsonDir / stringJsonFile, [this](const Json& entry) {
67         constructAttribute<BIOSStringAttribute>(entry);
68     });
69     load(jsonDir / stringJsonFile, [this](const Json& entry) {
70         constructAttribute<BIOSIntegerAttribute>(entry);
71     });
72 }
73 
74 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
75 {
76     BIOSStringTable biosStringTable(stringTable);
77 
78     if (biosAttributes.empty())
79     {
80         return;
81     }
82 
83     Table attrTable, attrValueTable;
84 
85     for (auto& attr : biosAttributes)
86     {
87         try
88         {
89             attr->constructEntry(biosStringTable, attrTable, attrValueTable);
90         }
91         catch (const std::exception& e)
92         {
93             std::cerr << "Construct Table Entry Error, AttributeName = "
94                       << attr->name << std::endl;
95         }
96     }
97 
98     table::appendPadAndChecksum(attrTable);
99     table::appendPadAndChecksum(attrValueTable);
100 
101     storeTable(tableDir / attrTableFile, attrTable);
102     storeTable(tableDir / attrValueTableFile, attrValueTable);
103 }
104 
105 std::optional<Table> BIOSConfig::buildAndStoreStringTable()
106 {
107     std::set<std::string> strings;
108     auto handler = [&strings](const Json& entry) {
109         strings.emplace(entry.at("attribute_name"));
110     };
111 
112     load(jsonDir / stringJsonFile, handler);
113     load(jsonDir / integerJsonFile, handler);
114     load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
115         strings.emplace(entry.at("attribute_name"));
116         auto possibleValues = entry.at("possible_values");
117         for (auto& pv : possibleValues)
118         {
119             strings.emplace(pv);
120         }
121     });
122 
123     if (strings.empty())
124     {
125         return std::nullopt;
126     }
127 
128     Table table;
129     for (const auto& elem : strings)
130     {
131         table::string::constructEntry(table, elem);
132     }
133 
134     table::appendPadAndChecksum(table);
135     storeTable(tableDir / stringTableFile, table);
136     return table;
137 }
138 
139 void BIOSConfig::storeTable(const fs::path& path, const Table& table)
140 {
141     BIOSTable biosTable(path.c_str());
142     biosTable.store(table);
143 }
144 
145 std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
146 {
147     BIOSTable biosTable(path.c_str());
148     if (biosTable.isEmpty())
149     {
150         return std::nullopt;
151     }
152 
153     Table table;
154     biosTable.load(table);
155     return table;
156 }
157 
158 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
159 {
160     std::ifstream file;
161     Json jsonConf;
162     if (fs::exists(filePath))
163     {
164         try
165         {
166             file.open(filePath);
167             jsonConf = Json::parse(file);
168             auto entries = jsonConf.at("entries");
169             for (auto& entry : entries)
170             {
171                 try
172                 {
173                     handler(entry);
174                 }
175                 catch (const std::exception& e)
176                 {
177                     std::cerr
178                         << "Failed to parse JSON config file(entry handler) : "
179                         << filePath.c_str() << ", " << e.what() << std::endl;
180                 }
181             }
182         }
183         catch (const std::exception& e)
184         {
185             std::cerr << "Failed to parse JSON config file : "
186                       << filePath.c_str() << std::endl;
187         }
188     }
189 }
190 
191 int BIOSConfig::setAttrValue(const void* entry, size_t size)
192 {
193     auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
194     auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
195     auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
196     if (!attrValueTable || !attrTable || !stringTable)
197     {
198         return PLDM_BIOS_TABLE_UNAVAILABLE;
199     }
200 
201     auto destTable =
202         table::attribute_value::updateTable(*attrValueTable, entry, size);
203 
204     if (!destTable)
205     {
206         return PLDM_ERROR;
207     }
208     auto attrValueEntry =
209         reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
210 
211     auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
212 
213     auto attrEntry =
214         table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
215     if (!attrEntry)
216     {
217         return PLDM_ERROR;
218     }
219 
220     try
221     {
222         auto attrHeader = table::attribute::decodeHeader(attrEntry);
223 
224         BIOSStringTable biosStringTable(*stringTable);
225         auto attrName = biosStringTable.findString(attrHeader.stringHandle);
226 
227         auto iter = std::find_if(
228             biosAttributes.begin(), biosAttributes.end(),
229             [&attrName](const auto& attr) { return attr->name == attrName; });
230 
231         if (iter == biosAttributes.end())
232         {
233             return PLDM_ERROR;
234         }
235         (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable);
236     }
237     catch (const std::exception& e)
238     {
239         std::cerr << "Set attribute value error: " << e.what() << std::endl;
240         return PLDM_ERROR;
241     }
242 
243     BIOSTable biosAttrValueTable((tableDir / attrValueTableFile).c_str());
244     biosAttrValueTable.store(*destTable);
245     return PLDM_SUCCESS;
246 }
247 
248 void BIOSConfig::removeTables()
249 {
250     try
251     {
252         fs::remove(tableDir / stringTableFile);
253         fs::remove(tableDir / attrTableFile);
254         fs::remove(tableDir / attrValueTableFile);
255     }
256     catch (const std::exception& e)
257     {
258         std::cerr << "Remove the tables error: " << e.what() << std::endl;
259     }
260 }
261 
262 } // namespace bios
263 } // namespace responder
264 } // namespace pldm
265