blob: 0c39acbf75c2bafe272bcfcacd759de14cfb3ecb [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
11namespace bios_parser
12{
13
14using Json = nlohmann::json;
15namespace fs = std::filesystem;
16using namespace phosphor::logging;
Tom Joseph52552ef2019-06-20 09:50:15 +053017
Carol Wang612f35b2019-08-26 17:14:26 +080018const std::vector<Json> emptyJsonList{};
19const Json emptyJson{};
20
John Wange96e7e52019-10-05 17:47:30 +080021struct DBusMapping
22{
23 std::string objectPath; //!< D-Bus object path
24 std::string interface; //!< D-Bus interface
25 std::string propertyName; //!< D-Bus property name
26};
Carol Wang612f35b2019-08-26 17:14:26 +080027
John Wange96e7e52019-10-05 17:47:30 +080028using AttrName = std::string;
29using BIOSJsonName = std::string;
30using AttrLookup = std::map<AttrName, std::optional<DBusMapping>>;
31using BIOSStringHandler =
32 std::function<int(const Json& entry, Strings& strings)>;
33using AttrLookupHandler = std::function<int(const Json& entry, AttrLookup)>;
34using typeHandler = std::function<int(const Json& entry)>;
35
36Strings BIOSStrings;
37AttrLookup BIOSAttrLookup;
38
39const Strings& getStrings()
40{
41 return BIOSStrings;
42}
43
44int parseBiosJsonFile(const fs::path& dirPath, const std::string& fileName,
Carol Wang612f35b2019-08-26 17:14:26 +080045 Json& fileData)
46{
47 int rc = 0;
48
John Wange96e7e52019-10-05 17:47:30 +080049 fs::path filePath = dirPath / fileName;
Carol Wang612f35b2019-08-26 17:14:26 +080050
51 std::ifstream jsonFile(filePath);
52 if (!jsonFile.is_open())
53 {
54 log<level::ERR>("BIOS config file does not exist",
55 entry("FILE=%s", filePath.c_str()));
56 rc = -1;
57 }
58 else
59 {
60 fileData = Json::parse(jsonFile, nullptr, false);
61 if (fileData.is_discarded())
62 {
63 log<level::ERR>("Parsing config file failed",
64 entry("FILE=%s", filePath.c_str()));
65 rc = -1;
66 }
67 }
68
69 return rc;
70}
71
Tom Joseph52552ef2019-06-20 09:50:15 +053072namespace bios_enum
73{
74
75namespace internal
76{
77
78using PropertyValue =
79 std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
80 uint64_t, double, std::string>;
81using Value = std::string;
82
John Wange96e7e52019-10-05 17:47:30 +080083/** @brief Map of DBus property value to attribute value
Tom Joseph52552ef2019-06-20 09:50:15 +053084 */
John Wange96e7e52019-10-05 17:47:30 +080085using DbusValToValMap = std::map<PropertyValue, Value>;
86
87/** @brief Map containing the DBus property value to attribute value map for the
88 * BIOS enumeration type attributes
89 */
90std::map<AttrName, DbusValToValMap> dbusValToValMaps;
Tom Joseph52552ef2019-06-20 09:50:15 +053091
92/** @brief Map containing the possible and the default values for the BIOS
93 * enumeration type attributes.
94 */
95AttrValuesMap valueMap;
96
Tom Joseph52552ef2019-06-20 09:50:15 +053097/** @brief Populate the mapping between D-Bus property value and attribute value
98 * for the BIOS enumeration attribute.
99 *
100 * @param[in] type - type of the D-Bus property
101 * @param[in] dBusValues - json array of D-Bus property values
102 * @param[in] pv - Possible values for the BIOS enumeration attribute
Tom Joseph52552ef2019-06-20 09:50:15 +0530103 *
104 */
John Wange96e7e52019-10-05 17:47:30 +0800105DbusValToValMap populateMapping(const std::string& type, const Json& dBusValues,
106 const PossibleValues& pv)
Tom Joseph52552ef2019-06-20 09:50:15 +0530107{
108 size_t pos = 0;
109 PropertyValue value;
John Wange96e7e52019-10-05 17:47:30 +0800110 DbusValToValMap valueMap;
Tom Joseph52552ef2019-06-20 09:50:15 +0530111 for (auto it = dBusValues.begin(); it != dBusValues.end(); ++it, ++pos)
112 {
113 if (type == "uint8_t")
114 {
115 value = static_cast<uint8_t>(it.value());
116 }
117 else if (type == "uint16_t")
118 {
119 value = static_cast<uint16_t>(it.value());
120 }
121 else if (type == "uint32_t")
122 {
123 value = static_cast<uint32_t>(it.value());
124 }
125 else if (type == "uint64_t")
126 {
127 value = static_cast<uint64_t>(it.value());
128 }
129 else if (type == "int16_t")
130 {
131 value = static_cast<int16_t>(it.value());
132 }
133 else if (type == "int32_t")
134 {
135 value = static_cast<int32_t>(it.value());
136 }
137 else if (type == "int64_t")
138 {
139 value = static_cast<int64_t>(it.value());
140 }
141 else if (type == "bool")
142 {
143 value = static_cast<bool>(it.value());
144 }
145 else if (type == "double")
146 {
147 value = static_cast<double>(it.value());
148 }
149 else if (type == "string")
150 {
151 value = static_cast<std::string>(it.value());
152 }
153 else
154 {
155 log<level::ERR>("Unknown D-Bus property type",
156 entry("TYPE=%s", type.c_str()));
157 }
158
John Wange96e7e52019-10-05 17:47:30 +0800159 valueMap.emplace(value, pv[pos]);
Tom Joseph52552ef2019-06-20 09:50:15 +0530160 }
161
John Wange96e7e52019-10-05 17:47:30 +0800162 return valueMap;
Tom Joseph52552ef2019-06-20 09:50:15 +0530163}
164
165} // namespace internal
166
John Wange96e7e52019-10-05 17:47:30 +0800167int setupBIOSStrings(const Json& entry, Strings& strings)
Tom Joseph52552ef2019-06-20 09:50:15 +0530168{
John Wange96e7e52019-10-05 17:47:30 +0800169 Json pvs = entry.value("possible_values", emptyJsonList);
Tom Joseph52552ef2019-06-20 09:50:15 +0530170
John Wange96e7e52019-10-05 17:47:30 +0800171 for (auto& pv : pvs)
Tom Joseph52552ef2019-06-20 09:50:15 +0530172 {
John Wange96e7e52019-10-05 17:47:30 +0800173 strings.emplace_back(std::move(pv.get<std::string>()));
Tom Joseph52552ef2019-06-20 09:50:15 +0530174 }
175
John Wange96e7e52019-10-05 17:47:30 +0800176 return 0;
177}
Tom Joseph52552ef2019-06-20 09:50:15 +0530178
John Wange96e7e52019-10-05 17:47:30 +0800179int setup(const Json& entry)
180{
181 PossibleValues possibleValues;
182 DefaultValues defaultValues;
183
184 std::string attrName = entry.value("attribute_name", "");
185 Json pv = entry["possible_values"];
186 for (auto& val : pv)
Tom Joseph52552ef2019-06-20 09:50:15 +0530187 {
John Wange96e7e52019-10-05 17:47:30 +0800188 possibleValues.emplace_back(std::move(val));
Tom Joseph52552ef2019-06-20 09:50:15 +0530189 }
John Wange96e7e52019-10-05 17:47:30 +0800190 Json dv = entry["default_values"];
191 for (auto& val : dv)
Tom Joseph52552ef2019-06-20 09:50:15 +0530192 {
John Wange96e7e52019-10-05 17:47:30 +0800193 defaultValues.emplace_back(std::move(val));
Tom Joseph52552ef2019-06-20 09:50:15 +0530194 }
John Wange96e7e52019-10-05 17:47:30 +0800195 if (entry.count("dbus") != 0)
Tom Joseph52552ef2019-06-20 09:50:15 +0530196 {
John Wange96e7e52019-10-05 17:47:30 +0800197 auto dbusEntry = entry.value("dbus", emptyJson);
198 std::string propertyType = dbusEntry.value("property_type", "");
199 Json propValues = dbusEntry["property_values"];
200 internal::dbusValToValMaps.emplace(
201 attrName, internal::populateMapping(propertyType, propValues,
202 possibleValues));
Tom Joseph52552ef2019-06-20 09:50:15 +0530203 }
John Wange96e7e52019-10-05 17:47:30 +0800204 // Defaulting all the types of attributes to BIOSEnumeration
205 internal::valueMap.emplace(std::move(attrName),
206 std::make_tuple(entry.count("dbus") == 0,
207 std::move(possibleValues),
208 std::move(defaultValues)));
209 return 0;
Tom Joseph52552ef2019-06-20 09:50:15 +0530210}
211
212const AttrValuesMap& getValues()
213{
214 return internal::valueMap;
215}
216
217CurrentValues getAttrValue(const AttrName& attrName)
218{
John Wange96e7e52019-10-05 17:47:30 +0800219 const auto& dBusMap = BIOSAttrLookup.at(attrName);
Tom Joseph52552ef2019-06-20 09:50:15 +0530220 CurrentValues currentValues;
221 internal::PropertyValue propValue;
222
223 if (dBusMap == std::nullopt)
224 {
225 const auto& valueEntry = internal::valueMap.at(attrName);
226 const auto& [readOnly, possibleValues, currentValues] = valueEntry;
227 return currentValues;
228 }
229
John Wange96e7e52019-10-05 17:47:30 +0800230 const auto& dbusValToValMap = internal::dbusValToValMaps.at(attrName);
John Wang8b85f522019-10-17 19:28:19 +0800231 propValue =
232 pldm::responder::DBusHandler()
233 .getDbusPropertyVariant<internal::PropertyValue>(
234 dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
235 dBusMap->interface.c_str());
Tom Joseph52552ef2019-06-20 09:50:15 +0530236
John Wange96e7e52019-10-05 17:47:30 +0800237 auto iter = dbusValToValMap.find(propValue);
238 if (iter != dbusValToValMap.end())
Tom Joseph52552ef2019-06-20 09:50:15 +0530239 {
240 currentValues.push_back(iter->second);
241 }
242
243 return currentValues;
244}
245
246} // namespace bios_enum
247
Carol Wang612f35b2019-08-26 17:14:26 +0800248namespace bios_string
249{
250
251/** @brief BIOS string types
252 */
253enum BiosStringEncoding
254{
255 UNKNOWN = 0x00,
256 ASCII = 0x01,
257 HEX = 0x02,
258 UTF_8 = 0x03,
259 UTF_16LE = 0x04,
260 UTF_16BE = 0x05,
261 VENDOR_SPECIFIC = 0xFF
262};
263
264const std::map<std::string, uint8_t> strTypeMap{
265 {"Unknown", UNKNOWN},
266 {"ASCII", ASCII},
267 {"Hex", HEX},
268 {"UTF-8", UTF_8},
269 {"UTF-16LE", UTF_16LE},
270 {"UTF-16LE", UTF_16LE},
271 {"Vendor Specific", VENDOR_SPECIFIC}};
272
273namespace internal
274{
275
Carol Wang612f35b2019-08-26 17:14:26 +0800276/** @brief Map containing the possible and the default values for the BIOS
277 * string type attributes.
278 */
279AttrValuesMap valueMap;
280
Carol Wang612f35b2019-08-26 17:14:26 +0800281} // namespace internal
282
John Wange96e7e52019-10-05 17:47:30 +0800283int setup(const Json& entry)
Carol Wang612f35b2019-08-26 17:14:26 +0800284{
Carol Wang612f35b2019-08-26 17:14:26 +0800285
John Wange96e7e52019-10-05 17:47:30 +0800286 std::string attr = entry.value("attribute_name", "");
287 // Transfer string type from string to enum
288 std::string strTypeTmp = entry.value("string_type", "Unknown");
289 auto iter = strTypeMap.find(strTypeTmp);
290 if (iter == strTypeMap.end())
Carol Wang612f35b2019-08-26 17:14:26 +0800291 {
John Wange96e7e52019-10-05 17:47:30 +0800292 log<level::ERR>(
293 "Wrong string type",
294 phosphor::logging::entry("STRING_TYPE=%s", strTypeTmp.c_str()),
295 phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
296 return -1;
297 }
298 uint8_t strType = iter->second;
299
300 uint16_t minStrLen = entry.value("minimum_string_length", 0);
301 uint16_t maxStrLen = entry.value("maximum_string_length", 0);
302 if (maxStrLen - minStrLen < 0)
303 {
304 log<level::ERR>(
305 "Maximum string length is smaller than minimum string length",
306 phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
307 return -1;
308 }
309 uint16_t defaultStrLen = entry.value("default_string_length", 0);
310 std::string defaultStr = entry.value("default_string", "");
311 if ((defaultStrLen == 0) && (defaultStr.size() > 0))
312 {
313 log<level::ERR>(
314 "Default string length is 0, but default string is existing",
315 phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
316 return -1;
Carol Wang612f35b2019-08-26 17:14:26 +0800317 }
318
John Wange96e7e52019-10-05 17:47:30 +0800319 // Defaulting all the types of attributes to BIOSString
320 internal::valueMap.emplace(
321 std::move(attr),
322 std::make_tuple(entry.count("dbus") == 0, strType, minStrLen, maxStrLen,
323 defaultStrLen, std::move(defaultStr)));
Carol Wang612f35b2019-08-26 17:14:26 +0800324
John Wange96e7e52019-10-05 17:47:30 +0800325 return 0;
Carol Wang612f35b2019-08-26 17:14:26 +0800326}
327
328const AttrValuesMap& getValues()
329{
330 return internal::valueMap;
331}
Carol Wangb503f9e2019-09-02 16:34:10 +0800332
333std::string getAttrValue(const AttrName& attrName)
334{
John Wange96e7e52019-10-05 17:47:30 +0800335 const auto& dBusMap = BIOSAttrLookup.at(attrName);
Carol Wangb503f9e2019-09-02 16:34:10 +0800336 std::variant<std::string> propValue;
337
338 if (dBusMap == std::nullopt)
339 { // return default string
340 const auto& valueEntry = internal::valueMap.at(attrName);
341 return std::get<DefaultStr>(valueEntry);
342 }
343
John Wang8b85f522019-10-17 19:28:19 +0800344 return pldm::responder::DBusHandler().getDbusProperty<std::string>(
345 dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
346 dBusMap->interface.c_str());
Carol Wangb503f9e2019-09-02 16:34:10 +0800347}
348
Carol Wang612f35b2019-08-26 17:14:26 +0800349} // namespace bios_string
350
John Wange96e7e52019-10-05 17:47:30 +0800351const std::map<BIOSJsonName, BIOSStringHandler> BIOSStringHandlers = {
352 {bIOSEnumJson, bios_enum::setupBIOSStrings},
353};
Tom Joseph52552ef2019-06-20 09:50:15 +0530354
John Wange96e7e52019-10-05 17:47:30 +0800355const std::map<BIOSJsonName, typeHandler> BIOSTypeHandlers = {
356 {bIOSEnumJson, bios_enum::setup},
357 {bIOSStrJson, bios_string::setup},
358};
359
360void setupBIOSStrings(const BIOSJsonName& jsonName, const Json& entry,
361 Strings& strings)
362{
363 strings.emplace_back(entry.value("attribute_name", ""));
364 auto iter = BIOSStringHandlers.find(jsonName);
365 if (iter != BIOSStringHandlers.end())
366 {
367 iter->second(entry, strings);
368 }
369}
370
371void setupBIOSAttrLookup(const Json& entry, AttrLookup& lookup)
372{
373 std::optional<DBusMapping> dBusMap;
374 std::string attrName = entry.value("attribute_name", "");
375
376 if (entry.count("dbus") != 0)
377 {
378 auto dBusEntry = entry.value("dbus", emptyJson);
379 std::string objectPath = dBusEntry.value("object_path", "");
380 std::string interface = dBusEntry.value("interface", "");
381 std::string propertyName = dBusEntry.value("property_name", "");
382 if (!objectPath.empty() && !interface.empty() && !propertyName.empty())
383 {
384 dBusMap = std::optional<DBusMapping>(
385 {objectPath, interface, propertyName});
386 }
387 else
388 {
389 log<level::ERR>(
390 "Invalid dbus config",
391 phosphor::logging::entry("OBJPATH=%s",
392 dBusMap->objectPath.c_str()),
393 phosphor::logging::entry("INTERFACE=%s",
394 dBusMap->interface.c_str()),
395 phosphor::logging::entry("PROPERTY_NAME=%s",
396 dBusMap->propertyName.c_str()));
397 }
398 }
399 lookup.emplace(attrName, dBusMap);
400}
401
402int setupBIOSType(const BIOSJsonName& jsonName, const Json& entry)
403{
404 auto iter = BIOSTypeHandlers.find(jsonName);
405 if (iter != BIOSTypeHandlers.end())
406 {
407 iter->second(entry);
408 }
409 return 0;
410}
411
412const std::vector<BIOSJsonName> BIOSConfigFiles = {bIOSEnumJson, bIOSStrJson};
413
414int setupConfig(const char* dirPath)
415{
416 if (!BIOSStrings.empty() && !BIOSAttrLookup.empty())
417 {
418 return 0;
419 }
420
421 fs::path dir(dirPath);
Tom Joseph52552ef2019-06-20 09:50:15 +0530422 if (!fs::exists(dir) || fs::is_empty(dir))
423 {
John Wange96e7e52019-10-05 17:47:30 +0800424 log<level::ERR>("BIOS config directory does not exist or empty",
425 entry("DIR=%s", dirPath));
426 return -1;
Tom Joseph52552ef2019-06-20 09:50:15 +0530427 }
John Wange96e7e52019-10-05 17:47:30 +0800428 for (auto jsonName : BIOSConfigFiles)
Tom Joseph52552ef2019-06-20 09:50:15 +0530429 {
John Wange96e7e52019-10-05 17:47:30 +0800430 Json json;
431 if (parseBiosJsonFile(dir, jsonName, json) < 0)
Tom Joseph52552ef2019-06-20 09:50:15 +0530432 {
Tom Joseph52552ef2019-06-20 09:50:15 +0530433 continue;
434 }
John Wange96e7e52019-10-05 17:47:30 +0800435 auto entries = json.value("entries", emptyJsonList);
Tom Joseph52552ef2019-06-20 09:50:15 +0530436 for (auto& entry : entries)
437 {
John Wange96e7e52019-10-05 17:47:30 +0800438 setupBIOSStrings(jsonName, entry, BIOSStrings);
439 setupBIOSAttrLookup(entry, BIOSAttrLookup);
440 setupBIOSType(jsonName, entry);
Tom Joseph52552ef2019-06-20 09:50:15 +0530441 }
442 }
John Wange96e7e52019-10-05 17:47:30 +0800443 if (BIOSStrings.empty())
444 { // means there is no attribute
445 log<level::ERR>("No attribute is found in the config directory",
446 entry("DIR=%s", dirPath));
447 return -1;
448 }
449 return 0;
Tom Joseph52552ef2019-06-20 09:50:15 +0530450}
451
452} // namespace bios_parser