blob: 15e3116bdd0691ac69de1a79234631f62fd6d1b0 [file] [log] [blame]
SunnySrivastava198443306542020-04-01 02:50:20 -05001#include "config.h"
2
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05003#include "ibm_vpd_utils.hpp"
Patrick Venturec83c4dc2018-11-01 16:29:18 -07004
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05005#include "common_utility.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06006#include "defines.hpp"
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +05307#include "vpd_exceptions.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06008
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +05309#include <fstream>
10#include <iomanip>
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -050011#include <nlohmann/json.hpp>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050012#include <phosphor-logging/elog-errors.hpp>
Patrick Venturec83c4dc2018-11-01 16:29:18 -070013#include <phosphor-logging/log.hpp>
14#include <sdbusplus/server.hpp>
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053015#include <sstream>
16#include <vector>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050017#include <xyz/openbmc_project/Common/error.hpp>
Deepak Kodihalli76794492017-02-16 23:48:18 -060018
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053019using json = nlohmann::json;
20
Deepak Kodihalli76794492017-02-16 23:48:18 -060021namespace openpower
22{
23namespace vpd
24{
SunnySrivastava1984945a02d2020-05-06 01:55:41 -050025using namespace openpower::vpd::constants;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050026using namespace inventory;
27using namespace phosphor::logging;
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050028using namespace sdbusplus::xyz::openbmc_project::Common::Error;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053029using namespace record;
30using namespace openpower::vpd::exceptions;
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -050031using namespace common::utility;
Sunny Srivastava0746eee2021-03-22 13:36:54 -050032using Severity = openpower::vpd::constants::PelSeverity;
33
34// mapping of severity enum to severity interface
35static std::unordered_map<Severity, std::string> sevMap = {
36 {Severity::INFORMATIONAL,
37 "xyz.openbmc_project.Logging.Entry.Level.Informational"},
38 {Severity::DEBUG, "xyz.openbmc_project.Logging.Entry.Level.Debug"},
39 {Severity::NOTICE, "xyz.openbmc_project.Logging.Entry.Level.Notice"},
40 {Severity::WARNING, "xyz.openbmc_project.Logging.Entry.Level.Warning"},
41 {Severity::CRITICAL, "xyz.openbmc_project.Logging.Entry.Level.Critical"},
42 {Severity::EMERGENCY, "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
43 {Severity::ERROR, "xyz.openbmc_project.Logging.Entry.Level.Error"},
44 {Severity::ALERT, "xyz.openbmc_project.Logging.Entry.Level.Alert"}};
45
Deepak Kodihalli76794492017-02-16 23:48:18 -060046namespace inventory
47{
48
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050049MapperResponse
50 getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
51 const std::vector<std::string>& interfaces)
52{
53 auto bus = sdbusplus::bus::new_default();
54 auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath,
55 mapperInterface, "GetSubTree");
56 mapperCall.append(root);
57 mapperCall.append(depth);
58 mapperCall.append(interfaces);
59
60 MapperResponse result = {};
61
62 try
63 {
64 auto response = bus.call(mapperCall);
65
66 response.read(result);
67 }
68 catch (const sdbusplus::exception::SdBusError& e)
69 {
70 log<level::ERR>("Error in mapper GetSubTree",
71 entry("ERROR=%s", e.what()));
72 }
73
74 return result;
75}
76
Deepak Kodihalli76794492017-02-16 23:48:18 -060077} // namespace inventory
78
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060079LE2ByteData readUInt16LE(Binary::const_iterator iterator)
80{
81 LE2ByteData lowByte = *iterator;
82 LE2ByteData highByte = *(iterator + 1);
83 lowByte |= (highByte << 8);
84 return lowByte;
85}
86
SunnySrivastava1984d076da82020-03-05 05:33:35 -060087/** @brief Encodes a keyword for D-Bus.
88 */
89string encodeKeyword(const string& kw, const string& encoding)
90{
91 if (encoding == "MAC")
92 {
93 string res{};
94 size_t first = kw[0];
95 res += toHex(first >> 4);
96 res += toHex(first & 0x0f);
97 for (size_t i = 1; i < kw.size(); ++i)
98 {
99 res += ":";
100 res += toHex(kw[i] >> 4);
101 res += toHex(kw[i] & 0x0f);
102 }
103 return res;
104 }
105 else if (encoding == "DATE")
106 {
107 // Date, represent as
108 // <year>-<month>-<day> <hour>:<min>
109 string res{};
110 static constexpr uint8_t skipPrefix = 3;
111
112 auto strItr = kw.begin();
113 advance(strItr, skipPrefix);
114 for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
115
116 res.insert(BD_YEAR_END, 1, '-');
117 res.insert(BD_MONTH_END, 1, '-');
118 res.insert(BD_DAY_END, 1, ' ');
119 res.insert(BD_HOUR_END, 1, ':');
120
121 return res;
122 }
123 else // default to string encoding
124 {
125 return string(kw.begin(), kw.end());
126 }
127}
SunnySrivastava198443306542020-04-01 02:50:20 -0500128
129string readBusProperty(const string& obj, const string& inf, const string& prop)
130{
131 std::string propVal{};
132 std::string object = INVENTORY_PATH + obj;
133 auto bus = sdbusplus::bus::new_default();
134 auto properties = bus.new_method_call(
135 "xyz.openbmc_project.Inventory.Manager", object.c_str(),
136 "org.freedesktop.DBus.Properties", "Get");
137 properties.append(inf);
138 properties.append(prop);
139 auto result = bus.call(properties);
140 if (!result.is_method_error())
141 {
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500142 variant<Binary, string> val;
SunnySrivastava198443306542020-04-01 02:50:20 -0500143 result.read(val);
SunnySrivastava198443306542020-04-01 02:50:20 -0500144 if (auto pVal = get_if<Binary>(&val))
145 {
146 propVal.assign(reinterpret_cast<const char*>(pVal->data()),
147 pVal->size());
148 }
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500149 else if (auto pVal = get_if<string>(&val))
150 {
151 propVal.assign(pVal->data(), pVal->size());
152 }
SunnySrivastava198443306542020-04-01 02:50:20 -0500153 }
154 return propVal;
155}
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500156
157void createPEL(const std::map<std::string, std::string>& additionalData,
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500158 const Severity& sev, const std::string& errIntf)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500159{
160 try
161 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500162 std::string pelSeverity =
163 "xyz.openbmc_project.Logging.Entry.Level.Error";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500164 auto bus = sdbusplus::bus::new_default();
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500165 auto service = getService(bus, loggerObjectPath, loggerCreateInterface);
166 auto method = bus.new_method_call(service.c_str(), loggerObjectPath,
167 loggerCreateInterface, "Create");
168
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500169 auto itr = sevMap.find(sev);
170 if (itr != sevMap.end())
171 {
172 pelSeverity = itr->second;
173 }
174
175 method.append(errIntf, pelSeverity, additionalData);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500176 auto resp = bus.call(method);
177 }
178 catch (const sdbusplus::exception::SdBusError& e)
179 {
180 throw std::runtime_error(
181 "Error in invoking D-Bus logging create interface to register PEL");
182 }
183}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530184
185inventory::VPDfilepath getVpdFilePath(const string& jsonFile,
186 const std::string& ObjPath)
187{
188 ifstream inventoryJson(jsonFile);
189 const auto& jsonObject = json::parse(inventoryJson);
190 inventory::VPDfilepath filePath{};
191
192 if (jsonObject.find("frus") == jsonObject.end())
193 {
194 throw(VpdJsonException(
195 "Invalid JSON structure - frus{} object not found in ", jsonFile));
196 }
197
198 const nlohmann::json& groupFRUS =
199 jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
200 for (const auto& itemFRUS : groupFRUS.items())
201 {
202 const std::vector<nlohmann::json>& groupEEPROM =
203 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
204 for (const auto& itemEEPROM : groupEEPROM)
205 {
206 if (itemEEPROM["inventoryPath"]
207 .get_ref<const nlohmann::json::string_t&>() == ObjPath)
208 {
209 filePath = itemFRUS.key();
210 return filePath;
211 }
212 }
213 }
214
215 return filePath;
216}
217
218bool isPathInJson(const std::string& eepromPath)
219{
220 bool present = false;
221 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
222
223 try
224 {
225 auto js = json::parse(inventoryJson);
226 if (js.find("frus") == js.end())
227 {
228 throw(VpdJsonException(
229 "Invalid JSON structure - frus{} object not found in ",
230 INVENTORY_JSON_SYM_LINK));
231 }
232 json fruJson = js["frus"];
233
234 if (fruJson.find(eepromPath) != fruJson.end())
235 {
236 present = true;
237 }
238 }
239 catch (json::parse_error& ex)
240 {
241 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
242 }
243 return present;
244}
245
246bool isRecKwInDbusJson(const std::string& recordName,
247 const std::string& keyword)
248{
249 ifstream propertyJson(DBUS_PROP_JSON);
250 json dbusProperty;
251 bool present = false;
252
253 if (propertyJson.is_open())
254 {
255 try
256 {
257 auto dbusPropertyJson = json::parse(propertyJson);
258 if (dbusPropertyJson.find("dbusProperties") ==
259 dbusPropertyJson.end())
260 {
261 throw(VpdJsonException("dbusProperties{} object not found in "
262 "DbusProperties json : ",
263 DBUS_PROP_JSON));
264 }
265
266 dbusProperty = dbusPropertyJson["dbusProperties"];
267 if (dbusProperty.contains(recordName))
268 {
269 const vector<string>& kwdsToPublish = dbusProperty[recordName];
270 if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
271 kwdsToPublish.end()) // present
272 {
273 present = true;
274 }
275 }
276 }
277 catch (json::parse_error& ex)
278 {
279 throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
280 }
281 }
282 else
283 {
284 // If dbus properties json is not available, we assume the given
285 // record-keyword is part of dbus-properties json. So setting the bool
286 // variable to true.
287 present = true;
288 }
289 return present;
290}
291
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -0500292vpdType vpdTypeCheck(const Binary& vpdVector)
293{
294 // Read first 3 Bytes to check the 11S bar code format
295 std::string is11SFormat = "";
296 for (uint8_t i = 0; i < FORMAT_11S_LEN; i++)
297 {
298 is11SFormat += vpdVector[MEMORY_VPD_DATA_START + i];
299 }
300
301 if (vpdVector[IPZ_DATA_START] == KW_VAL_PAIR_START_TAG)
302 {
303 // IPZ VPD FORMAT
304 return vpdType::IPZ_VPD;
305 }
306 else if (vpdVector[KW_VPD_DATA_START] == KW_VPD_START_TAG)
307 {
308 // KEYWORD VPD FORMAT
309 return vpdType::KEYWORD_VPD;
310 }
311 else if (is11SFormat.compare(MEMORY_VPD_START_TAG) == 0)
312 {
313 // Memory VPD format
314 return vpdType::MEMORY_VPD;
315 }
316
317 // INVALID VPD FORMAT
318 return vpdType::INVALID_VPD_FORMAT;
319}
320
Alpana Kumarif05effd2021-04-07 07:32:53 -0500321const string getIM(const Parsed& vpdMap)
322{
323 Binary imVal;
324 auto property = vpdMap.find("VSBP");
325 if (property != vpdMap.end())
326 {
327 auto kw = (property->second).find("IM");
328 if (kw != (property->second).end())
329 {
330 copy(kw->second.begin(), kw->second.end(), back_inserter(imVal));
331 }
332 }
333
334 ostringstream oss;
335 for (auto& i : imVal)
336 {
337 oss << setw(2) << setfill('0') << hex << static_cast<int>(i);
338 }
339
340 return oss.str();
341}
342
343const string getHW(const Parsed& vpdMap)
344{
345 Binary hwVal;
346 auto prop = vpdMap.find("VINI");
347 if (prop != vpdMap.end())
348 {
349 auto kw = (prop->second).find("HW");
350 if (kw != (prop->second).end())
351 {
352 copy(kw->second.begin(), kw->second.end(), back_inserter(hwVal));
353 }
354 }
355
356 ostringstream hwString;
357 for (auto& i : hwVal)
358 {
359 hwString << setw(2) << setfill('0') << hex << static_cast<int>(i);
360 }
361
362 return hwString.str();
363}
364
365string getSystemsJson(const Parsed& vpdMap)
366{
367 string jsonPath = "/usr/share/vpd/";
368 string jsonName{};
369
370 ifstream systemJson(SYSTEM_JSON);
371 if (!systemJson)
372 {
373 throw((VpdJsonException("Failed to access Json path", SYSTEM_JSON)));
374 }
375
376 try
377 {
378 auto js = json::parse(systemJson);
379
380 const string hwKeyword = getHW(vpdMap);
381 const string imKeyword = getIM(vpdMap);
382
383 if (js.find("system") == js.end())
384 {
385 throw runtime_error("Invalid systems Json");
386 }
387
388 if (js["system"].find(imKeyword) == js["system"].end())
389 {
390 throw runtime_error(
391 "Invalid system. This system type is not present "
392 "in the systemsJson. IM: " +
393 imKeyword);
394 }
395
396 if ((js["system"][imKeyword].find("constraint") !=
397 js["system"][imKeyword].end()) &&
398 (hwKeyword == js["system"][imKeyword]["constraint"]["HW"]))
399 {
400 jsonName = js["system"][imKeyword]["constraint"]["json"];
401 }
402 else if (js["system"][imKeyword].find("default") !=
403 js["system"][imKeyword].end())
404 {
405 jsonName = js["system"][imKeyword]["default"];
406 }
407 else
408 {
409 throw runtime_error(
410 "Bad System json. Neither constraint nor default found");
411 }
412
413 jsonPath += jsonName;
414 }
415
416 catch (json::parse_error& ex)
417 {
418 throw(VpdJsonException("Json Parsing failed", SYSTEM_JSON));
419 }
420 return jsonPath;
421}
422
Patrick Venturec83c4dc2018-11-01 16:29:18 -0700423} // namespace vpd
Alpana Kumarif05effd2021-04-07 07:32:53 -0500424} // namespace openpower