blob: a80771b75691f9158aa2fdd510f7ad705593f5fc [file] [log] [blame]
Tom Joseph52552ef2019-06-20 09:50:15 +05301#include "bios_parser.hpp"
2
3#include "libpldmresponder/utils.hpp"
4
5#include <filesystem>
6#include <fstream>
7#include <nlohmann/json.hpp>
8#include <optional>
9#include <phosphor-logging/log.hpp>
10
John Wangecb7d572019-10-17 13:38:53 +080011#include "libpldm/bios_table.h"
12
Tom Joseph52552ef2019-06-20 09:50:15 +053013namespace bios_parser
14{
15
16using Json = nlohmann::json;
17namespace fs = std::filesystem;
18using namespace phosphor::logging;
Tom Joseph52552ef2019-06-20 09:50:15 +053019
Carol Wang612f35b2019-08-26 17:14:26 +080020const std::vector<Json> emptyJsonList{};
21const Json emptyJson{};
22
John Wange96e7e52019-10-05 17:47:30 +080023struct DBusMapping
24{
25 std::string objectPath; //!< D-Bus object path
26 std::string interface; //!< D-Bus interface
27 std::string propertyName; //!< D-Bus property name
28};
Carol Wang612f35b2019-08-26 17:14:26 +080029
John Wange96e7e52019-10-05 17:47:30 +080030using AttrName = std::string;
31using BIOSJsonName = std::string;
32using AttrLookup = std::map<AttrName, std::optional<DBusMapping>>;
33using BIOSStringHandler =
34 std::function<int(const Json& entry, Strings& strings)>;
35using AttrLookupHandler = std::function<int(const Json& entry, AttrLookup)>;
36using typeHandler = std::function<int(const Json& entry)>;
37
38Strings BIOSStrings;
39AttrLookup BIOSAttrLookup;
40
41const Strings& getStrings()
42{
43 return BIOSStrings;
44}
45
46int parseBiosJsonFile(const fs::path& dirPath, const std::string& fileName,
Carol Wang612f35b2019-08-26 17:14:26 +080047 Json& fileData)
48{
49 int rc = 0;
50
John Wange96e7e52019-10-05 17:47:30 +080051 fs::path filePath = dirPath / fileName;
Carol Wang612f35b2019-08-26 17:14:26 +080052
53 std::ifstream jsonFile(filePath);
54 if (!jsonFile.is_open())
55 {
56 log<level::ERR>("BIOS config file does not exist",
57 entry("FILE=%s", filePath.c_str()));
58 rc = -1;
59 }
60 else
61 {
62 fileData = Json::parse(jsonFile, nullptr, false);
63 if (fileData.is_discarded())
64 {
65 log<level::ERR>("Parsing config file failed",
66 entry("FILE=%s", filePath.c_str()));
67 rc = -1;
68 }
69 }
70
71 return rc;
72}
73
Tom Joseph52552ef2019-06-20 09:50:15 +053074namespace bios_enum
75{
76
77namespace internal
78{
79
80using PropertyValue =
81 std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
82 uint64_t, double, std::string>;
83using Value = std::string;
84
John Wange96e7e52019-10-05 17:47:30 +080085/** @brief Map of DBus property value to attribute value
Tom Joseph52552ef2019-06-20 09:50:15 +053086 */
John Wange96e7e52019-10-05 17:47:30 +080087using DbusValToValMap = std::map<PropertyValue, Value>;
88
89/** @brief Map containing the DBus property value to attribute value map for the
90 * BIOS enumeration type attributes
91 */
92std::map<AttrName, DbusValToValMap> dbusValToValMaps;
Tom Joseph52552ef2019-06-20 09:50:15 +053093
94/** @brief Map containing the possible and the default values for the BIOS
95 * enumeration type attributes.
96 */
97AttrValuesMap valueMap;
98
Tom Joseph52552ef2019-06-20 09:50:15 +053099/** @brief Populate the mapping between D-Bus property value and attribute value
100 * for the BIOS enumeration attribute.
101 *
102 * @param[in] type - type of the D-Bus property
103 * @param[in] dBusValues - json array of D-Bus property values
104 * @param[in] pv - Possible values for the BIOS enumeration attribute
Tom Joseph52552ef2019-06-20 09:50:15 +0530105 *
106 */
John Wange96e7e52019-10-05 17:47:30 +0800107DbusValToValMap populateMapping(const std::string& type, const Json& dBusValues,
108 const PossibleValues& pv)
Tom Joseph52552ef2019-06-20 09:50:15 +0530109{
110 size_t pos = 0;
111 PropertyValue value;
John Wange96e7e52019-10-05 17:47:30 +0800112 DbusValToValMap valueMap;
Tom Joseph52552ef2019-06-20 09:50:15 +0530113 for (auto it = dBusValues.begin(); it != dBusValues.end(); ++it, ++pos)
114 {
115 if (type == "uint8_t")
116 {
117 value = static_cast<uint8_t>(it.value());
118 }
119 else if (type == "uint16_t")
120 {
121 value = static_cast<uint16_t>(it.value());
122 }
123 else if (type == "uint32_t")
124 {
125 value = static_cast<uint32_t>(it.value());
126 }
127 else if (type == "uint64_t")
128 {
129 value = static_cast<uint64_t>(it.value());
130 }
131 else if (type == "int16_t")
132 {
133 value = static_cast<int16_t>(it.value());
134 }
135 else if (type == "int32_t")
136 {
137 value = static_cast<int32_t>(it.value());
138 }
139 else if (type == "int64_t")
140 {
141 value = static_cast<int64_t>(it.value());
142 }
143 else if (type == "bool")
144 {
145 value = static_cast<bool>(it.value());
146 }
147 else if (type == "double")
148 {
149 value = static_cast<double>(it.value());
150 }
151 else if (type == "string")
152 {
153 value = static_cast<std::string>(it.value());
154 }
155 else
156 {
157 log<level::ERR>("Unknown D-Bus property type",
158 entry("TYPE=%s", type.c_str()));
159 }
160
John Wange96e7e52019-10-05 17:47:30 +0800161 valueMap.emplace(value, pv[pos]);
Tom Joseph52552ef2019-06-20 09:50:15 +0530162 }
163
John Wange96e7e52019-10-05 17:47:30 +0800164 return valueMap;
Tom Joseph52552ef2019-06-20 09:50:15 +0530165}
166
167} // namespace internal
168
John Wange96e7e52019-10-05 17:47:30 +0800169int setupBIOSStrings(const Json& entry, Strings& strings)
Tom Joseph52552ef2019-06-20 09:50:15 +0530170{
John Wange96e7e52019-10-05 17:47:30 +0800171 Json pvs = entry.value("possible_values", emptyJsonList);
Tom Joseph52552ef2019-06-20 09:50:15 +0530172
John Wange96e7e52019-10-05 17:47:30 +0800173 for (auto& pv : pvs)
Tom Joseph52552ef2019-06-20 09:50:15 +0530174 {
John Wange96e7e52019-10-05 17:47:30 +0800175 strings.emplace_back(std::move(pv.get<std::string>()));
Tom Joseph52552ef2019-06-20 09:50:15 +0530176 }
177
John Wange96e7e52019-10-05 17:47:30 +0800178 return 0;
179}
Tom Joseph52552ef2019-06-20 09:50:15 +0530180
John Wange96e7e52019-10-05 17:47:30 +0800181int setup(const Json& entry)
182{
183 PossibleValues possibleValues;
184 DefaultValues defaultValues;
185
186 std::string attrName = entry.value("attribute_name", "");
187 Json pv = entry["possible_values"];
188 for (auto& val : pv)
Tom Joseph52552ef2019-06-20 09:50:15 +0530189 {
John Wange96e7e52019-10-05 17:47:30 +0800190 possibleValues.emplace_back(std::move(val));
Tom Joseph52552ef2019-06-20 09:50:15 +0530191 }
John Wange96e7e52019-10-05 17:47:30 +0800192 Json dv = entry["default_values"];
193 for (auto& val : dv)
Tom Joseph52552ef2019-06-20 09:50:15 +0530194 {
John Wange96e7e52019-10-05 17:47:30 +0800195 defaultValues.emplace_back(std::move(val));
Tom Joseph52552ef2019-06-20 09:50:15 +0530196 }
John Wange96e7e52019-10-05 17:47:30 +0800197 if (entry.count("dbus") != 0)
Tom Joseph52552ef2019-06-20 09:50:15 +0530198 {
John Wange96e7e52019-10-05 17:47:30 +0800199 auto dbusEntry = entry.value("dbus", emptyJson);
200 std::string propertyType = dbusEntry.value("property_type", "");
201 Json propValues = dbusEntry["property_values"];
202 internal::dbusValToValMaps.emplace(
203 attrName, internal::populateMapping(propertyType, propValues,
204 possibleValues));
Tom Joseph52552ef2019-06-20 09:50:15 +0530205 }
John Wange96e7e52019-10-05 17:47:30 +0800206 // Defaulting all the types of attributes to BIOSEnumeration
207 internal::valueMap.emplace(std::move(attrName),
208 std::make_tuple(entry.count("dbus") == 0,
209 std::move(possibleValues),
210 std::move(defaultValues)));
211 return 0;
Tom Joseph52552ef2019-06-20 09:50:15 +0530212}
213
214const AttrValuesMap& getValues()
215{
216 return internal::valueMap;
217}
218
219CurrentValues getAttrValue(const AttrName& attrName)
220{
John Wange96e7e52019-10-05 17:47:30 +0800221 const auto& dBusMap = BIOSAttrLookup.at(attrName);
Tom Joseph52552ef2019-06-20 09:50:15 +0530222 CurrentValues currentValues;
223 internal::PropertyValue propValue;
224
225 if (dBusMap == std::nullopt)
226 {
227 const auto& valueEntry = internal::valueMap.at(attrName);
228 const auto& [readOnly, possibleValues, currentValues] = valueEntry;
229 return currentValues;
230 }
231
John Wange96e7e52019-10-05 17:47:30 +0800232 const auto& dbusValToValMap = internal::dbusValToValMaps.at(attrName);
John Wang8b85f522019-10-17 19:28:19 +0800233 propValue =
234 pldm::responder::DBusHandler()
235 .getDbusPropertyVariant<internal::PropertyValue>(
236 dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
237 dBusMap->interface.c_str());
Tom Joseph52552ef2019-06-20 09:50:15 +0530238
John Wange96e7e52019-10-05 17:47:30 +0800239 auto iter = dbusValToValMap.find(propValue);
240 if (iter != dbusValToValMap.end())
Tom Joseph52552ef2019-06-20 09:50:15 +0530241 {
242 currentValues.push_back(iter->second);
243 }
244
245 return currentValues;
246}
247
248} // namespace bios_enum
249
Carol Wang612f35b2019-08-26 17:14:26 +0800250namespace bios_string
251{
252
253/** @brief BIOS string types
254 */
255enum BiosStringEncoding
256{
257 UNKNOWN = 0x00,
258 ASCII = 0x01,
259 HEX = 0x02,
260 UTF_8 = 0x03,
261 UTF_16LE = 0x04,
262 UTF_16BE = 0x05,
263 VENDOR_SPECIFIC = 0xFF
264};
265
266const std::map<std::string, uint8_t> strTypeMap{
267 {"Unknown", UNKNOWN},
268 {"ASCII", ASCII},
269 {"Hex", HEX},
270 {"UTF-8", UTF_8},
271 {"UTF-16LE", UTF_16LE},
272 {"UTF-16LE", UTF_16LE},
273 {"Vendor Specific", VENDOR_SPECIFIC}};
274
275namespace internal
276{
277
Carol Wang612f35b2019-08-26 17:14:26 +0800278/** @brief Map containing the possible and the default values for the BIOS
279 * string type attributes.
280 */
281AttrValuesMap valueMap;
282
Carol Wang612f35b2019-08-26 17:14:26 +0800283} // namespace internal
284
John Wangecb7d572019-10-17 13:38:53 +0800285int setup(const Json& jsonEntry)
Carol Wang612f35b2019-08-26 17:14:26 +0800286{
Carol Wang612f35b2019-08-26 17:14:26 +0800287
John Wangecb7d572019-10-17 13:38:53 +0800288 std::string attr = jsonEntry.value("attribute_name", "");
John Wange96e7e52019-10-05 17:47:30 +0800289 // Transfer string type from string to enum
John Wangecb7d572019-10-17 13:38:53 +0800290 std::string strTypeTmp = jsonEntry.value("string_type", "Unknown");
John Wange96e7e52019-10-05 17:47:30 +0800291 auto iter = strTypeMap.find(strTypeTmp);
292 if (iter == strTypeMap.end())
Carol Wang612f35b2019-08-26 17:14:26 +0800293 {
John Wangecb7d572019-10-17 13:38:53 +0800294 log<level::ERR>("Wrong string type",
295 entry("STRING_TYPE=%s", strTypeTmp.c_str()),
296 entry("ATTRIBUTE_NAME=%s", attr.c_str()));
John Wange96e7e52019-10-05 17:47:30 +0800297 return -1;
298 }
299 uint8_t strType = iter->second;
300
John Wangecb7d572019-10-17 13:38:53 +0800301 uint16_t minStrLen = jsonEntry.value("minimum_string_length", 0);
302 uint16_t maxStrLen = jsonEntry.value("maximum_string_length", 0);
303 uint16_t defaultStrLen = jsonEntry.value("default_string_length", 0);
304 std::string defaultStr = jsonEntry.value("default_string", "");
305
306 pldm_bios_table_attr_entry_string_info info = {
307 0, /* name handle */
308 false, /* read only */
309 strType, minStrLen, maxStrLen, defaultStrLen, defaultStr.data(),
310 };
311
312 const char* errmsg;
313 auto rc = pldm_bios_table_attr_entry_string_info_check(&info, &errmsg);
314 if (rc != PLDM_SUCCESS)
John Wange96e7e52019-10-05 17:47:30 +0800315 {
John Wangecb7d572019-10-17 13:38:53 +0800316 log<level::ERR>("Wrong filed for string attribute",
317 entry("ATTRIBUTE_NAME=%s", attr.c_str()),
318 entry("ERRMSG=%s", errmsg),
319 entry("MINIMUM_STRING_LENGTH=%u", minStrLen),
320 entry("MAXIMUM_STRING_LENGTH=%u", maxStrLen),
321 entry("DEFAULT_STRING_LENGTH=%u", defaultStrLen),
322 entry("DEFAULT_STRING=%s", defaultStr.data()));
John Wange96e7e52019-10-05 17:47:30 +0800323 return -1;
Carol Wang612f35b2019-08-26 17:14:26 +0800324 }
325
John Wange96e7e52019-10-05 17:47:30 +0800326 // Defaulting all the types of attributes to BIOSString
327 internal::valueMap.emplace(
328 std::move(attr),
John Wangecb7d572019-10-17 13:38:53 +0800329 std::make_tuple(jsonEntry.count("dbus") == 0, strType, minStrLen,
330 maxStrLen, defaultStrLen, std::move(defaultStr)));
Carol Wang612f35b2019-08-26 17:14:26 +0800331
John Wange96e7e52019-10-05 17:47:30 +0800332 return 0;
Carol Wang612f35b2019-08-26 17:14:26 +0800333}
334
335const AttrValuesMap& getValues()
336{
337 return internal::valueMap;
338}
Carol Wangb503f9e2019-09-02 16:34:10 +0800339
340std::string getAttrValue(const AttrName& attrName)
341{
John Wange96e7e52019-10-05 17:47:30 +0800342 const auto& dBusMap = BIOSAttrLookup.at(attrName);
Carol Wangb503f9e2019-09-02 16:34:10 +0800343 std::variant<std::string> propValue;
344
345 if (dBusMap == std::nullopt)
346 { // return default string
347 const auto& valueEntry = internal::valueMap.at(attrName);
348 return std::get<DefaultStr>(valueEntry);
349 }
350
John Wang8b85f522019-10-17 19:28:19 +0800351 return pldm::responder::DBusHandler().getDbusProperty<std::string>(
352 dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
353 dBusMap->interface.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800354}
355
Carol Wang612f35b2019-08-26 17:14:26 +0800356} // namespace bios_string
357
John Wangecb7d572019-10-17 13:38:53 +0800358namespace bios_integer
359{
360
361AttrValuesMap valueMap;
362
363int setup(const Json& jsonEntry)
364{
365
366 std::string attr = jsonEntry.value("attribute_name", "");
367 // Transfer string type from string to enum
368
369 uint64_t lowerBound = jsonEntry.value("lower_bound", 0);
370 uint64_t upperBound = jsonEntry.value("upper_bound", 0);
371 uint32_t scalarIncrement = jsonEntry.value("scalar_increment", 1);
372 uint64_t defaultValue = jsonEntry.value("default_value", 0);
373 pldm_bios_table_attr_entry_integer_info info = {
374 0, /* name handle*/
375 false, /* read only */
376 lowerBound, upperBound, scalarIncrement, defaultValue,
377 };
378 const char* errmsg = nullptr;
379 auto rc = pldm_bios_table_attr_entry_integer_info_check(&info, &errmsg);
380 if (rc != PLDM_SUCCESS)
381 {
382 log<level::ERR>("Wrong filed for integer attribute",
383 entry("ATTRIBUTE_NAME=%s", attr.c_str()),
384 entry("ERRMSG=%s", errmsg),
385 entry("LOWER_BOUND=%llu", lowerBound),
386 entry("UPPER_BOUND=%llu", upperBound),
387 entry("DEFAULT_VALUE=%llu", defaultValue),
388 entry("SCALAR_INCREMENT=%lu", scalarIncrement));
389 return -1;
390 }
391
392 valueMap.emplace(std::move(attr),
393 std::make_tuple(jsonEntry.count("dbus") == 0, lowerBound,
394 upperBound, scalarIncrement,
395 defaultValue));
396
397 return 0;
398}
399
400const AttrValuesMap& getValues()
401{
402 return valueMap;
403}
404
405uint64_t getAttrValue(const AttrName& attrName)
406{
407 const auto& dBusMap = BIOSAttrLookup.at(attrName);
408 std::variant<std::string> propValue;
409
410 if (dBusMap == std::nullopt)
411 { // return default string
412 const auto& valueEntry = valueMap.at(attrName);
413 return std::get<AttrDefaultValue>(valueEntry);
414 }
415
416 return pldm::responder::DBusHandler().getDbusProperty<uint64_t>(
417 dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
418 dBusMap->interface.c_str());
419}
420
421} // namespace bios_integer
422
John Wange96e7e52019-10-05 17:47:30 +0800423const std::map<BIOSJsonName, BIOSStringHandler> BIOSStringHandlers = {
424 {bIOSEnumJson, bios_enum::setupBIOSStrings},
425};
Tom Joseph52552ef2019-06-20 09:50:15 +0530426
John Wange96e7e52019-10-05 17:47:30 +0800427const std::map<BIOSJsonName, typeHandler> BIOSTypeHandlers = {
428 {bIOSEnumJson, bios_enum::setup},
429 {bIOSStrJson, bios_string::setup},
John Wangecb7d572019-10-17 13:38:53 +0800430 {bIOSIntegerJson, bios_integer::setup},
John Wange96e7e52019-10-05 17:47:30 +0800431};
432
433void setupBIOSStrings(const BIOSJsonName& jsonName, const Json& entry,
434 Strings& strings)
435{
436 strings.emplace_back(entry.value("attribute_name", ""));
437 auto iter = BIOSStringHandlers.find(jsonName);
438 if (iter != BIOSStringHandlers.end())
439 {
440 iter->second(entry, strings);
441 }
442}
443
John Wangecb7d572019-10-17 13:38:53 +0800444void setupBIOSAttrLookup(const Json& jsonEntry, AttrLookup& lookup)
John Wange96e7e52019-10-05 17:47:30 +0800445{
446 std::optional<DBusMapping> dBusMap;
John Wangecb7d572019-10-17 13:38:53 +0800447 std::string attrName = jsonEntry.value("attribute_name", "");
John Wange96e7e52019-10-05 17:47:30 +0800448
John Wangecb7d572019-10-17 13:38:53 +0800449 if (jsonEntry.count("dbus") != 0)
John Wange96e7e52019-10-05 17:47:30 +0800450 {
John Wangecb7d572019-10-17 13:38:53 +0800451 auto dBusEntry = jsonEntry.value("dbus", emptyJson);
John Wange96e7e52019-10-05 17:47:30 +0800452 std::string objectPath = dBusEntry.value("object_path", "");
453 std::string interface = dBusEntry.value("interface", "");
454 std::string propertyName = dBusEntry.value("property_name", "");
455 if (!objectPath.empty() && !interface.empty() && !propertyName.empty())
456 {
457 dBusMap = std::optional<DBusMapping>(
458 {objectPath, interface, propertyName});
459 }
460 else
461 {
462 log<level::ERR>(
463 "Invalid dbus config",
John Wangecb7d572019-10-17 13:38:53 +0800464 entry("OBJPATH=%s", dBusMap->objectPath.c_str()),
465 entry("INTERFACE=%s", dBusMap->interface.c_str()),
466 entry("PROPERTY_NAME=%s", dBusMap->propertyName.c_str()));
John Wange96e7e52019-10-05 17:47:30 +0800467 }
468 }
469 lookup.emplace(attrName, dBusMap);
470}
471
472int setupBIOSType(const BIOSJsonName& jsonName, const Json& entry)
473{
474 auto iter = BIOSTypeHandlers.find(jsonName);
475 if (iter != BIOSTypeHandlers.end())
476 {
477 iter->second(entry);
478 }
479 return 0;
480}
481
John Wangecb7d572019-10-17 13:38:53 +0800482const std::vector<BIOSJsonName> BIOSConfigFiles = {bIOSEnumJson, bIOSStrJson,
483 bIOSIntegerJson};
John Wange96e7e52019-10-05 17:47:30 +0800484
485int setupConfig(const char* dirPath)
486{
487 if (!BIOSStrings.empty() && !BIOSAttrLookup.empty())
488 {
489 return 0;
490 }
491
492 fs::path dir(dirPath);
Tom Joseph52552ef2019-06-20 09:50:15 +0530493 if (!fs::exists(dir) || fs::is_empty(dir))
494 {
John Wange96e7e52019-10-05 17:47:30 +0800495 log<level::ERR>("BIOS config directory does not exist or empty",
496 entry("DIR=%s", dirPath));
497 return -1;
Tom Joseph52552ef2019-06-20 09:50:15 +0530498 }
John Wange96e7e52019-10-05 17:47:30 +0800499 for (auto jsonName : BIOSConfigFiles)
Tom Joseph52552ef2019-06-20 09:50:15 +0530500 {
John Wange96e7e52019-10-05 17:47:30 +0800501 Json json;
502 if (parseBiosJsonFile(dir, jsonName, json) < 0)
Tom Joseph52552ef2019-06-20 09:50:15 +0530503 {
Tom Joseph52552ef2019-06-20 09:50:15 +0530504 continue;
505 }
John Wange96e7e52019-10-05 17:47:30 +0800506 auto entries = json.value("entries", emptyJsonList);
Tom Joseph52552ef2019-06-20 09:50:15 +0530507 for (auto& entry : entries)
508 {
John Wange96e7e52019-10-05 17:47:30 +0800509 setupBIOSStrings(jsonName, entry, BIOSStrings);
510 setupBIOSAttrLookup(entry, BIOSAttrLookup);
511 setupBIOSType(jsonName, entry);
Tom Joseph52552ef2019-06-20 09:50:15 +0530512 }
513 }
John Wange96e7e52019-10-05 17:47:30 +0800514 if (BIOSStrings.empty())
515 { // means there is no attribute
516 log<level::ERR>("No attribute is found in the config directory",
517 entry("DIR=%s", dirPath));
518 return -1;
519 }
520 return 0;
Tom Joseph52552ef2019-06-20 09:50:15 +0530521}
522
523} // namespace bios_parser