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