blob: 10bc577e304815e424d475ed4e256eb58eec7426 [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"
Jinu Joy Thomase2b03832023-08-22 19:51:31 +05306#include "const.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06007#include "defines.hpp"
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +05308#include "vpd_exceptions.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06009
Alpana Kumari6bd095f2022-02-23 10:20:20 -060010#include <boost/algorithm/string.hpp>
Alpana Kumari735dee92022-03-25 01:24:40 -050011#include <gpiod.hpp>
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -050012#include <nlohmann/json.hpp>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050013#include <phosphor-logging/elog-errors.hpp>
Patrick Venturec83c4dc2018-11-01 16:29:18 -070014#include <phosphor-logging/log.hpp>
15#include <sdbusplus/server.hpp>
Patrick Williamsc78d8872023-05-10 07:50:56 -050016#include <xyz/openbmc_project/Common/error.hpp>
17
18#include <filesystem>
19#include <fstream>
20#include <iomanip>
21#include <regex>
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053022#include <sstream>
23#include <vector>
Deepak Kodihalli76794492017-02-16 23:48:18 -060024
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053025using json = nlohmann::json;
26
Deepak Kodihalli76794492017-02-16 23:48:18 -060027namespace openpower
28{
29namespace vpd
30{
SunnySrivastava1984945a02d2020-05-06 01:55:41 -050031using namespace openpower::vpd::constants;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050032using namespace inventory;
33using namespace phosphor::logging;
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050034using namespace sdbusplus::xyz::openbmc_project::Common::Error;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053035using namespace record;
36using namespace openpower::vpd::exceptions;
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -050037using namespace common::utility;
Sunny Srivastava0746eee2021-03-22 13:36:54 -050038using Severity = openpower::vpd::constants::PelSeverity;
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -060039namespace fs = std::filesystem;
Sunny Srivastava0746eee2021-03-22 13:36:54 -050040
41// mapping of severity enum to severity interface
42static std::unordered_map<Severity, std::string> sevMap = {
43 {Severity::INFORMATIONAL,
44 "xyz.openbmc_project.Logging.Entry.Level.Informational"},
45 {Severity::DEBUG, "xyz.openbmc_project.Logging.Entry.Level.Debug"},
46 {Severity::NOTICE, "xyz.openbmc_project.Logging.Entry.Level.Notice"},
47 {Severity::WARNING, "xyz.openbmc_project.Logging.Entry.Level.Warning"},
48 {Severity::CRITICAL, "xyz.openbmc_project.Logging.Entry.Level.Critical"},
49 {Severity::EMERGENCY, "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
50 {Severity::ERROR, "xyz.openbmc_project.Logging.Entry.Level.Error"},
51 {Severity::ALERT, "xyz.openbmc_project.Logging.Entry.Level.Alert"}};
52
Deepak Kodihalli76794492017-02-16 23:48:18 -060053namespace inventory
54{
55
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050056MapperResponse
57 getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
58 const std::vector<std::string>& interfaces)
59{
60 auto bus = sdbusplus::bus::new_default();
61 auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath,
62 mapperInterface, "GetSubTree");
63 mapperCall.append(root);
64 mapperCall.append(depth);
65 mapperCall.append(interfaces);
66
67 MapperResponse result = {};
68
69 try
70 {
71 auto response = bus.call(mapperCall);
72
73 response.read(result);
74 }
Patrick Williams2eb01762022-07-22 19:26:56 -050075 catch (const sdbusplus::exception_t& e)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050076 {
77 log<level::ERR>("Error in mapper GetSubTree",
78 entry("ERROR=%s", e.what()));
79 }
80
81 return result;
82}
83
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +053084MapperGetObjectResponse getObject(const std::string& objectPath,
85 const std::vector<std::string>& interfaces)
86{
87 auto bus = sdbusplus::bus::new_default();
88 auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath,
89 mapperInterface, "GetObject");
90 mapperCall.append(objectPath);
91 mapperCall.append(interfaces);
92
93 MapperGetObjectResponse result = {};
94
95 try
96 {
97 auto response = bus.call(mapperCall);
98
99 response.read(result);
100 }
101 catch (const sdbusplus::exception_t& e)
102 {
103 log<level::ERR>("Error in mapper GetObject",
104 entry("ERROR=%s", e.what()));
105 }
106
107 return result;
108}
109
Deepak Kodihalli76794492017-02-16 23:48:18 -0600110} // namespace inventory
111
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600112LE2ByteData readUInt16LE(Binary::const_iterator iterator)
113{
114 LE2ByteData lowByte = *iterator;
115 LE2ByteData highByte = *(iterator + 1);
116 lowByte |= (highByte << 8);
117 return lowByte;
118}
119
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600120/** @brief Encodes a keyword for D-Bus.
121 */
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500122std::string encodeKeyword(const std::string& kw, const std::string& encoding)
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600123{
124 if (encoding == "MAC")
125 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500126 std::string res{};
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600127 size_t first = kw[0];
128 res += toHex(first >> 4);
129 res += toHex(first & 0x0f);
130 for (size_t i = 1; i < kw.size(); ++i)
131 {
132 res += ":";
133 res += toHex(kw[i] >> 4);
134 res += toHex(kw[i] & 0x0f);
135 }
136 return res;
137 }
138 else if (encoding == "DATE")
139 {
140 // Date, represent as
141 // <year>-<month>-<day> <hour>:<min>
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500142 std::string res{};
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600143 static constexpr uint8_t skipPrefix = 3;
144
145 auto strItr = kw.begin();
146 advance(strItr, skipPrefix);
147 for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
148
149 res.insert(BD_YEAR_END, 1, '-');
150 res.insert(BD_MONTH_END, 1, '-');
151 res.insert(BD_DAY_END, 1, ' ');
152 res.insert(BD_HOUR_END, 1, ':');
153
154 return res;
155 }
156 else // default to string encoding
157 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500158 return std::string(kw.begin(), kw.end());
SunnySrivastava1984d076da82020-03-05 05:33:35 -0600159 }
160}
SunnySrivastava198443306542020-04-01 02:50:20 -0500161
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500162std::string readBusProperty(const std::string& obj, const std::string& inf,
163 const std::string& prop)
SunnySrivastava198443306542020-04-01 02:50:20 -0500164{
165 std::string propVal{};
166 std::string object = INVENTORY_PATH + obj;
167 auto bus = sdbusplus::bus::new_default();
168 auto properties = bus.new_method_call(
169 "xyz.openbmc_project.Inventory.Manager", object.c_str(),
170 "org.freedesktop.DBus.Properties", "Get");
171 properties.append(inf);
172 properties.append(prop);
173 auto result = bus.call(properties);
174 if (!result.is_method_error())
175 {
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500176 inventory::Value val;
SunnySrivastava198443306542020-04-01 02:50:20 -0500177 result.read(val);
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500178 if (auto pVal = std::get_if<Binary>(&val))
SunnySrivastava198443306542020-04-01 02:50:20 -0500179 {
180 propVal.assign(reinterpret_cast<const char*>(pVal->data()),
181 pVal->size());
182 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500183 else if (auto pVal = std::get_if<std::string>(&val))
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500184 {
185 propVal.assign(pVal->data(), pVal->size());
186 }
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500187 else if (auto pVal = get_if<bool>(&val))
188 {
189 if (*pVal == false)
190 {
191 propVal = "false";
192 }
193 else
194 {
195 propVal = "true";
196 }
197 }
SunnySrivastava198443306542020-04-01 02:50:20 -0500198 }
199 return propVal;
200}
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500201
202void createPEL(const std::map<std::string, std::string>& additionalData,
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500203 const Severity& sev, const std::string& errIntf, sd_bus* sdBus)
204{
205 // This pointer will be NULL in case the call is made from ibm-read-vpd. In
206 // that case a sync call will do.
207 if (sdBus == nullptr)
208 {
209 createSyncPEL(additionalData, sev, errIntf);
210 }
211 else
212 {
213 std::string errDescription{};
214 auto pos = additionalData.find("DESCRIPTION");
215 if (pos != additionalData.end())
216 {
217 errDescription = pos->second;
218 }
219 else
220 {
221 errDescription = "Description field missing in additional data";
222 }
223
224 std::string pelSeverity =
225 "xyz.openbmc_project.Logging.Entry.Level.Error";
226 auto itr = sevMap.find(sev);
227 if (itr != sevMap.end())
228 {
229 pelSeverity = itr->second;
230 }
231
232 // Implies this is a call from Manager. Hence we need to make an async
233 // call to avoid deadlock with Phosphor-logging.
234 auto rc = sd_bus_call_method_async(
235 sdBus, NULL, loggerService, loggerObjectPath, loggerCreateInterface,
236 "Create", NULL, NULL, "ssa{ss}", errIntf.c_str(),
237 pelSeverity.c_str(), 1, "DESCRIPTION", errDescription.c_str());
238
239 if (rc < 0)
240 {
241 log<level::ERR>("Error calling sd_bus_call_method_async",
242 entry("RC=%d", rc), entry("MSG=%s", strerror(-rc)));
243 }
244 }
245}
246
247void createSyncPEL(const std::map<std::string, std::string>& additionalData,
248 const Severity& sev, const std::string& errIntf)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500249{
250 try
251 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500252 std::string pelSeverity =
253 "xyz.openbmc_project.Logging.Entry.Level.Error";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500254 auto bus = sdbusplus::bus::new_default();
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500255 auto service = getService(bus, loggerObjectPath, loggerCreateInterface);
256 auto method = bus.new_method_call(service.c_str(), loggerObjectPath,
257 loggerCreateInterface, "Create");
258
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500259 auto itr = sevMap.find(sev);
260 if (itr != sevMap.end())
261 {
262 pelSeverity = itr->second;
263 }
264
265 method.append(errIntf, pelSeverity, additionalData);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500266 auto resp = bus.call(method);
267 }
Patrick Williams2eb01762022-07-22 19:26:56 -0500268 catch (const sdbusplus::exception_t& e)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500269 {
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500270 std::cerr << "Dbus call to phosphor-logging Create failed. Reason:"
271 << e.what();
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500272 }
273}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530274
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500275inventory::VPDfilepath getVpdFilePath(const std::string& jsonFile,
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530276 const std::string& ObjPath)
277{
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500278 std::ifstream inventoryJson(jsonFile);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530279 const auto& jsonObject = json::parse(inventoryJson);
280 inventory::VPDfilepath filePath{};
281
282 if (jsonObject.find("frus") == jsonObject.end())
283 {
284 throw(VpdJsonException(
285 "Invalid JSON structure - frus{} object not found in ", jsonFile));
286 }
287
288 const nlohmann::json& groupFRUS =
289 jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
290 for (const auto& itemFRUS : groupFRUS.items())
291 {
292 const std::vector<nlohmann::json>& groupEEPROM =
293 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
294 for (const auto& itemEEPROM : groupEEPROM)
295 {
296 if (itemEEPROM["inventoryPath"]
297 .get_ref<const nlohmann::json::string_t&>() == ObjPath)
298 {
299 filePath = itemFRUS.key();
300 return filePath;
301 }
302 }
303 }
304
305 return filePath;
306}
307
308bool isPathInJson(const std::string& eepromPath)
309{
310 bool present = false;
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500311 std::ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530312
313 try
314 {
315 auto js = json::parse(inventoryJson);
316 if (js.find("frus") == js.end())
317 {
318 throw(VpdJsonException(
319 "Invalid JSON structure - frus{} object not found in ",
320 INVENTORY_JSON_SYM_LINK));
321 }
322 json fruJson = js["frus"];
323
324 if (fruJson.find(eepromPath) != fruJson.end())
325 {
326 present = true;
327 }
328 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500329 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530330 {
331 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
332 }
333 return present;
334}
335
336bool isRecKwInDbusJson(const std::string& recordName,
337 const std::string& keyword)
338{
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500339 std::ifstream propertyJson(DBUS_PROP_JSON);
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530340 json dbusProperty;
341 bool present = false;
342
343 if (propertyJson.is_open())
344 {
345 try
346 {
347 auto dbusPropertyJson = json::parse(propertyJson);
348 if (dbusPropertyJson.find("dbusProperties") ==
349 dbusPropertyJson.end())
350 {
351 throw(VpdJsonException("dbusProperties{} object not found in "
352 "DbusProperties json : ",
353 DBUS_PROP_JSON));
354 }
355
356 dbusProperty = dbusPropertyJson["dbusProperties"];
357 if (dbusProperty.contains(recordName))
358 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500359 const std::vector<std::string>& kwdsToPublish =
360 dbusProperty[recordName];
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530361 if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
362 kwdsToPublish.end()) // present
363 {
364 present = true;
365 }
366 }
367 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500368 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530369 {
370 throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
371 }
372 }
373 else
374 {
375 // If dbus properties json is not available, we assume the given
376 // record-keyword is part of dbus-properties json. So setting the bool
377 // variable to true.
378 present = true;
379 }
380 return present;
381}
382
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -0500383vpdType vpdTypeCheck(const Binary& vpdVector)
384{
385 // Read first 3 Bytes to check the 11S bar code format
386 std::string is11SFormat = "";
387 for (uint8_t i = 0; i < FORMAT_11S_LEN; i++)
388 {
389 is11SFormat += vpdVector[MEMORY_VPD_DATA_START + i];
390 }
391
392 if (vpdVector[IPZ_DATA_START] == KW_VAL_PAIR_START_TAG)
393 {
394 // IPZ VPD FORMAT
395 return vpdType::IPZ_VPD;
396 }
397 else if (vpdVector[KW_VPD_DATA_START] == KW_VPD_START_TAG)
398 {
399 // KEYWORD VPD FORMAT
400 return vpdType::KEYWORD_VPD;
401 }
jinuthomas6555e7e2023-02-14 21:48:00 -0600402 else if (((vpdVector[SPD_BYTE_3] & SPD_BYTE_BIT_0_3_MASK) ==
403 SPD_MODULE_TYPE_DDIMM) &&
jinuthomas0abbb9c2023-05-05 01:37:07 -0500404 (is11SFormat.compare(MEMORY_VPD_START_TAG) == 0))
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -0500405 {
jinuthomas6555e7e2023-02-14 21:48:00 -0600406 // DDIMM Memory VPD format
407 if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR5)
408 {
409 return vpdType::DDR5_DDIMM_MEMORY_VPD;
410 }
411 else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR4)
412 {
413 return vpdType::DDR4_DDIMM_MEMORY_VPD;
414 }
415 }
416 else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR5)
417 {
418 // ISDIMM Memory VPD format
419 return vpdType::DDR5_ISDIMM_MEMORY_VPD;
420 }
421 else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR4)
422 {
423 // ISDIMM Memory VPD format
424 return vpdType::DDR4_ISDIMM_MEMORY_VPD;
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -0500425 }
426
427 // INVALID VPD FORMAT
428 return vpdType::INVALID_VPD_FORMAT;
429}
430
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500431const std::string getIM(const Parsed& vpdMap)
Alpana Kumarif05effd2021-04-07 07:32:53 -0500432{
433 Binary imVal;
434 auto property = vpdMap.find("VSBP");
435 if (property != vpdMap.end())
436 {
437 auto kw = (property->second).find("IM");
438 if (kw != (property->second).end())
439 {
440 copy(kw->second.begin(), kw->second.end(), back_inserter(imVal));
441 }
442 }
443
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500444 std::ostringstream oss;
Alpana Kumarif05effd2021-04-07 07:32:53 -0500445 for (auto& i : imVal)
446 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500447 oss << std::setw(2) << std::setfill('0') << std::hex
448 << static_cast<int>(i);
Alpana Kumarif05effd2021-04-07 07:32:53 -0500449 }
450
451 return oss.str();
452}
453
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500454const std::string getHW(const Parsed& vpdMap)
Alpana Kumarif05effd2021-04-07 07:32:53 -0500455{
456 Binary hwVal;
457 auto prop = vpdMap.find("VINI");
458 if (prop != vpdMap.end())
459 {
460 auto kw = (prop->second).find("HW");
461 if (kw != (prop->second).end())
462 {
463 copy(kw->second.begin(), kw->second.end(), back_inserter(hwVal));
464 }
465 }
466
Alpana Kumari88d2ae82021-11-10 03:23:31 -0600467 // The planar pass only comes from the LSB of the HW keyword,
468 // where as the MSB is used for other purposes such as signifying clock
469 // termination.
470 hwVal[0] = 0x00;
471
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500472 std::ostringstream hwString;
Alpana Kumarif05effd2021-04-07 07:32:53 -0500473 for (auto& i : hwVal)
474 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500475 hwString << std::setw(2) << std::setfill('0') << std::hex
476 << static_cast<int>(i);
Alpana Kumarif05effd2021-04-07 07:32:53 -0500477 }
478
479 return hwString.str();
480}
481
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500482std::string getSystemsJson(const Parsed& vpdMap)
Alpana Kumarif05effd2021-04-07 07:32:53 -0500483{
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500484 std::string jsonPath = "/usr/share/vpd/";
485 std::string jsonName{};
Alpana Kumarif05effd2021-04-07 07:32:53 -0500486
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500487 std::ifstream systemJson(SYSTEM_JSON);
Alpana Kumarif05effd2021-04-07 07:32:53 -0500488 if (!systemJson)
489 {
490 throw((VpdJsonException("Failed to access Json path", SYSTEM_JSON)));
491 }
492
493 try
494 {
495 auto js = json::parse(systemJson);
496
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500497 std::string hwKeyword = getHW(vpdMap);
498 const std::string imKeyword = getIM(vpdMap);
Alpana Kumarif05effd2021-04-07 07:32:53 -0500499
Alpana Kumari1b026112022-03-02 23:41:38 -0600500 transform(hwKeyword.begin(), hwKeyword.end(), hwKeyword.begin(),
501 ::toupper);
502
Alpana Kumarif05effd2021-04-07 07:32:53 -0500503 if (js.find("system") == js.end())
504 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500505 throw std::runtime_error("Invalid systems Json");
Alpana Kumarif05effd2021-04-07 07:32:53 -0500506 }
507
508 if (js["system"].find(imKeyword) == js["system"].end())
509 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500510 throw std::runtime_error(
Alpana Kumarif05effd2021-04-07 07:32:53 -0500511 "Invalid system. This system type is not present "
512 "in the systemsJson. IM: " +
513 imKeyword);
514 }
515
516 if ((js["system"][imKeyword].find("constraint") !=
517 js["system"][imKeyword].end()) &&
Alpana Kumari1b026112022-03-02 23:41:38 -0600518 js["system"][imKeyword]["constraint"].find("HW") !=
519 js["system"][imKeyword]["constraint"].end())
Alpana Kumarif05effd2021-04-07 07:32:53 -0500520 {
Alpana Kumari1b026112022-03-02 23:41:38 -0600521 // collect hw versions from json, and check hwKeyword is part of it
522 // if hwKeyword is found there then load respective json
523 // otherwise load default one.
524 for (const auto& hwVersion :
525 js["system"][imKeyword]["constraint"]["HW"])
526 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500527 std::string hw = hwVersion;
Alpana Kumari1b026112022-03-02 23:41:38 -0600528 transform(hw.begin(), hw.end(), hw.begin(), ::toupper);
529
530 if (hw == hwKeyword)
531 {
532 jsonName = js["system"][imKeyword]["constraint"]["json"];
533 break;
534 }
535 }
536
537 if (jsonName.empty() && js["system"][imKeyword].find("default") !=
538 js["system"][imKeyword].end())
539 {
540 jsonName = js["system"][imKeyword]["default"];
541 }
Alpana Kumarif05effd2021-04-07 07:32:53 -0500542 }
543 else if (js["system"][imKeyword].find("default") !=
544 js["system"][imKeyword].end())
545 {
546 jsonName = js["system"][imKeyword]["default"];
547 }
548 else
549 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500550 throw std::runtime_error(
Alpana Kumarif05effd2021-04-07 07:32:53 -0500551 "Bad System json. Neither constraint nor default found");
552 }
553
554 jsonPath += jsonName;
555 }
556
Patrick Williams8e15b932021-10-06 13:04:22 -0500557 catch (const json::parse_error& ex)
Alpana Kumarif05effd2021-04-07 07:32:53 -0500558 {
559 throw(VpdJsonException("Json Parsing failed", SYSTEM_JSON));
560 }
561 return jsonPath;
562}
563
jinuthomasf457a3e2023-04-13 12:22:48 -0500564void udevToGenericPath(std::string& file, const std::string& driver)
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530565{
566 // Sample udevEvent i2c path :
567 // "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem"
568 // find if the path contains the word i2c in it.
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500569 if (file.find("i2c") != std::string::npos)
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530570 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500571 std::string i2cBusAddr{};
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530572
573 // Every udev i2c path should have the common pattern
574 // "i2c-bus_number/bus_number-vpd_address". Search for
575 // "bus_number-vpd_address".
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500576 std::regex i2cPattern("((i2c)-[0-9]+\\/)([0-9]+-[0-9]{4})");
577 std::smatch match;
578 if (std::regex_search(file, match, i2cPattern))
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530579 {
580 i2cBusAddr = match.str(3);
581 }
582 else
583 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500584 std::cerr << "The given udev path < " << file
585 << " > doesn't match the required pattern. Skipping VPD "
586 "collection."
587 << std::endl;
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530588 exit(EXIT_SUCCESS);
589 }
590 // Forming the generic file path
jinuthomasf457a3e2023-04-13 12:22:48 -0500591 file = i2cPathPrefix + driver + "/" + i2cBusAddr + "/eeprom";
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530592 }
593 // Sample udevEvent spi path :
594 // "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/fsi0/slave@00:00/00:00:00:04/spi_master/spi2/spi2.0/spi2.00/nvmem"
595 // find if the path contains the word spi in it.
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500596 else if (file.find("spi") != std::string::npos)
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530597 {
598 // Every udev spi path will have common pattern "spi<Digit>/", which
599 // describes the spi bus number at which the fru is connected; Followed
600 // by a slash following the vpd address of the fru. Taking the above
601 // input as a common key, we try to search for the pattern "spi<Digit>/"
602 // using regular expression.
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500603 std::regex spiPattern("((spi)[0-9]+)(\\/)");
604 std::string spiBus{};
605 std::smatch match;
606 if (std::regex_search(file, match, spiPattern))
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530607 {
608 spiBus = match.str(1);
609 }
610 else
611 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500612 std::cerr << "The given udev path < " << file
613 << " > doesn't match the required pattern. Skipping VPD "
614 "collection."
615 << std::endl;
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530616 exit(EXIT_SUCCESS);
617 }
618 // Forming the generic path
jinuthomasf457a3e2023-04-13 12:22:48 -0500619 file = spiPathPrefix + driver + "/" + spiBus + ".0/eeprom";
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530620 }
621 else
622 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500623 std::cerr << "\n The given EEPROM path < " << file
624 << " > is not valid. It's neither I2C nor "
625 "SPI path. Skipping VPD collection.."
626 << std::endl;
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530627 exit(EXIT_SUCCESS);
628 }
629}
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500630std::string getBadVpdName(const std::string& file)
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600631{
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500632 std::string badVpd = BAD_VPD_DIR;
633 if (file.find("i2c") != std::string::npos)
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600634 {
635 badVpd += "i2c-";
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500636 std::regex i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
637 std::smatch match;
638 if (std::regex_search(file, match, i2cPattern))
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600639 {
640 badVpd += match.str(2);
641 }
642 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500643 else if (file.find("spi") != std::string::npos)
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600644 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500645 std::regex spiPattern("((spi)[0-9]+)(.0)");
646 std::smatch match;
647 if (std::regex_search(file, match, spiPattern))
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600648 {
649 badVpd += match.str(1);
650 }
651 }
652 return badVpd;
653}
654
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500655void dumpBadVpd(const std::string& file, const Binary& vpdVector)
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600656{
657 fs::path badVpdDir = BAD_VPD_DIR;
658 fs::create_directory(badVpdDir);
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500659 std::string badVpdPath = getBadVpdName(file);
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600660 if (fs::exists(badVpdPath))
661 {
662 std::error_code ec;
663 fs::remove(badVpdPath, ec);
664 if (ec) // error code
665 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500666 std::string error = "Error removing the existing broken vpd in ";
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600667 error += badVpdPath;
668 error += ". Error code : ";
669 error += ec.value();
670 error += ". Error message : ";
671 error += ec.message();
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500672 throw std::runtime_error(error);
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600673 }
674 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500675 std::ofstream badVpdFileStream(badVpdPath, std::ofstream::binary);
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600676 if (!badVpdFileStream)
677 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500678 throw std::runtime_error(
679 "Failed to open bad vpd file path in /tmp/bad-vpd. "
680 "Unable to dump the broken/bad vpd file.");
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600681 }
682 badVpdFileStream.write(reinterpret_cast<const char*>(vpdVector.data()),
683 vpdVector.size());
684}
alpana077ce68722021-07-25 13:23:59 -0500685
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500686const std::string getKwVal(const Parsed& vpdMap, const std::string& rec,
687 const std::string& kwd)
alpana077ce68722021-07-25 13:23:59 -0500688{
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500689 std::string kwVal{};
alpana077ce68722021-07-25 13:23:59 -0500690
691 auto findRec = vpdMap.find(rec);
692
693 // check if record is found in map we got by parser
694 if (findRec != vpdMap.end())
695 {
696 auto findKwd = findRec->second.find(kwd);
697
698 if (findKwd != findRec->second.end())
699 {
700 kwVal = findKwd->second;
701 }
Sunny Srivastava37992a62023-07-11 05:18:41 -0500702 else
703 {
704 std::cout << "Keyword not found" << std::endl;
705 }
706 }
707 else
708 {
709 std::cerr << "Record not found" << std::endl;
alpana077ce68722021-07-25 13:23:59 -0500710 }
711
712 return kwVal;
713}
714
GiridhariKrishnan63639102023-03-02 05:55:47 -0600715std::string hexString(const std::variant<Binary, std::string>& kw)
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500716{
GiridhariKrishnan63639102023-03-02 05:55:47 -0600717 std::string hexString;
718 std::visit(
719 [&hexString](auto&& kw) {
Patrick Williams08dc31c2024-08-16 15:21:06 -0400720 std::stringstream ss;
721 std::string hexRep = "0x";
722 ss << hexRep;
723 for (auto& kwVal : kw)
724 {
725 ss << std::setfill('0') << std::setw(2) << std::hex
726 << static_cast<int>(kwVal);
727 }
728 hexString = ss.str();
729 },
GiridhariKrishnan63639102023-03-02 05:55:47 -0600730 kw);
731 return hexString;
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500732}
733
GiridhariKrishnan63639102023-03-02 05:55:47 -0600734std::string getPrintableValue(const std::variant<Binary, std::string>& kwVal)
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500735{
GiridhariKrishnan63639102023-03-02 05:55:47 -0600736 std::string kwString{};
737 std::visit(
738 [&kwString](auto&& kwVal) {
Patrick Williams08dc31c2024-08-16 15:21:06 -0400739 const auto it =
740 std::find_if(kwVal.begin(), kwVal.end(),
741 [](const auto& kw) { return !isprint(kw); });
742 if (it != kwVal.end())
743 {
744 kwString = hexString(kwVal);
745 }
746 else
747 {
748 kwString = std::string(kwVal.begin(), kwVal.end());
749 }
750 },
GiridhariKrishnan63639102023-03-02 05:55:47 -0600751 kwVal);
752 return kwString;
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500753}
754
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500755void executePostFailAction(const nlohmann::json& json, const std::string& file)
Alpana Kumari735dee92022-03-25 01:24:40 -0500756{
757 if ((json["frus"][file].at(0)).find("postActionFail") ==
758 json["frus"][file].at(0).end())
759 {
760 return;
761 }
762
763 uint8_t pinValue = 0;
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500764 std::string pinName;
Alpana Kumari735dee92022-03-25 01:24:40 -0500765
766 for (const auto& postAction :
767 (json["frus"][file].at(0))["postActionFail"].items())
768 {
769 if (postAction.key() == "pin")
770 {
771 pinName = postAction.value();
772 }
773 else if (postAction.key() == "value")
774 {
775 // Get the value to set
776 pinValue = postAction.value();
777 }
778 }
779
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500780 std::cout << "Setting GPIO: " << pinName << " to " << (int)pinValue
781 << std::endl;
Alpana Kumari735dee92022-03-25 01:24:40 -0500782
783 try
784 {
785 gpiod::line outputLine = gpiod::find_line(pinName);
786
787 if (!outputLine)
788 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500789 throw GpioException(
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600790 "Couldn't find output line for the GPIO. Skipping "
791 "this GPIO action.");
Alpana Kumari735dee92022-03-25 01:24:40 -0500792 }
793 outputLine.request(
794 {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
795 pinValue);
796 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500797 catch (const std::exception& e)
Alpana Kumari735dee92022-03-25 01:24:40 -0500798 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500799 std::string i2cBusAddr;
800 std::string errMsg = e.what();
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600801 errMsg += "\nGPIO: " + pinName;
802
803 if ((json["frus"][file].at(0)["postActionFail"].find(
804 "gpioI2CAddress")) !=
805 json["frus"][file].at(0)["postActionFail"].end())
806 {
807 i2cBusAddr =
808 json["frus"][file].at(0)["postActionFail"]["gpioI2CAddress"];
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500809 errMsg += " i2cBusAddress: " + i2cBusAddr;
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600810 }
811
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500812 throw GpioException(e.what());
Alpana Kumari735dee92022-03-25 01:24:40 -0500813 }
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600814
815 return;
Alpana Kumari735dee92022-03-25 01:24:40 -0500816}
817
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500818std::optional<bool> isPresent(const nlohmann::json& json,
819 const std::string& file)
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530820
Alpana Kumari735dee92022-03-25 01:24:40 -0500821{
822 if ((json["frus"][file].at(0)).find("presence") !=
823 json["frus"][file].at(0).end())
824 {
825 if (((json["frus"][file].at(0)["presence"]).find("pin") !=
826 json["frus"][file].at(0)["presence"].end()) &&
827 ((json["frus"][file].at(0)["presence"]).find("value") !=
828 json["frus"][file].at(0)["presence"].end()))
829 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500830 std::string presPinName =
831 json["frus"][file].at(0)["presence"]["pin"];
Alpana Kumari735dee92022-03-25 01:24:40 -0500832 Byte presPinValue = json["frus"][file].at(0)["presence"]["value"];
833
834 try
835 {
836 gpiod::line presenceLine = gpiod::find_line(presPinName);
837
838 if (!presenceLine)
839 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500840 std::cerr << "Couldn't find the presence line for - "
841 << presPinName << std::endl;
Alpana Kumari40d1c192022-03-09 21:16:02 -0600842
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500843 throw GpioException(
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600844 "Couldn't find the presence line for the "
845 "GPIO. Skipping this GPIO action.");
Alpana Kumari735dee92022-03-25 01:24:40 -0500846 }
847
848 presenceLine.request({"Read the presence line",
849 gpiod::line_request::DIRECTION_INPUT, 0});
850
851 Byte gpioData = presenceLine.get_value();
852
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530853 return (gpioData == presPinValue);
Alpana Kumari735dee92022-03-25 01:24:40 -0500854 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500855 catch (const std::exception& e)
Alpana Kumari735dee92022-03-25 01:24:40 -0500856 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500857 std::string i2cBusAddr;
858 std::string errMsg = e.what();
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600859 errMsg += " GPIO : " + presPinName;
860
861 if ((json["frus"][file].at(0)["presence"])
862 .find("gpioI2CAddress") !=
863 json["frus"][file].at(0)["presence"].end())
864 {
865 i2cBusAddr =
866 json["frus"][file].at(0)["presence"]["gpioI2CAddress"];
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500867 errMsg += " i2cBusAddress: " + i2cBusAddr;
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600868 }
869
Alpana Kumari40d1c192022-03-09 21:16:02 -0600870 // Take failure postAction
871 executePostFailAction(json, file);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500872 throw GpioException(errMsg);
Alpana Kumari735dee92022-03-25 01:24:40 -0500873 }
874 }
Alpana Kumari40d1c192022-03-09 21:16:02 -0600875 else
876 {
Manojkiran Edaaf921752024-06-17 15:10:21 +0530877 // missing required information
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500878 std::cerr
Manojkiran Edaaf921752024-06-17 15:10:21 +0530879 << "VPD inventory JSON missing basic information of presence "
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500880 "for this FRU : ["
881 << file << "]. Executing executePostFailAction." << std::endl;
Alpana Kumari40d1c192022-03-09 21:16:02 -0600882
883 // Take failure postAction
884 executePostFailAction(json, file);
885
886 return false;
887 }
Alpana Kumari735dee92022-03-25 01:24:40 -0500888 }
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530889 return std::optional<bool>{};
890}
891
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500892bool executePreAction(const nlohmann::json& json, const std::string& file)
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530893{
894 auto present = isPresent(json, file);
895 if (present && !present.value())
896 {
897 executePostFailAction(json, file);
898 return false;
899 }
Alpana Kumari735dee92022-03-25 01:24:40 -0500900
901 if ((json["frus"][file].at(0)).find("preAction") !=
902 json["frus"][file].at(0).end())
903 {
904 if (((json["frus"][file].at(0)["preAction"]).find("pin") !=
905 json["frus"][file].at(0)["preAction"].end()) &&
906 ((json["frus"][file].at(0)["preAction"]).find("value") !=
907 json["frus"][file].at(0)["preAction"].end()))
908 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500909 std::string pinName = json["frus"][file].at(0)["preAction"]["pin"];
Alpana Kumari735dee92022-03-25 01:24:40 -0500910 // Get the value to set
911 Byte pinValue = json["frus"][file].at(0)["preAction"]["value"];
912
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500913 std::cout << "Setting GPIO: " << pinName << " to " << (int)pinValue
914 << std::endl;
Alpana Kumari735dee92022-03-25 01:24:40 -0500915 try
916 {
917 gpiod::line outputLine = gpiod::find_line(pinName);
918
919 if (!outputLine)
920 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500921 std::cerr << "Couldn't find the line for output pin - "
922 << pinName << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500923 throw GpioException(
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600924 "Couldn't find output line for the GPIO. "
925 "Skipping this GPIO action.");
Alpana Kumari735dee92022-03-25 01:24:40 -0500926 }
927 outputLine.request({"FRU pre-action",
928 ::gpiod::line_request::DIRECTION_OUTPUT, 0},
929 pinValue);
930 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500931 catch (const std::exception& e)
Alpana Kumari735dee92022-03-25 01:24:40 -0500932 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500933 std::string i2cBusAddr;
934 std::string errMsg = e.what();
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600935 errMsg += " GPIO : " + pinName;
936
937 if ((json["frus"][file].at(0)["preAction"])
938 .find("gpioI2CAddress") !=
939 json["frus"][file].at(0)["preAction"].end())
940 {
941 i2cBusAddr =
942 json["frus"][file].at(0)["preAction"]["gpioI2CAddress"];
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500943 errMsg += " i2cBusAddress: " + i2cBusAddr;
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600944 }
945
Alpana Kumari40d1c192022-03-09 21:16:02 -0600946 // Take failure postAction
947 executePostFailAction(json, file);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500948 throw GpioException(errMsg);
Alpana Kumari735dee92022-03-25 01:24:40 -0500949 }
950 }
Alpana Kumari40d1c192022-03-09 21:16:02 -0600951 else
952 {
Manojkiran Edaaf921752024-06-17 15:10:21 +0530953 // missing required information
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500954 std::cerr
Manojkiran Edaaf921752024-06-17 15:10:21 +0530955 << "VPD inventory JSON missing basic information of preAction "
Alpana Kumari40d1c192022-03-09 21:16:02 -0600956 "for this FRU : ["
Priyanga Ramasamye0084322022-09-27 06:28:33 -0500957 << file << "]. Executing executePostFailAction." << std::endl;
Alpana Kumari40d1c192022-03-09 21:16:02 -0600958
959 // Take failure postAction
960 executePostFailAction(json, file);
Alpana Kumari40d1c192022-03-09 21:16:02 -0600961 return false;
962 }
Alpana Kumari735dee92022-03-25 01:24:40 -0500963 }
964 return true;
965}
966
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -0600967void insertOrMerge(inventory::InterfaceMap& map,
968 const inventory::Interface& interface,
969 inventory::PropertyMap&& property)
970{
971 if (map.find(interface) != map.end())
972 {
973 auto& prop = map.at(interface);
974 prop.insert(property.begin(), property.end());
975 }
976 else
977 {
978 map.emplace(interface, property);
979 }
980}
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500981
982BIOSAttrValueType readBIOSAttribute(const std::string& attrName)
983{
984 std::tuple<std::string, BIOSAttrValueType, BIOSAttrValueType> attrVal;
985 auto bus = sdbusplus::bus::new_default();
986 auto method = bus.new_method_call(
987 "xyz.openbmc_project.BIOSConfigManager",
988 "/xyz/openbmc_project/bios_config/manager",
989 "xyz.openbmc_project.BIOSConfig.Manager", "GetAttribute");
990 method.append(attrName);
991 try
992 {
993 auto result = bus.call(method);
994 result.read(std::get<0>(attrVal), std::get<1>(attrVal),
995 std::get<2>(attrVal));
996 }
997 catch (const sdbusplus::exception::SdBusError& e)
998 {
999 std::cerr << "Failed to read BIOS Attribute: " << attrName << std::endl;
1000 std::cerr << e.what() << std::endl;
1001 }
1002 return std::get<1>(attrVal);
1003}
Priyanga Ramasamy335873f2022-05-18 01:31:54 -05001004
1005std::string getPowerState()
1006{
1007 // TODO: How do we handle multiple chassis?
Priyanga Ramasamye0084322022-09-27 06:28:33 -05001008 std::string powerState{};
Priyanga Ramasamy335873f2022-05-18 01:31:54 -05001009 auto bus = sdbusplus::bus::new_default();
Patrick Williams08dc31c2024-08-16 15:21:06 -04001010 auto properties =
1011 bus.new_method_call("xyz.openbmc_project.State.Chassis0",
1012 "/xyz/openbmc_project/state/chassis0",
1013 "org.freedesktop.DBus.Properties", "Get");
Priyanga Ramasamy335873f2022-05-18 01:31:54 -05001014 properties.append("xyz.openbmc_project.State.Chassis");
1015 properties.append("CurrentPowerState");
1016 auto result = bus.call(properties);
1017 if (!result.is_method_error())
1018 {
Priyanga Ramasamye0084322022-09-27 06:28:33 -05001019 std::variant<std::string> val;
Priyanga Ramasamy335873f2022-05-18 01:31:54 -05001020 result.read(val);
Priyanga Ramasamye0084322022-09-27 06:28:33 -05001021 if (auto pVal = std::get_if<std::string>(&val))
Priyanga Ramasamy335873f2022-05-18 01:31:54 -05001022 {
1023 powerState = *pVal;
1024 }
1025 }
Priyanga Ramasamye0084322022-09-27 06:28:33 -05001026 std::cout << "Power state is: " << powerState << std::endl;
Priyanga Ramasamy335873f2022-05-18 01:31:54 -05001027 return powerState;
1028}
Santosh Puranik6b2b5372022-06-02 20:49:02 +05301029
1030Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file)
1031{
1032 uint32_t offset = 0;
1033 // check if offset present?
1034 for (const auto& item : js["frus"][file])
1035 {
1036 if (item.find("offset") != item.end())
1037 {
1038 offset = item["offset"];
1039 }
1040 }
1041
1042 // TODO: Figure out a better way to get max possible VPD size.
1043 auto maxVPDSize = std::min(std::filesystem::file_size(file),
1044 static_cast<uintmax_t>(65504));
1045
1046 Binary vpdVector;
1047 vpdVector.resize(maxVPDSize);
Priyanga Ramasamye0084322022-09-27 06:28:33 -05001048 std::ifstream vpdFile;
jinuthomas45d54972023-07-03 04:36:29 -05001049 vpdFile.exceptions(std::ifstream::badbit | std::ifstream::failbit);
1050 try
1051 {
Jinu Joy Thomase2b03832023-08-22 19:51:31 +05301052 vpdFile.open(file, std::ios::binary | std::ios::in);
jinuthomas45d54972023-07-03 04:36:29 -05001053 vpdFile.seekg(offset, std::ios_base::cur);
1054 vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), maxVPDSize);
1055 vpdVector.resize(vpdFile.gcount());
1056 }
1057 catch (const std::ifstream::failure& fail)
1058 {
1059 std::cerr << "Exception in file handling [" << file
1060 << "] error : " << fail.what();
1061 std::cerr << "EEPROM file size =" << std::filesystem::file_size(file)
1062 << std::endl;
1063 std::cerr << "Stream file size = " << vpdFile.gcount() << std::endl;
1064 std::cerr << " Vector size" << vpdVector.size() << std::endl;
1065 throw;
1066 }
Santosh Puranik6b2b5372022-06-02 20:49:02 +05301067
Jinu Joy Thomase2b03832023-08-22 19:51:31 +05301068 // Make sure we reset the EEPROM pointer to a "safe" location if it was
1069 // a DDIMM SPD that we just read.
Santosh Puranik6b2b5372022-06-02 20:49:02 +05301070 for (const auto& item : js["frus"][file])
1071 {
1072 if (item.find("extraInterfaces") != item.end())
1073 {
1074 if (item["extraInterfaces"].find(
1075 "xyz.openbmc_project.Inventory.Item.Dimm") !=
1076 item["extraInterfaces"].end())
1077 {
Manojkiran Edaaf921752024-06-17 15:10:21 +05301078 // check added here for DDIMM only workaround
Jinu Joy Thomase2b03832023-08-22 19:51:31 +05301079 vpdType dimmType = vpdTypeCheck(vpdVector);
1080 if (dimmType == constants::DDR4_DDIMM_MEMORY_VPD ||
1081 dimmType == constants::DDR5_DDIMM_MEMORY_VPD)
jinuthomas45d54972023-07-03 04:36:29 -05001082 {
Jinu Joy Thomase2b03832023-08-22 19:51:31 +05301083 try
1084 {
1085 // moves the EEPROM pointer to 2048 'th byte.
1086 vpdFile.seekg(2047, std::ios::beg);
1087 // Read that byte and discard - to affirm the move
1088 // operation.
1089 char ch;
1090 vpdFile.read(&ch, sizeof(ch));
1091 }
1092 catch (const std::ifstream::failure& fail)
1093 {
1094 std::cerr << "Exception in file handling [" << file
1095 << "] error : " << fail.what();
1096 std::cerr << "Stream file size = " << vpdFile.gcount()
1097 << std::endl;
1098 throw;
1099 }
jinuthomas45d54972023-07-03 04:36:29 -05001100 }
Santosh Puranik6b2b5372022-06-02 20:49:02 +05301101 break;
1102 }
1103 }
1104 }
1105
1106 return vpdVector;
1107}
Priyanga Ramasamy5629fbc2023-03-01 08:17:19 -06001108
1109std::string getDbusNameForThisKw(const std::string& keyword)
1110{
1111 if (keyword[0] == constants::POUND_KW)
1112 {
1113 return (std::string(constants::POUND_KW_PREFIX) + keyword[1]);
1114 }
1115 else if (isdigit(keyword[0]))
1116 {
1117 return (std::string(constants::NUMERIC_KW_PREFIX) + keyword);
1118 }
1119 return keyword;
1120}
1121
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +05301122void clearVpdOnRemoval(const std::string& objPath,
1123 inventory::InterfaceMap& interfacesPropMap)
1124{
1125 std::vector<std::string> vpdRelatedInterfaces{
1126 constants::invOperationalStatusIntf, constants::invItemIntf,
1127 constants::invAssetIntf};
1128
1129 std::vector<std::string> interfaces{};
1130 auto mapperResponse = inventory::getObject(objPath, interfaces);
1131
1132 for (const auto& [service, interfaceList] : mapperResponse)
1133 {
1134 // Handle FRUs under PIM
1135 if (service.compare(pimService) != 0)
1136 {
1137 continue;
1138 }
1139
1140 for (const auto& interface : interfaceList)
1141 {
1142 // Only process for VPD related interfaces.
1143 if ((interface.find("com.ibm.ipzvpd") != std::string::npos) ||
1144 ((std::find(vpdRelatedInterfaces.begin(),
1145 vpdRelatedInterfaces.end(), interface)) !=
1146 vpdRelatedInterfaces.end()))
1147 {
1148 const auto propertyList = getAllDBusProperty<GetAllResultType>(
1149 service, objPath, interface);
1150
1151 inventory::PropertyMap propertyValueMap;
1152 for (auto aProperty : propertyList)
1153 {
1154 const auto& propertyName = std::get<0>(aProperty);
1155 const auto& propertyValue = std::get<1>(aProperty);
1156
1157 if (std::holds_alternative<Binary>(propertyValue))
1158 {
1159 propertyValueMap.emplace(propertyName, Binary{});
1160 }
1161 else if (std::holds_alternative<std::string>(propertyValue))
1162 {
1163 propertyValueMap.emplace(propertyName, std::string{});
1164 }
1165 else if (std::holds_alternative<bool>(propertyValue))
1166 {
1167 if (propertyName.compare("Present") == 0)
1168 {
1169 propertyValueMap.emplace(propertyName, false);
1170 }
1171 else if (propertyName.compare("Functional") == 0)
1172 {
1173 propertyValueMap.emplace(propertyName, true);
1174 }
1175 }
1176 }
1177 interfacesPropMap.emplace(interface,
1178 std::move(propertyValueMap));
1179 }
1180 }
1181 }
1182}
priyaram0eb8cac2023-09-20 09:16:46 +05301183
1184void findBackupVPDPaths(std::string& backupEepromPath,
1185 std::string& backupInvPath, const nlohmann::json& js)
1186{
1187 for (const auto& item : js["frus"][constants::systemVpdFilePath])
1188 {
1189 if (item.find("systemVpdBackupPath") != item.end())
1190 {
1191 backupEepromPath = item["systemVpdBackupPath"];
1192 for (const auto& item : js["frus"][backupEepromPath])
1193 {
1194 if (item.find("inventoryPath") != item.end())
1195 {
1196 backupInvPath = item["inventoryPath"];
1197 break;
1198 }
1199 }
1200 break;
1201 }
1202 }
1203}
1204
1205void getBackupRecordKeyword(std::string& record, std::string& keyword)
1206{
1207 for (const auto& recordKw : svpdKwdMap)
1208 {
1209 if (record == recordKw.first)
1210 {
1211 for (const auto& keywordInfo : recordKw.second)
1212 {
1213 if (keyword == get<0>(keywordInfo))
1214 {
1215 record = get<4>(keywordInfo);
1216 keyword = get<5>(keywordInfo);
1217 break;
1218 }
1219 }
1220 break;
1221 }
1222 }
1223}
PriyangaRamasamy44fca012024-08-26 02:35:05 -05001224
1225bool isReadOnlyEEPROM(const std::string& vpdPath,
1226 const nlohmann::json& jsObject)
1227{
1228 // check if given path is FRU path
1229 if (jsObject["frus"].contains(vpdPath))
1230 {
1231 return jsObject["frus"][vpdPath].at(0).value("readOnly", false);
1232 }
1233
1234 const nlohmann::json& fruList =
1235 jsObject["frus"].get_ref<const nlohmann::json::object_t&>();
1236
1237 for (const auto& fru : fruList.items())
1238 {
1239 const auto fruPath = fru.key();
1240
1241 // If given VPD path is either the inventory path or redundant EEPROM
1242 // path.
1243 if ((vpdPath ==
1244 jsObject["frus"][fruPath].at(0).value("inventoryPath", "")) ||
1245 (vpdPath ==
1246 jsObject["frus"][fruPath].at(0).value("redundantEeprom", "")))
1247 {
1248 return jsObject["frus"][fruPath].at(0).value("readOnly", false);
1249 }
1250 }
1251
1252 // Given path not found in JSON
1253 return false;
1254}
Patrick Venturec83c4dc2018-11-01 16:29:18 -07001255} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -05001256} // namespace openpower