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