blob: fa704e61a7bad6d1ec62e35ccf45d4791cf15e66 [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;
17constexpr auto bIOSEnumJson = "enum_attrs.json";
18
19namespace bios_enum
20{
21
22namespace internal
23{
24
25using PropertyValue =
26 std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
27 uint64_t, double, std::string>;
28using Value = std::string;
29
30/** @struct DBusMapping
31 *
32 * Data structure for storing information regarding BIOS enumeration attribute
33 * and the D-Bus object for the attribute.
34 */
35struct DBusMapping
36{
37 std::string objectPath; //!< D-Bus object path
38 std::string interface; //!< D-Bus interface
39 std::string propertyName; //!< D-Bus property name
40 std::map<PropertyValue, Value>
41 dBusValToValMap; //!< Map of D-Bus property
42 //!< value to attribute value
43};
44
45/** @brief Map containing the possible and the default values for the BIOS
46 * enumeration type attributes.
47 */
48AttrValuesMap valueMap;
49
50/** @brief Map containing the optional D-Bus property information about the
51 * BIOS enumeration type attributes.
52 */
53std::map<AttrName, std::optional<DBusMapping>> attrLookup;
54
55/** @brief Populate the mapping between D-Bus property value and attribute value
56 * for the BIOS enumeration attribute.
57 *
58 * @param[in] type - type of the D-Bus property
59 * @param[in] dBusValues - json array of D-Bus property values
60 * @param[in] pv - Possible values for the BIOS enumeration attribute
61 * @param[out] mapping - D-Bus mapping object for the attribute
62 *
63 */
64void populateMapping(const std::string& type, const Json& dBusValues,
65 const PossibleValues& pv, DBusMapping& mapping)
66{
67 size_t pos = 0;
68 PropertyValue value;
69 for (auto it = dBusValues.begin(); it != dBusValues.end(); ++it, ++pos)
70 {
71 if (type == "uint8_t")
72 {
73 value = static_cast<uint8_t>(it.value());
74 }
75 else if (type == "uint16_t")
76 {
77 value = static_cast<uint16_t>(it.value());
78 }
79 else if (type == "uint32_t")
80 {
81 value = static_cast<uint32_t>(it.value());
82 }
83 else if (type == "uint64_t")
84 {
85 value = static_cast<uint64_t>(it.value());
86 }
87 else if (type == "int16_t")
88 {
89 value = static_cast<int16_t>(it.value());
90 }
91 else if (type == "int32_t")
92 {
93 value = static_cast<int32_t>(it.value());
94 }
95 else if (type == "int64_t")
96 {
97 value = static_cast<int64_t>(it.value());
98 }
99 else if (type == "bool")
100 {
101 value = static_cast<bool>(it.value());
102 }
103 else if (type == "double")
104 {
105 value = static_cast<double>(it.value());
106 }
107 else if (type == "string")
108 {
109 value = static_cast<std::string>(it.value());
110 }
111 else
112 {
113 log<level::ERR>("Unknown D-Bus property type",
114 entry("TYPE=%s", type.c_str()));
115 }
116
117 mapping.dBusValToValMap.emplace(value, pv[pos]);
118 }
119}
120
121/** @brief Read the possible values for the BIOS enumeration type
122 *
123 * @param[in] possibleValues - json array of BIOS enumeration possible values
124 */
125PossibleValues readPossibleValues(Json& possibleValues)
126{
127 Strings biosStrings{};
128
129 for (auto& val : possibleValues)
130 {
131 biosStrings.emplace_back(std::move(val));
132 }
133
134 return biosStrings;
135}
136
137} // namespace internal
138
139int setupValueLookup(const char* dirPath)
140{
141 int rc = 0;
142
143 if (!internal::valueMap.empty() && !internal::attrLookup.empty())
144 {
145 return rc;
146 }
147
148 // Parse the BIOS enumeration config file
149 fs::path filePath(dirPath);
150 filePath /= bIOSEnumJson;
151
152 std::ifstream jsonFile(filePath);
153 if (!jsonFile.is_open())
154 {
155 log<level::ERR>("BIOS enum config file does not exist",
156 entry("FILE=%s", filePath.c_str()));
157 rc = -1;
158 return rc;
159 }
160
161 auto fileData = Json::parse(jsonFile, nullptr, false);
162 if (fileData.is_discarded())
163 {
164 log<level::ERR>("Parsing config file failed");
165 rc = -1;
166 return rc;
167 }
168
169 static const std::vector<Json> emptyList{};
170 auto entries = fileData.value("entries", emptyList);
171 // Iterate through each JSON object in the config file
172 for (const auto& entry : entries)
173 {
174 std::string attr = entry.value("attribute_name", "");
175 PossibleValues possibleValues;
176 DefaultValues defaultValues;
177
178 Json pv = entry["possible_values"];
179 for (auto& val : pv)
180 {
181 possibleValues.emplace_back(std::move(val));
182 }
183
184 Json dv = entry["default_values"];
185 for (auto& val : dv)
186 {
187 defaultValues.emplace_back(std::move(val));
188 }
189
190 std::optional<internal::DBusMapping> dBusMap = std::nullopt;
191 static const Json empty{};
192 if (entry.count("dbus") != 0)
193 {
194 auto dBusEntry = entry.value("dbus", empty);
195 dBusMap = std::make_optional<internal::DBusMapping>();
196 dBusMap.value().objectPath = dBusEntry.value("object_path", "");
197 dBusMap.value().interface = dBusEntry.value("interface", "");
198 dBusMap.value().propertyName = dBusEntry.value("property_name", "");
199 std::string propType = dBusEntry.value("property_type", "");
200 Json propValues = dBusEntry["property_values"];
201 internal::populateMapping(propType, propValues, possibleValues,
202 dBusMap.value());
203 }
204
205 internal::attrLookup.emplace(attr, std::move(dBusMap));
206
207 // Defaulting all the types of attributes to BIOSEnumeration
208 internal::valueMap.emplace(
209 std::move(attr), std::make_tuple(false, std::move(possibleValues),
210 std::move(defaultValues)));
211 }
212
213 return rc;
214}
215
216const AttrValuesMap& getValues()
217{
218 return internal::valueMap;
219}
220
221CurrentValues getAttrValue(const AttrName& attrName)
222{
223 const auto& dBusMap = internal::attrLookup.at(attrName);
224 CurrentValues currentValues;
225 internal::PropertyValue propValue;
226
227 if (dBusMap == std::nullopt)
228 {
229 const auto& valueEntry = internal::valueMap.at(attrName);
230 const auto& [readOnly, possibleValues, currentValues] = valueEntry;
231 return currentValues;
232 }
233
234 auto bus = sdbusplus::bus::new_default();
235 auto service = pldm::responder::getService(bus, dBusMap.value().objectPath,
236 dBusMap.value().interface);
237 auto method =
238 bus.new_method_call(service.c_str(), dBusMap.value().objectPath.c_str(),
239 "org.freedesktop.DBus.Properties", "Get");
240 method.append(dBusMap.value().interface, dBusMap.value().propertyName);
241 auto reply = bus.call(method);
242 reply.read(propValue);
243
244 auto iter = dBusMap.value().dBusValToValMap.find(propValue);
245 if (iter != dBusMap.value().dBusValToValMap.end())
246 {
247 currentValues.push_back(iter->second);
248 }
249
250 return currentValues;
251}
252
253} // namespace bios_enum
254
255Strings getStrings(const char* dirPath)
256{
257 Strings biosStrings{};
258 fs::path dir(dirPath);
259
260 if (!fs::exists(dir) || fs::is_empty(dir))
261 {
262 return biosStrings;
263 }
264
265 for (const auto& file : fs::directory_iterator(dir))
266 {
267 std::ifstream jsonFile(file.path().c_str());
268 if (!jsonFile.is_open())
269 {
270 log<level::ERR>("JSON BIOS config file does not exist",
271 entry("FILE=%s", file.path().filename().c_str()));
272 continue;
273 }
274
275 auto fileData = Json::parse(jsonFile, nullptr, false);
276 if (fileData.is_discarded())
277 {
278 log<level::ERR>("Parsing config file failed",
279 entry("FILE=%s", file.path().filename().c_str()));
280 continue;
281 }
282
283 static const std::vector<Json> emptyList{};
284 auto entries = fileData.value("entries", emptyList);
285
286 // Iterate through each entry in the config file
287 for (auto& entry : entries)
288 {
289 biosStrings.emplace_back(entry.value("attribute_name", ""));
290
291 // For BIOS enumeration attributes the possible values are strings
292 if (file.path().filename() == bIOSEnumJson)
293 {
294 auto possibleValues = bios_enum::internal::readPossibleValues(
295 entry["possible_values"]);
296 std::move(possibleValues.begin(), possibleValues.end(),
297 std::back_inserter(biosStrings));
298 }
299 }
300 }
301
302 return biosStrings;
303}
304
305} // namespace bios_parser