16c71c9dcSSunny Srivastava #include "config.h"
26c71c9dcSSunny Srivastava 
36c71c9dcSSunny Srivastava #include "ibm_vpd_utils.hpp"
46c71c9dcSSunny Srivastava 
56c71c9dcSSunny Srivastava #include "common_utility.hpp"
66c71c9dcSSunny Srivastava #include "defines.hpp"
76c71c9dcSSunny Srivastava #include "vpd_exceptions.hpp"
86c71c9dcSSunny Srivastava 
96bd095f9SAlpana Kumari #include <boost/algorithm/string.hpp>
10735dee9bSAlpana Kumari #include <gpiod.hpp>
116c71c9dcSSunny Srivastava #include <nlohmann/json.hpp>
126c71c9dcSSunny Srivastava #include <phosphor-logging/elog-errors.hpp>
136c71c9dcSSunny Srivastava #include <phosphor-logging/log.hpp>
146c71c9dcSSunny Srivastava #include <sdbusplus/server.hpp>
15*c78d887cSPatrick Williams #include <xyz/openbmc_project/Common/error.hpp>
16*c78d887cSPatrick Williams 
17*c78d887cSPatrick Williams #include <filesystem>
18*c78d887cSPatrick Williams #include <fstream>
19*c78d887cSPatrick Williams #include <iomanip>
20*c78d887cSPatrick Williams #include <regex>
216c71c9dcSSunny Srivastava #include <sstream>
226c71c9dcSSunny Srivastava #include <vector>
236c71c9dcSSunny Srivastava 
246c71c9dcSSunny Srivastava using json = nlohmann::json;
256c71c9dcSSunny Srivastava 
266c71c9dcSSunny Srivastava namespace openpower
276c71c9dcSSunny Srivastava {
286c71c9dcSSunny Srivastava namespace vpd
296c71c9dcSSunny Srivastava {
306c71c9dcSSunny Srivastava using namespace openpower::vpd::constants;
316c71c9dcSSunny Srivastava using namespace inventory;
326c71c9dcSSunny Srivastava using namespace phosphor::logging;
336c71c9dcSSunny Srivastava using namespace sdbusplus::xyz::openbmc_project::Common::Error;
346c71c9dcSSunny Srivastava using namespace record;
356c71c9dcSSunny Srivastava using namespace openpower::vpd::exceptions;
366c71c9dcSSunny Srivastava using namespace common::utility;
370746eeebSSunny Srivastava using Severity = openpower::vpd::constants::PelSeverity;
38c2fe40f8SPriyangaRamasamy namespace fs = std::filesystem;
390746eeebSSunny Srivastava 
400746eeebSSunny Srivastava // mapping of severity enum to severity interface
410746eeebSSunny Srivastava static std::unordered_map<Severity, std::string> sevMap = {
420746eeebSSunny Srivastava     {Severity::INFORMATIONAL,
430746eeebSSunny Srivastava      "xyz.openbmc_project.Logging.Entry.Level.Informational"},
440746eeebSSunny Srivastava     {Severity::DEBUG, "xyz.openbmc_project.Logging.Entry.Level.Debug"},
450746eeebSSunny Srivastava     {Severity::NOTICE, "xyz.openbmc_project.Logging.Entry.Level.Notice"},
460746eeebSSunny Srivastava     {Severity::WARNING, "xyz.openbmc_project.Logging.Entry.Level.Warning"},
470746eeebSSunny Srivastava     {Severity::CRITICAL, "xyz.openbmc_project.Logging.Entry.Level.Critical"},
480746eeebSSunny Srivastava     {Severity::EMERGENCY, "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
490746eeebSSunny Srivastava     {Severity::ERROR, "xyz.openbmc_project.Logging.Entry.Level.Error"},
500746eeebSSunny Srivastava     {Severity::ALERT, "xyz.openbmc_project.Logging.Entry.Level.Alert"}};
510746eeebSSunny Srivastava 
526c71c9dcSSunny Srivastava namespace inventory
536c71c9dcSSunny Srivastava {
546c71c9dcSSunny Srivastava 
556c71c9dcSSunny Srivastava MapperResponse
566c71c9dcSSunny Srivastava     getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
576c71c9dcSSunny Srivastava                                   const std::vector<std::string>& interfaces)
586c71c9dcSSunny Srivastava {
596c71c9dcSSunny Srivastava     auto bus = sdbusplus::bus::new_default();
606c71c9dcSSunny Srivastava     auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath,
616c71c9dcSSunny Srivastava                                           mapperInterface, "GetSubTree");
626c71c9dcSSunny Srivastava     mapperCall.append(root);
636c71c9dcSSunny Srivastava     mapperCall.append(depth);
646c71c9dcSSunny Srivastava     mapperCall.append(interfaces);
656c71c9dcSSunny Srivastava 
666c71c9dcSSunny Srivastava     MapperResponse result = {};
676c71c9dcSSunny Srivastava 
686c71c9dcSSunny Srivastava     try
696c71c9dcSSunny Srivastava     {
706c71c9dcSSunny Srivastava         auto response = bus.call(mapperCall);
716c71c9dcSSunny Srivastava 
726c71c9dcSSunny Srivastava         response.read(result);
736c71c9dcSSunny Srivastava     }
742eb0176cSPatrick Williams     catch (const sdbusplus::exception_t& e)
756c71c9dcSSunny Srivastava     {
766c71c9dcSSunny Srivastava         log<level::ERR>("Error in mapper GetSubTree",
776c71c9dcSSunny Srivastava                         entry("ERROR=%s", e.what()));
786c71c9dcSSunny Srivastava     }
796c71c9dcSSunny Srivastava 
806c71c9dcSSunny Srivastava     return result;
816c71c9dcSSunny Srivastava }
826c71c9dcSSunny Srivastava 
836c71c9dcSSunny Srivastava } // namespace inventory
846c71c9dcSSunny Srivastava 
856c71c9dcSSunny Srivastava LE2ByteData readUInt16LE(Binary::const_iterator iterator)
866c71c9dcSSunny Srivastava {
876c71c9dcSSunny Srivastava     LE2ByteData lowByte = *iterator;
886c71c9dcSSunny Srivastava     LE2ByteData highByte = *(iterator + 1);
896c71c9dcSSunny Srivastava     lowByte |= (highByte << 8);
906c71c9dcSSunny Srivastava     return lowByte;
916c71c9dcSSunny Srivastava }
926c71c9dcSSunny Srivastava 
936c71c9dcSSunny Srivastava /** @brief Encodes a keyword for D-Bus.
946c71c9dcSSunny Srivastava  */
95e008432aSPriyanga Ramasamy std::string encodeKeyword(const std::string& kw, const std::string& encoding)
966c71c9dcSSunny Srivastava {
976c71c9dcSSunny Srivastava     if (encoding == "MAC")
986c71c9dcSSunny Srivastava     {
99e008432aSPriyanga Ramasamy         std::string res{};
1006c71c9dcSSunny Srivastava         size_t first = kw[0];
1016c71c9dcSSunny Srivastava         res += toHex(first >> 4);
1026c71c9dcSSunny Srivastava         res += toHex(first & 0x0f);
1036c71c9dcSSunny Srivastava         for (size_t i = 1; i < kw.size(); ++i)
1046c71c9dcSSunny Srivastava         {
1056c71c9dcSSunny Srivastava             res += ":";
1066c71c9dcSSunny Srivastava             res += toHex(kw[i] >> 4);
1076c71c9dcSSunny Srivastava             res += toHex(kw[i] & 0x0f);
1086c71c9dcSSunny Srivastava         }
1096c71c9dcSSunny Srivastava         return res;
1106c71c9dcSSunny Srivastava     }
1116c71c9dcSSunny Srivastava     else if (encoding == "DATE")
1126c71c9dcSSunny Srivastava     {
1136c71c9dcSSunny Srivastava         // Date, represent as
1146c71c9dcSSunny Srivastava         // <year>-<month>-<day> <hour>:<min>
115e008432aSPriyanga Ramasamy         std::string res{};
1166c71c9dcSSunny Srivastava         static constexpr uint8_t skipPrefix = 3;
1176c71c9dcSSunny Srivastava 
1186c71c9dcSSunny Srivastava         auto strItr = kw.begin();
1196c71c9dcSSunny Srivastava         advance(strItr, skipPrefix);
1206c71c9dcSSunny Srivastava         for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
1216c71c9dcSSunny Srivastava 
1226c71c9dcSSunny Srivastava         res.insert(BD_YEAR_END, 1, '-');
1236c71c9dcSSunny Srivastava         res.insert(BD_MONTH_END, 1, '-');
1246c71c9dcSSunny Srivastava         res.insert(BD_DAY_END, 1, ' ');
1256c71c9dcSSunny Srivastava         res.insert(BD_HOUR_END, 1, ':');
1266c71c9dcSSunny Srivastava 
1276c71c9dcSSunny Srivastava         return res;
1286c71c9dcSSunny Srivastava     }
1296c71c9dcSSunny Srivastava     else // default to string encoding
1306c71c9dcSSunny Srivastava     {
131e008432aSPriyanga Ramasamy         return std::string(kw.begin(), kw.end());
1326c71c9dcSSunny Srivastava     }
1336c71c9dcSSunny Srivastava }
1346c71c9dcSSunny Srivastava 
135e008432aSPriyanga Ramasamy std::string readBusProperty(const std::string& obj, const std::string& inf,
136e008432aSPriyanga Ramasamy                             const std::string& prop)
1376c71c9dcSSunny Srivastava {
1386c71c9dcSSunny Srivastava     std::string propVal{};
1396c71c9dcSSunny Srivastava     std::string object = INVENTORY_PATH + obj;
1406c71c9dcSSunny Srivastava     auto bus = sdbusplus::bus::new_default();
1416c71c9dcSSunny Srivastava     auto properties = bus.new_method_call(
1426c71c9dcSSunny Srivastava         "xyz.openbmc_project.Inventory.Manager", object.c_str(),
1436c71c9dcSSunny Srivastava         "org.freedesktop.DBus.Properties", "Get");
1446c71c9dcSSunny Srivastava     properties.append(inf);
1456c71c9dcSSunny Srivastava     properties.append(prop);
1466c71c9dcSSunny Srivastava     auto result = bus.call(properties);
1476c71c9dcSSunny Srivastava     if (!result.is_method_error())
1486c71c9dcSSunny Srivastava     {
14928abd6e4SSunny Srivastava         inventory::Value val;
1506c71c9dcSSunny Srivastava         result.read(val);
151e008432aSPriyanga Ramasamy         if (auto pVal = std::get_if<Binary>(&val))
1526c71c9dcSSunny Srivastava         {
1536c71c9dcSSunny Srivastava             propVal.assign(reinterpret_cast<const char*>(pVal->data()),
1546c71c9dcSSunny Srivastava                            pVal->size());
1556c71c9dcSSunny Srivastava         }
156e008432aSPriyanga Ramasamy         else if (auto pVal = std::get_if<std::string>(&val))
1576c71c9dcSSunny Srivastava         {
1586c71c9dcSSunny Srivastava             propVal.assign(pVal->data(), pVal->size());
1596c71c9dcSSunny Srivastava         }
16028abd6e4SSunny Srivastava         else if (auto pVal = get_if<bool>(&val))
16128abd6e4SSunny Srivastava         {
16228abd6e4SSunny Srivastava             if (*pVal == false)
16328abd6e4SSunny Srivastava             {
16428abd6e4SSunny Srivastava                 propVal = "false";
16528abd6e4SSunny Srivastava             }
16628abd6e4SSunny Srivastava             else
16728abd6e4SSunny Srivastava             {
16828abd6e4SSunny Srivastava                 propVal = "true";
16928abd6e4SSunny Srivastava             }
17028abd6e4SSunny Srivastava         }
1716c71c9dcSSunny Srivastava     }
1726c71c9dcSSunny Srivastava     return propVal;
1736c71c9dcSSunny Srivastava }
1746c71c9dcSSunny Srivastava 
1756c71c9dcSSunny Srivastava void createPEL(const std::map<std::string, std::string>& additionalData,
176a2ddc96eSSunny Srivastava                const Severity& sev, const std::string& errIntf, sd_bus* sdBus)
177a2ddc96eSSunny Srivastava {
178a2ddc96eSSunny Srivastava     // This pointer will be NULL in case the call is made from ibm-read-vpd. In
179a2ddc96eSSunny Srivastava     // that case a sync call will do.
180a2ddc96eSSunny Srivastava     if (sdBus == nullptr)
181a2ddc96eSSunny Srivastava     {
182a2ddc96eSSunny Srivastava         createSyncPEL(additionalData, sev, errIntf);
183a2ddc96eSSunny Srivastava     }
184a2ddc96eSSunny Srivastava     else
185a2ddc96eSSunny Srivastava     {
186a2ddc96eSSunny Srivastava         std::string errDescription{};
187a2ddc96eSSunny Srivastava         auto pos = additionalData.find("DESCRIPTION");
188a2ddc96eSSunny Srivastava         if (pos != additionalData.end())
189a2ddc96eSSunny Srivastava         {
190a2ddc96eSSunny Srivastava             errDescription = pos->second;
191a2ddc96eSSunny Srivastava         }
192a2ddc96eSSunny Srivastava         else
193a2ddc96eSSunny Srivastava         {
194a2ddc96eSSunny Srivastava             errDescription = "Description field missing in additional data";
195a2ddc96eSSunny Srivastava         }
196a2ddc96eSSunny Srivastava 
197a2ddc96eSSunny Srivastava         std::string pelSeverity =
198a2ddc96eSSunny Srivastava             "xyz.openbmc_project.Logging.Entry.Level.Error";
199a2ddc96eSSunny Srivastava         auto itr = sevMap.find(sev);
200a2ddc96eSSunny Srivastava         if (itr != sevMap.end())
201a2ddc96eSSunny Srivastava         {
202a2ddc96eSSunny Srivastava             pelSeverity = itr->second;
203a2ddc96eSSunny Srivastava         }
204a2ddc96eSSunny Srivastava 
205a2ddc96eSSunny Srivastava         // Implies this is a call from Manager. Hence we need to make an async
206a2ddc96eSSunny Srivastava         // call to avoid deadlock with Phosphor-logging.
207a2ddc96eSSunny Srivastava         auto rc = sd_bus_call_method_async(
208a2ddc96eSSunny Srivastava             sdBus, NULL, loggerService, loggerObjectPath, loggerCreateInterface,
209a2ddc96eSSunny Srivastava             "Create", NULL, NULL, "ssa{ss}", errIntf.c_str(),
210a2ddc96eSSunny Srivastava             pelSeverity.c_str(), 1, "DESCRIPTION", errDescription.c_str());
211a2ddc96eSSunny Srivastava 
212a2ddc96eSSunny Srivastava         if (rc < 0)
213a2ddc96eSSunny Srivastava         {
214a2ddc96eSSunny Srivastava             log<level::ERR>("Error calling sd_bus_call_method_async",
215a2ddc96eSSunny Srivastava                             entry("RC=%d", rc), entry("MSG=%s", strerror(-rc)));
216a2ddc96eSSunny Srivastava         }
217a2ddc96eSSunny Srivastava     }
218a2ddc96eSSunny Srivastava }
219a2ddc96eSSunny Srivastava 
220a2ddc96eSSunny Srivastava void createSyncPEL(const std::map<std::string, std::string>& additionalData,
2210746eeebSSunny Srivastava                    const Severity& sev, const std::string& errIntf)
2226c71c9dcSSunny Srivastava {
2236c71c9dcSSunny Srivastava     try
2246c71c9dcSSunny Srivastava     {
2250746eeebSSunny Srivastava         std::string pelSeverity =
2260746eeebSSunny Srivastava             "xyz.openbmc_project.Logging.Entry.Level.Error";
2276c71c9dcSSunny Srivastava         auto bus = sdbusplus::bus::new_default();
2286c71c9dcSSunny Srivastava         auto service = getService(bus, loggerObjectPath, loggerCreateInterface);
2296c71c9dcSSunny Srivastava         auto method = bus.new_method_call(service.c_str(), loggerObjectPath,
2306c71c9dcSSunny Srivastava                                           loggerCreateInterface, "Create");
2316c71c9dcSSunny Srivastava 
2320746eeebSSunny Srivastava         auto itr = sevMap.find(sev);
2330746eeebSSunny Srivastava         if (itr != sevMap.end())
2340746eeebSSunny Srivastava         {
2350746eeebSSunny Srivastava             pelSeverity = itr->second;
2360746eeebSSunny Srivastava         }
2370746eeebSSunny Srivastava 
2380746eeebSSunny Srivastava         method.append(errIntf, pelSeverity, additionalData);
2396c71c9dcSSunny Srivastava         auto resp = bus.call(method);
2406c71c9dcSSunny Srivastava     }
2412eb0176cSPatrick Williams     catch (const sdbusplus::exception_t& e)
2426c71c9dcSSunny Srivastava     {
2435ef6ccc0SSunny Srivastava         std::cerr << "Dbus call to phosphor-logging Create failed. Reason:"
2445ef6ccc0SSunny Srivastava                   << e.what();
2456c71c9dcSSunny Srivastava     }
2466c71c9dcSSunny Srivastava }
2476c71c9dcSSunny Srivastava 
248e008432aSPriyanga Ramasamy inventory::VPDfilepath getVpdFilePath(const std::string& jsonFile,
2496c71c9dcSSunny Srivastava                                       const std::string& ObjPath)
2506c71c9dcSSunny Srivastava {
251e008432aSPriyanga Ramasamy     std::ifstream inventoryJson(jsonFile);
2526c71c9dcSSunny Srivastava     const auto& jsonObject = json::parse(inventoryJson);
2536c71c9dcSSunny Srivastava     inventory::VPDfilepath filePath{};
2546c71c9dcSSunny Srivastava 
2556c71c9dcSSunny Srivastava     if (jsonObject.find("frus") == jsonObject.end())
2566c71c9dcSSunny Srivastava     {
2576c71c9dcSSunny Srivastava         throw(VpdJsonException(
2586c71c9dcSSunny Srivastava             "Invalid JSON structure - frus{} object not found in ", jsonFile));
2596c71c9dcSSunny Srivastava     }
2606c71c9dcSSunny Srivastava 
2616c71c9dcSSunny Srivastava     const nlohmann::json& groupFRUS =
2626c71c9dcSSunny Srivastava         jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
2636c71c9dcSSunny Srivastava     for (const auto& itemFRUS : groupFRUS.items())
2646c71c9dcSSunny Srivastava     {
2656c71c9dcSSunny Srivastava         const std::vector<nlohmann::json>& groupEEPROM =
2666c71c9dcSSunny Srivastava             itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
2676c71c9dcSSunny Srivastava         for (const auto& itemEEPROM : groupEEPROM)
2686c71c9dcSSunny Srivastava         {
2696c71c9dcSSunny Srivastava             if (itemEEPROM["inventoryPath"]
2706c71c9dcSSunny Srivastava                     .get_ref<const nlohmann::json::string_t&>() == ObjPath)
2716c71c9dcSSunny Srivastava             {
2726c71c9dcSSunny Srivastava                 filePath = itemFRUS.key();
2736c71c9dcSSunny Srivastava                 return filePath;
2746c71c9dcSSunny Srivastava             }
2756c71c9dcSSunny Srivastava         }
2766c71c9dcSSunny Srivastava     }
2776c71c9dcSSunny Srivastava 
2786c71c9dcSSunny Srivastava     return filePath;
2796c71c9dcSSunny Srivastava }
2806c71c9dcSSunny Srivastava 
2816c71c9dcSSunny Srivastava bool isPathInJson(const std::string& eepromPath)
2826c71c9dcSSunny Srivastava {
2836c71c9dcSSunny Srivastava     bool present = false;
284e008432aSPriyanga Ramasamy     std::ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
2856c71c9dcSSunny Srivastava 
2866c71c9dcSSunny Srivastava     try
2876c71c9dcSSunny Srivastava     {
2886c71c9dcSSunny Srivastava         auto js = json::parse(inventoryJson);
2896c71c9dcSSunny Srivastava         if (js.find("frus") == js.end())
2906c71c9dcSSunny Srivastava         {
2916c71c9dcSSunny Srivastava             throw(VpdJsonException(
2926c71c9dcSSunny Srivastava                 "Invalid JSON structure - frus{} object not found in ",
2936c71c9dcSSunny Srivastava                 INVENTORY_JSON_SYM_LINK));
2946c71c9dcSSunny Srivastava         }
2956c71c9dcSSunny Srivastava         json fruJson = js["frus"];
2966c71c9dcSSunny Srivastava 
2976c71c9dcSSunny Srivastava         if (fruJson.find(eepromPath) != fruJson.end())
2986c71c9dcSSunny Srivastava         {
2996c71c9dcSSunny Srivastava             present = true;
3006c71c9dcSSunny Srivastava         }
3016c71c9dcSSunny Srivastava     }
3028e15b93aSPatrick Williams     catch (const json::parse_error& ex)
3036c71c9dcSSunny Srivastava     {
3046c71c9dcSSunny Srivastava         throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
3056c71c9dcSSunny Srivastava     }
3066c71c9dcSSunny Srivastava     return present;
3076c71c9dcSSunny Srivastava }
3086c71c9dcSSunny Srivastava 
3096c71c9dcSSunny Srivastava bool isRecKwInDbusJson(const std::string& recordName,
3106c71c9dcSSunny Srivastava                        const std::string& keyword)
3116c71c9dcSSunny Srivastava {
312e008432aSPriyanga Ramasamy     std::ifstream propertyJson(DBUS_PROP_JSON);
3136c71c9dcSSunny Srivastava     json dbusProperty;
3146c71c9dcSSunny Srivastava     bool present = false;
3156c71c9dcSSunny Srivastava 
3166c71c9dcSSunny Srivastava     if (propertyJson.is_open())
3176c71c9dcSSunny Srivastava     {
3186c71c9dcSSunny Srivastava         try
3196c71c9dcSSunny Srivastava         {
3206c71c9dcSSunny Srivastava             auto dbusPropertyJson = json::parse(propertyJson);
3216c71c9dcSSunny Srivastava             if (dbusPropertyJson.find("dbusProperties") ==
3226c71c9dcSSunny Srivastava                 dbusPropertyJson.end())
3236c71c9dcSSunny Srivastava             {
3246c71c9dcSSunny Srivastava                 throw(VpdJsonException("dbusProperties{} object not found in "
3256c71c9dcSSunny Srivastava                                        "DbusProperties json : ",
3266c71c9dcSSunny Srivastava                                        DBUS_PROP_JSON));
3276c71c9dcSSunny Srivastava             }
3286c71c9dcSSunny Srivastava 
3296c71c9dcSSunny Srivastava             dbusProperty = dbusPropertyJson["dbusProperties"];
3306c71c9dcSSunny Srivastava             if (dbusProperty.contains(recordName))
3316c71c9dcSSunny Srivastava             {
332e008432aSPriyanga Ramasamy                 const std::vector<std::string>& kwdsToPublish =
333e008432aSPriyanga Ramasamy                     dbusProperty[recordName];
3346c71c9dcSSunny Srivastava                 if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
3356c71c9dcSSunny Srivastava                     kwdsToPublish.end()) // present
3366c71c9dcSSunny Srivastava                 {
3376c71c9dcSSunny Srivastava                     present = true;
3386c71c9dcSSunny Srivastava                 }
3396c71c9dcSSunny Srivastava             }
3406c71c9dcSSunny Srivastava         }
3418e15b93aSPatrick Williams         catch (const json::parse_error& ex)
3426c71c9dcSSunny Srivastava         {
3436c71c9dcSSunny Srivastava             throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
3446c71c9dcSSunny Srivastava         }
3456c71c9dcSSunny Srivastava     }
3466c71c9dcSSunny Srivastava     else
3476c71c9dcSSunny Srivastava     {
3486c71c9dcSSunny Srivastava         // If dbus properties json is not available, we assume the given
3496c71c9dcSSunny Srivastava         // record-keyword is part of dbus-properties json. So setting the bool
3506c71c9dcSSunny Srivastava         // variable to true.
3516c71c9dcSSunny Srivastava         present = true;
3526c71c9dcSSunny Srivastava     }
3536c71c9dcSSunny Srivastava     return present;
3546c71c9dcSSunny Srivastava }
3556c71c9dcSSunny Srivastava 
3566c71c9dcSSunny Srivastava vpdType vpdTypeCheck(const Binary& vpdVector)
3576c71c9dcSSunny Srivastava {
3586c71c9dcSSunny Srivastava     // Read first 3 Bytes to check the 11S bar code format
3596c71c9dcSSunny Srivastava     std::string is11SFormat = "";
3606c71c9dcSSunny Srivastava     for (uint8_t i = 0; i < FORMAT_11S_LEN; i++)
3616c71c9dcSSunny Srivastava     {
3626c71c9dcSSunny Srivastava         is11SFormat += vpdVector[MEMORY_VPD_DATA_START + i];
3636c71c9dcSSunny Srivastava     }
3646c71c9dcSSunny Srivastava 
3656c71c9dcSSunny Srivastava     if (vpdVector[IPZ_DATA_START] == KW_VAL_PAIR_START_TAG)
3666c71c9dcSSunny Srivastava     {
3676c71c9dcSSunny Srivastava         // IPZ VPD FORMAT
3686c71c9dcSSunny Srivastava         return vpdType::IPZ_VPD;
3696c71c9dcSSunny Srivastava     }
3706c71c9dcSSunny Srivastava     else if (vpdVector[KW_VPD_DATA_START] == KW_VPD_START_TAG)
3716c71c9dcSSunny Srivastava     {
3726c71c9dcSSunny Srivastava         // KEYWORD VPD FORMAT
3736c71c9dcSSunny Srivastava         return vpdType::KEYWORD_VPD;
3746c71c9dcSSunny Srivastava     }
3756555e7efSjinuthomas     else if (((vpdVector[SPD_BYTE_3] & SPD_BYTE_BIT_0_3_MASK) ==
3766555e7efSjinuthomas               SPD_MODULE_TYPE_DDIMM) &&
3770abbb9c9Sjinuthomas              (is11SFormat.compare(MEMORY_VPD_START_TAG) == 0))
3786c71c9dcSSunny Srivastava     {
3796555e7efSjinuthomas         // DDIMM Memory VPD format
3806555e7efSjinuthomas         if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR5)
3816555e7efSjinuthomas         {
3826555e7efSjinuthomas             return vpdType::DDR5_DDIMM_MEMORY_VPD;
3836555e7efSjinuthomas         }
3846555e7efSjinuthomas         else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR4)
3856555e7efSjinuthomas         {
3866555e7efSjinuthomas             return vpdType::DDR4_DDIMM_MEMORY_VPD;
3876555e7efSjinuthomas         }
3886555e7efSjinuthomas     }
3896555e7efSjinuthomas     else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR5)
3906555e7efSjinuthomas     {
3916555e7efSjinuthomas         // ISDIMM Memory VPD format
3926555e7efSjinuthomas         return vpdType::DDR5_ISDIMM_MEMORY_VPD;
3936555e7efSjinuthomas     }
3946555e7efSjinuthomas     else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR4)
3956555e7efSjinuthomas     {
3966555e7efSjinuthomas         // ISDIMM Memory VPD format
3976555e7efSjinuthomas         return vpdType::DDR4_ISDIMM_MEMORY_VPD;
3986c71c9dcSSunny Srivastava     }
3996c71c9dcSSunny Srivastava 
4006c71c9dcSSunny Srivastava     // INVALID VPD FORMAT
4016c71c9dcSSunny Srivastava     return vpdType::INVALID_VPD_FORMAT;
4026c71c9dcSSunny Srivastava }
4036c71c9dcSSunny Srivastava 
404e008432aSPriyanga Ramasamy const std::string getIM(const Parsed& vpdMap)
405f05effdbSAlpana Kumari {
406f05effdbSAlpana Kumari     Binary imVal;
407f05effdbSAlpana Kumari     auto property = vpdMap.find("VSBP");
408f05effdbSAlpana Kumari     if (property != vpdMap.end())
409f05effdbSAlpana Kumari     {
410f05effdbSAlpana Kumari         auto kw = (property->second).find("IM");
411f05effdbSAlpana Kumari         if (kw != (property->second).end())
412f05effdbSAlpana Kumari         {
413f05effdbSAlpana Kumari             copy(kw->second.begin(), kw->second.end(), back_inserter(imVal));
414f05effdbSAlpana Kumari         }
415f05effdbSAlpana Kumari     }
416f05effdbSAlpana Kumari 
417e008432aSPriyanga Ramasamy     std::ostringstream oss;
418f05effdbSAlpana Kumari     for (auto& i : imVal)
419f05effdbSAlpana Kumari     {
420e008432aSPriyanga Ramasamy         oss << std::setw(2) << std::setfill('0') << std::hex
421e008432aSPriyanga Ramasamy             << static_cast<int>(i);
422f05effdbSAlpana Kumari     }
423f05effdbSAlpana Kumari 
424f05effdbSAlpana Kumari     return oss.str();
425f05effdbSAlpana Kumari }
426f05effdbSAlpana Kumari 
427e008432aSPriyanga Ramasamy const std::string getHW(const Parsed& vpdMap)
428f05effdbSAlpana Kumari {
429f05effdbSAlpana Kumari     Binary hwVal;
430f05effdbSAlpana Kumari     auto prop = vpdMap.find("VINI");
431f05effdbSAlpana Kumari     if (prop != vpdMap.end())
432f05effdbSAlpana Kumari     {
433f05effdbSAlpana Kumari         auto kw = (prop->second).find("HW");
434f05effdbSAlpana Kumari         if (kw != (prop->second).end())
435f05effdbSAlpana Kumari         {
436f05effdbSAlpana Kumari             copy(kw->second.begin(), kw->second.end(), back_inserter(hwVal));
437f05effdbSAlpana Kumari         }
438f05effdbSAlpana Kumari     }
439f05effdbSAlpana Kumari 
44088d2ae82SAlpana Kumari     // The planar pass only comes from the LSB of the HW keyword,
44188d2ae82SAlpana Kumari     // where as the MSB is used for other purposes such as signifying clock
44288d2ae82SAlpana Kumari     // termination.
44388d2ae82SAlpana Kumari     hwVal[0] = 0x00;
44488d2ae82SAlpana Kumari 
445e008432aSPriyanga Ramasamy     std::ostringstream hwString;
446f05effdbSAlpana Kumari     for (auto& i : hwVal)
447f05effdbSAlpana Kumari     {
448e008432aSPriyanga Ramasamy         hwString << std::setw(2) << std::setfill('0') << std::hex
449e008432aSPriyanga Ramasamy                  << static_cast<int>(i);
450f05effdbSAlpana Kumari     }
451f05effdbSAlpana Kumari 
452f05effdbSAlpana Kumari     return hwString.str();
453f05effdbSAlpana Kumari }
454f05effdbSAlpana Kumari 
455e008432aSPriyanga Ramasamy std::string getSystemsJson(const Parsed& vpdMap)
456f05effdbSAlpana Kumari {
457e008432aSPriyanga Ramasamy     std::string jsonPath = "/usr/share/vpd/";
458e008432aSPriyanga Ramasamy     std::string jsonName{};
459f05effdbSAlpana Kumari 
460e008432aSPriyanga Ramasamy     std::ifstream systemJson(SYSTEM_JSON);
461f05effdbSAlpana Kumari     if (!systemJson)
462f05effdbSAlpana Kumari     {
463f05effdbSAlpana Kumari         throw((VpdJsonException("Failed to access Json path", SYSTEM_JSON)));
464f05effdbSAlpana Kumari     }
465f05effdbSAlpana Kumari 
466f05effdbSAlpana Kumari     try
467f05effdbSAlpana Kumari     {
468f05effdbSAlpana Kumari         auto js = json::parse(systemJson);
469f05effdbSAlpana Kumari 
470e008432aSPriyanga Ramasamy         std::string hwKeyword = getHW(vpdMap);
471e008432aSPriyanga Ramasamy         const std::string imKeyword = getIM(vpdMap);
472f05effdbSAlpana Kumari 
4731b026119SAlpana Kumari         transform(hwKeyword.begin(), hwKeyword.end(), hwKeyword.begin(),
4741b026119SAlpana Kumari                   ::toupper);
4751b026119SAlpana Kumari 
476f05effdbSAlpana Kumari         if (js.find("system") == js.end())
477f05effdbSAlpana Kumari         {
478e008432aSPriyanga Ramasamy             throw std::runtime_error("Invalid systems Json");
479f05effdbSAlpana Kumari         }
480f05effdbSAlpana Kumari 
481f05effdbSAlpana Kumari         if (js["system"].find(imKeyword) == js["system"].end())
482f05effdbSAlpana Kumari         {
483e008432aSPriyanga Ramasamy             throw std::runtime_error(
484f05effdbSAlpana Kumari                 "Invalid system. This system type is not present "
485f05effdbSAlpana Kumari                 "in the systemsJson. IM: " +
486f05effdbSAlpana Kumari                 imKeyword);
487f05effdbSAlpana Kumari         }
488f05effdbSAlpana Kumari 
489f05effdbSAlpana Kumari         if ((js["system"][imKeyword].find("constraint") !=
490f05effdbSAlpana Kumari              js["system"][imKeyword].end()) &&
4911b026119SAlpana Kumari             js["system"][imKeyword]["constraint"].find("HW") !=
4921b026119SAlpana Kumari                 js["system"][imKeyword]["constraint"].end())
4931b026119SAlpana Kumari         {
4941b026119SAlpana Kumari             // collect hw versions from json, and check hwKeyword  is part of it
4951b026119SAlpana Kumari             // if hwKeyword is found there then load respective json
4961b026119SAlpana Kumari             // otherwise load default one.
4971b026119SAlpana Kumari             for (const auto& hwVersion :
4981b026119SAlpana Kumari                  js["system"][imKeyword]["constraint"]["HW"])
4991b026119SAlpana Kumari             {
500e008432aSPriyanga Ramasamy                 std::string hw = hwVersion;
5011b026119SAlpana Kumari                 transform(hw.begin(), hw.end(), hw.begin(), ::toupper);
5021b026119SAlpana Kumari 
5031b026119SAlpana Kumari                 if (hw == hwKeyword)
504f05effdbSAlpana Kumari                 {
505f05effdbSAlpana Kumari                     jsonName = js["system"][imKeyword]["constraint"]["json"];
5061b026119SAlpana Kumari                     break;
5071b026119SAlpana Kumari                 }
5081b026119SAlpana Kumari             }
5091b026119SAlpana Kumari 
5101b026119SAlpana Kumari             if (jsonName.empty() && js["system"][imKeyword].find("default") !=
5111b026119SAlpana Kumari                                         js["system"][imKeyword].end())
5121b026119SAlpana Kumari             {
5131b026119SAlpana Kumari                 jsonName = js["system"][imKeyword]["default"];
5141b026119SAlpana Kumari             }
515f05effdbSAlpana Kumari         }
516f05effdbSAlpana Kumari         else if (js["system"][imKeyword].find("default") !=
517f05effdbSAlpana Kumari                  js["system"][imKeyword].end())
518f05effdbSAlpana Kumari         {
519f05effdbSAlpana Kumari             jsonName = js["system"][imKeyword]["default"];
520f05effdbSAlpana Kumari         }
521f05effdbSAlpana Kumari         else
522f05effdbSAlpana Kumari         {
523e008432aSPriyanga Ramasamy             throw std::runtime_error(
524f05effdbSAlpana Kumari                 "Bad System json. Neither constraint nor default found");
525f05effdbSAlpana Kumari         }
526f05effdbSAlpana Kumari 
527f05effdbSAlpana Kumari         jsonPath += jsonName;
528f05effdbSAlpana Kumari     }
529f05effdbSAlpana Kumari 
5308e15b93aSPatrick Williams     catch (const json::parse_error& ex)
531f05effdbSAlpana Kumari     {
532f05effdbSAlpana Kumari         throw(VpdJsonException("Json Parsing failed", SYSTEM_JSON));
533f05effdbSAlpana Kumari     }
534f05effdbSAlpana Kumari     return jsonPath;
535f05effdbSAlpana Kumari }
536f05effdbSAlpana Kumari 
537f457a3efSjinuthomas void udevToGenericPath(std::string& file, const std::string& driver)
538647868edSPriyangaRamasamy {
539647868edSPriyangaRamasamy     // Sample udevEvent i2c path :
540647868edSPriyangaRamasamy     // "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem"
541647868edSPriyangaRamasamy     // find if the path contains the word i2c in it.
542e008432aSPriyanga Ramasamy     if (file.find("i2c") != std::string::npos)
543647868edSPriyangaRamasamy     {
544e008432aSPriyanga Ramasamy         std::string i2cBusAddr{};
545647868edSPriyangaRamasamy 
546647868edSPriyangaRamasamy         // Every udev i2c path should have the common pattern
547647868edSPriyangaRamasamy         // "i2c-bus_number/bus_number-vpd_address". Search for
548647868edSPriyangaRamasamy         // "bus_number-vpd_address".
549e008432aSPriyanga Ramasamy         std::regex i2cPattern("((i2c)-[0-9]+\\/)([0-9]+-[0-9]{4})");
550e008432aSPriyanga Ramasamy         std::smatch match;
551e008432aSPriyanga Ramasamy         if (std::regex_search(file, match, i2cPattern))
552647868edSPriyangaRamasamy         {
553647868edSPriyangaRamasamy             i2cBusAddr = match.str(3);
554647868edSPriyangaRamasamy         }
555647868edSPriyangaRamasamy         else
556647868edSPriyangaRamasamy         {
557e008432aSPriyanga Ramasamy             std::cerr << "The given udev path < " << file
558647868edSPriyangaRamasamy                       << " > doesn't match the required pattern. Skipping VPD "
559647868edSPriyangaRamasamy                          "collection."
560e008432aSPriyanga Ramasamy                       << std::endl;
561647868edSPriyangaRamasamy             exit(EXIT_SUCCESS);
562647868edSPriyangaRamasamy         }
563647868edSPriyangaRamasamy         // Forming the generic file path
564f457a3efSjinuthomas         file = i2cPathPrefix + driver + "/" + i2cBusAddr + "/eeprom";
565647868edSPriyangaRamasamy     }
566647868edSPriyangaRamasamy     // Sample udevEvent spi path :
567647868edSPriyangaRamasamy     // "/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"
568647868edSPriyangaRamasamy     // find if the path contains the word spi in it.
569e008432aSPriyanga Ramasamy     else if (file.find("spi") != std::string::npos)
570647868edSPriyangaRamasamy     {
571647868edSPriyangaRamasamy         // Every udev spi path will have common pattern "spi<Digit>/", which
572647868edSPriyangaRamasamy         // describes the spi bus number at which the fru is connected; Followed
573647868edSPriyangaRamasamy         // by a slash following the vpd address of the fru. Taking the above
574647868edSPriyangaRamasamy         // input as a common key, we try to search for the pattern "spi<Digit>/"
575647868edSPriyangaRamasamy         // using regular expression.
576e008432aSPriyanga Ramasamy         std::regex spiPattern("((spi)[0-9]+)(\\/)");
577e008432aSPriyanga Ramasamy         std::string spiBus{};
578e008432aSPriyanga Ramasamy         std::smatch match;
579e008432aSPriyanga Ramasamy         if (std::regex_search(file, match, spiPattern))
580647868edSPriyangaRamasamy         {
581647868edSPriyangaRamasamy             spiBus = match.str(1);
582647868edSPriyangaRamasamy         }
583647868edSPriyangaRamasamy         else
584647868edSPriyangaRamasamy         {
585e008432aSPriyanga Ramasamy             std::cerr << "The given udev path < " << file
586647868edSPriyangaRamasamy                       << " > doesn't match the required pattern. Skipping VPD "
587647868edSPriyangaRamasamy                          "collection."
588e008432aSPriyanga Ramasamy                       << std::endl;
589647868edSPriyangaRamasamy             exit(EXIT_SUCCESS);
590647868edSPriyangaRamasamy         }
591647868edSPriyangaRamasamy         // Forming the generic path
592f457a3efSjinuthomas         file = spiPathPrefix + driver + "/" + spiBus + ".0/eeprom";
593647868edSPriyangaRamasamy     }
594647868edSPriyangaRamasamy     else
595647868edSPriyangaRamasamy     {
596e008432aSPriyanga Ramasamy         std::cerr << "\n The given EEPROM path < " << file
597647868edSPriyangaRamasamy                   << " > is not valid. It's neither I2C nor "
598647868edSPriyangaRamasamy                      "SPI path. Skipping VPD collection.."
599e008432aSPriyanga Ramasamy                   << std::endl;
600647868edSPriyangaRamasamy         exit(EXIT_SUCCESS);
601647868edSPriyangaRamasamy     }
602647868edSPriyangaRamasamy }
603e008432aSPriyanga Ramasamy std::string getBadVpdName(const std::string& file)
604c2fe40f8SPriyangaRamasamy {
605e008432aSPriyanga Ramasamy     std::string badVpd = BAD_VPD_DIR;
606e008432aSPriyanga Ramasamy     if (file.find("i2c") != std::string::npos)
607c2fe40f8SPriyangaRamasamy     {
608c2fe40f8SPriyangaRamasamy         badVpd += "i2c-";
609e008432aSPriyanga Ramasamy         std::regex i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
610e008432aSPriyanga Ramasamy         std::smatch match;
611e008432aSPriyanga Ramasamy         if (std::regex_search(file, match, i2cPattern))
612c2fe40f8SPriyangaRamasamy         {
613c2fe40f8SPriyangaRamasamy             badVpd += match.str(2);
614c2fe40f8SPriyangaRamasamy         }
615c2fe40f8SPriyangaRamasamy     }
616e008432aSPriyanga Ramasamy     else if (file.find("spi") != std::string::npos)
617c2fe40f8SPriyangaRamasamy     {
618e008432aSPriyanga Ramasamy         std::regex spiPattern("((spi)[0-9]+)(.0)");
619e008432aSPriyanga Ramasamy         std::smatch match;
620e008432aSPriyanga Ramasamy         if (std::regex_search(file, match, spiPattern))
621c2fe40f8SPriyangaRamasamy         {
622c2fe40f8SPriyangaRamasamy             badVpd += match.str(1);
623c2fe40f8SPriyangaRamasamy         }
624c2fe40f8SPriyangaRamasamy     }
625c2fe40f8SPriyangaRamasamy     return badVpd;
626c2fe40f8SPriyangaRamasamy }
627c2fe40f8SPriyangaRamasamy 
628e008432aSPriyanga Ramasamy void dumpBadVpd(const std::string& file, const Binary& vpdVector)
629c2fe40f8SPriyangaRamasamy {
630c2fe40f8SPriyangaRamasamy     fs::path badVpdDir = BAD_VPD_DIR;
631c2fe40f8SPriyangaRamasamy     fs::create_directory(badVpdDir);
632e008432aSPriyanga Ramasamy     std::string badVpdPath = getBadVpdName(file);
633c2fe40f8SPriyangaRamasamy     if (fs::exists(badVpdPath))
634c2fe40f8SPriyangaRamasamy     {
635c2fe40f8SPriyangaRamasamy         std::error_code ec;
636c2fe40f8SPriyangaRamasamy         fs::remove(badVpdPath, ec);
637c2fe40f8SPriyangaRamasamy         if (ec) // error code
638c2fe40f8SPriyangaRamasamy         {
639e008432aSPriyanga Ramasamy             std::string error = "Error removing the existing broken vpd in ";
640c2fe40f8SPriyangaRamasamy             error += badVpdPath;
641c2fe40f8SPriyangaRamasamy             error += ". Error code : ";
642c2fe40f8SPriyangaRamasamy             error += ec.value();
643c2fe40f8SPriyangaRamasamy             error += ". Error message : ";
644c2fe40f8SPriyangaRamasamy             error += ec.message();
645e008432aSPriyanga Ramasamy             throw std::runtime_error(error);
646c2fe40f8SPriyangaRamasamy         }
647c2fe40f8SPriyangaRamasamy     }
648e008432aSPriyanga Ramasamy     std::ofstream badVpdFileStream(badVpdPath, std::ofstream::binary);
649c2fe40f8SPriyangaRamasamy     if (!badVpdFileStream)
650c2fe40f8SPriyangaRamasamy     {
651e008432aSPriyanga Ramasamy         throw std::runtime_error(
652e008432aSPriyanga Ramasamy             "Failed to open bad vpd file path in /tmp/bad-vpd. "
653c2fe40f8SPriyangaRamasamy             "Unable to dump the broken/bad vpd file.");
654c2fe40f8SPriyangaRamasamy     }
655c2fe40f8SPriyangaRamasamy     badVpdFileStream.write(reinterpret_cast<const char*>(vpdVector.data()),
656c2fe40f8SPriyangaRamasamy                            vpdVector.size());
657c2fe40f8SPriyangaRamasamy }
6587ce68724Salpana07 
659e008432aSPriyanga Ramasamy const std::string getKwVal(const Parsed& vpdMap, const std::string& rec,
660e008432aSPriyanga Ramasamy                            const std::string& kwd)
6617ce68724Salpana07 {
662e008432aSPriyanga Ramasamy     std::string kwVal{};
6637ce68724Salpana07 
6647ce68724Salpana07     auto findRec = vpdMap.find(rec);
6657ce68724Salpana07 
6667ce68724Salpana07     // check if record is found in map we got by parser
6677ce68724Salpana07     if (findRec != vpdMap.end())
6687ce68724Salpana07     {
6697ce68724Salpana07         auto findKwd = findRec->second.find(kwd);
6707ce68724Salpana07 
6717ce68724Salpana07         if (findKwd != findRec->second.end())
6727ce68724Salpana07         {
6737ce68724Salpana07             kwVal = findKwd->second;
6747ce68724Salpana07         }
6757ce68724Salpana07     }
6767ce68724Salpana07 
6777ce68724Salpana07     return kwVal;
6787ce68724Salpana07 }
6797ce68724Salpana07 
68063639101SGiridhariKrishnan std::string hexString(const std::variant<Binary, std::string>& kw)
68163639101SGiridhariKrishnan {
68263639101SGiridhariKrishnan     std::string hexString;
68363639101SGiridhariKrishnan     std::visit(
68463639101SGiridhariKrishnan         [&hexString](auto&& kw) {
685e008432aSPriyanga Ramasamy         std::stringstream ss;
686e008432aSPriyanga Ramasamy         std::string hexRep = "0x";
68702434931SPriyanga Ramasamy         ss << hexRep;
688b498cd3cSgirik         for (auto& kwVal : kw)
689b498cd3cSgirik         {
69063639101SGiridhariKrishnan             ss << std::setfill('0') << std::setw(2) << std::hex
69163639101SGiridhariKrishnan                << static_cast<int>(kwVal);
69202434931SPriyanga Ramasamy         }
693b498cd3cSgirik         hexString = ss.str();
69463639101SGiridhariKrishnan         },
69563639101SGiridhariKrishnan         kw);
69663639101SGiridhariKrishnan     return hexString;
697c9ecf8eaSPriyanga Ramasamy }
698c9ecf8eaSPriyanga Ramasamy 
69963639101SGiridhariKrishnan std::string getPrintableValue(const std::variant<Binary, std::string>& kwVal)
700c9ecf8eaSPriyanga Ramasamy {
70163639101SGiridhariKrishnan     std::string kwString{};
70263639101SGiridhariKrishnan     std::visit(
70363639101SGiridhariKrishnan         [&kwString](auto&& kwVal) {
70463639101SGiridhariKrishnan         const auto it =
70563639101SGiridhariKrishnan             std::find_if(kwVal.begin(), kwVal.end(),
70663639101SGiridhariKrishnan                          [](const auto& kw) { return !isprint(kw); });
70763639101SGiridhariKrishnan         if (it != kwVal.end())
708c9ecf8eaSPriyanga Ramasamy         {
70963639101SGiridhariKrishnan             bool printable = true;
71063639101SGiridhariKrishnan             for (auto itr = it; itr != kwVal.end(); itr++)
711c9ecf8eaSPriyanga Ramasamy             {
712c9ecf8eaSPriyanga Ramasamy                 if (*itr != 0x00)
713c9ecf8eaSPriyanga Ramasamy                 {
71463639101SGiridhariKrishnan                     kwString = hexString(kwVal);
71563639101SGiridhariKrishnan                     printable = false;
71663639101SGiridhariKrishnan                     break;
717c9ecf8eaSPriyanga Ramasamy                 }
718c9ecf8eaSPriyanga Ramasamy             }
71963639101SGiridhariKrishnan             if (printable)
72063639101SGiridhariKrishnan             {
72163639101SGiridhariKrishnan                 kwString = std::string(kwVal.begin(), it);
72263639101SGiridhariKrishnan             }
72302434931SPriyanga Ramasamy         }
72402434931SPriyanga Ramasamy         else
72502434931SPriyanga Ramasamy         {
72663639101SGiridhariKrishnan             kwString = std::string(kwVal.begin(), kwVal.end());
72702434931SPriyanga Ramasamy         }
72863639101SGiridhariKrishnan         },
72963639101SGiridhariKrishnan         kwVal);
73063639101SGiridhariKrishnan     return kwString;
73102434931SPriyanga Ramasamy }
73202434931SPriyanga Ramasamy 
733e008432aSPriyanga Ramasamy void executePostFailAction(const nlohmann::json& json, const std::string& file)
734735dee9bSAlpana Kumari {
735735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("postActionFail") ==
736735dee9bSAlpana Kumari         json["frus"][file].at(0).end())
737735dee9bSAlpana Kumari     {
738735dee9bSAlpana Kumari         return;
739735dee9bSAlpana Kumari     }
740735dee9bSAlpana Kumari 
741735dee9bSAlpana Kumari     uint8_t pinValue = 0;
742e008432aSPriyanga Ramasamy     std::string pinName;
743735dee9bSAlpana Kumari 
744735dee9bSAlpana Kumari     for (const auto& postAction :
745735dee9bSAlpana Kumari          (json["frus"][file].at(0))["postActionFail"].items())
746735dee9bSAlpana Kumari     {
747735dee9bSAlpana Kumari         if (postAction.key() == "pin")
748735dee9bSAlpana Kumari         {
749735dee9bSAlpana Kumari             pinName = postAction.value();
750735dee9bSAlpana Kumari         }
751735dee9bSAlpana Kumari         else if (postAction.key() == "value")
752735dee9bSAlpana Kumari         {
753735dee9bSAlpana Kumari             // Get the value to set
754735dee9bSAlpana Kumari             pinValue = postAction.value();
755735dee9bSAlpana Kumari         }
756735dee9bSAlpana Kumari     }
757735dee9bSAlpana Kumari 
758e008432aSPriyanga Ramasamy     std::cout << "Setting GPIO: " << pinName << " to " << (int)pinValue
759e008432aSPriyanga Ramasamy               << std::endl;
760735dee9bSAlpana Kumari 
761735dee9bSAlpana Kumari     try
762735dee9bSAlpana Kumari     {
763735dee9bSAlpana Kumari         gpiod::line outputLine = gpiod::find_line(pinName);
764735dee9bSAlpana Kumari 
765735dee9bSAlpana Kumari         if (!outputLine)
766735dee9bSAlpana Kumari         {
767a2ddc96eSSunny Srivastava             throw GpioException(
7686bd095f9SAlpana Kumari                 "Couldn't find output line for the GPIO. Skipping "
7696bd095f9SAlpana Kumari                 "this GPIO action.");
770735dee9bSAlpana Kumari         }
771735dee9bSAlpana Kumari         outputLine.request(
772735dee9bSAlpana Kumari             {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
773735dee9bSAlpana Kumari             pinValue);
774735dee9bSAlpana Kumari     }
775e008432aSPriyanga Ramasamy     catch (const std::exception& e)
776735dee9bSAlpana Kumari     {
777e008432aSPriyanga Ramasamy         std::string i2cBusAddr;
778e008432aSPriyanga Ramasamy         std::string errMsg = e.what();
7796bd095f9SAlpana Kumari         errMsg += "\nGPIO: " + pinName;
7806bd095f9SAlpana Kumari 
7816bd095f9SAlpana Kumari         if ((json["frus"][file].at(0)["postActionFail"].find(
7826bd095f9SAlpana Kumari                 "gpioI2CAddress")) !=
7836bd095f9SAlpana Kumari             json["frus"][file].at(0)["postActionFail"].end())
7846bd095f9SAlpana Kumari         {
7856bd095f9SAlpana Kumari             i2cBusAddr =
7866bd095f9SAlpana Kumari                 json["frus"][file].at(0)["postActionFail"]["gpioI2CAddress"];
787fdf9ff2aSSunny Srivastava             errMsg += " i2cBusAddress: " + i2cBusAddr;
788735dee9bSAlpana Kumari         }
7896bd095f9SAlpana Kumari 
790a2ddc96eSSunny Srivastava         throw GpioException(e.what());
7916bd095f9SAlpana Kumari     }
7926bd095f9SAlpana Kumari 
7936bd095f9SAlpana Kumari     return;
794735dee9bSAlpana Kumari }
795735dee9bSAlpana Kumari 
796e008432aSPriyanga Ramasamy std::optional<bool> isPresent(const nlohmann::json& json,
797e008432aSPriyanga Ramasamy                               const std::string& file)
79853b38ed0SSantosh Puranik 
799735dee9bSAlpana Kumari {
800735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("presence") !=
801735dee9bSAlpana Kumari         json["frus"][file].at(0).end())
802735dee9bSAlpana Kumari     {
803735dee9bSAlpana Kumari         if (((json["frus"][file].at(0)["presence"]).find("pin") !=
804735dee9bSAlpana Kumari              json["frus"][file].at(0)["presence"].end()) &&
805735dee9bSAlpana Kumari             ((json["frus"][file].at(0)["presence"]).find("value") !=
806735dee9bSAlpana Kumari              json["frus"][file].at(0)["presence"].end()))
807735dee9bSAlpana Kumari         {
808e008432aSPriyanga Ramasamy             std::string presPinName =
809e008432aSPriyanga Ramasamy                 json["frus"][file].at(0)["presence"]["pin"];
810735dee9bSAlpana Kumari             Byte presPinValue = json["frus"][file].at(0)["presence"]["value"];
811735dee9bSAlpana Kumari 
812735dee9bSAlpana Kumari             try
813735dee9bSAlpana Kumari             {
814735dee9bSAlpana Kumari                 gpiod::line presenceLine = gpiod::find_line(presPinName);
815735dee9bSAlpana Kumari 
816735dee9bSAlpana Kumari                 if (!presenceLine)
817735dee9bSAlpana Kumari                 {
818e008432aSPriyanga Ramasamy                     std::cerr << "Couldn't find the presence line for - "
819e008432aSPriyanga Ramasamy                               << presPinName << std::endl;
82040d1c196SAlpana Kumari 
821a2ddc96eSSunny Srivastava                     throw GpioException(
8226bd095f9SAlpana Kumari                         "Couldn't find the presence line for the "
8236bd095f9SAlpana Kumari                         "GPIO. Skipping this GPIO action.");
824735dee9bSAlpana Kumari                 }
825735dee9bSAlpana Kumari 
826735dee9bSAlpana Kumari                 presenceLine.request({"Read the presence line",
827735dee9bSAlpana Kumari                                       gpiod::line_request::DIRECTION_INPUT, 0});
828735dee9bSAlpana Kumari 
829735dee9bSAlpana Kumari                 Byte gpioData = presenceLine.get_value();
830735dee9bSAlpana Kumari 
83153b38ed0SSantosh Puranik                 return (gpioData == presPinValue);
832735dee9bSAlpana Kumari             }
833e008432aSPriyanga Ramasamy             catch (const std::exception& e)
834735dee9bSAlpana Kumari             {
835e008432aSPriyanga Ramasamy                 std::string i2cBusAddr;
836e008432aSPriyanga Ramasamy                 std::string errMsg = e.what();
8376bd095f9SAlpana Kumari                 errMsg += " GPIO : " + presPinName;
8386bd095f9SAlpana Kumari 
8396bd095f9SAlpana Kumari                 if ((json["frus"][file].at(0)["presence"])
8406bd095f9SAlpana Kumari                         .find("gpioI2CAddress") !=
8416bd095f9SAlpana Kumari                     json["frus"][file].at(0)["presence"].end())
8426bd095f9SAlpana Kumari                 {
8436bd095f9SAlpana Kumari                     i2cBusAddr =
8446bd095f9SAlpana Kumari                         json["frus"][file].at(0)["presence"]["gpioI2CAddress"];
845fdf9ff2aSSunny Srivastava                     errMsg += " i2cBusAddress: " + i2cBusAddr;
8466bd095f9SAlpana Kumari                 }
8476bd095f9SAlpana Kumari 
84840d1c196SAlpana Kumari                 // Take failure postAction
84940d1c196SAlpana Kumari                 executePostFailAction(json, file);
850a2ddc96eSSunny Srivastava                 throw GpioException(errMsg);
851735dee9bSAlpana Kumari             }
852735dee9bSAlpana Kumari         }
85340d1c196SAlpana Kumari         else
85440d1c196SAlpana Kumari         {
85540d1c196SAlpana Kumari             // missing required informations
856e008432aSPriyanga Ramasamy             std::cerr
857e008432aSPriyanga Ramasamy                 << "VPD inventory JSON missing basic informations of presence "
85840d1c196SAlpana Kumari                    "for this FRU : ["
859e008432aSPriyanga Ramasamy                 << file << "]. Executing executePostFailAction." << std::endl;
86040d1c196SAlpana Kumari 
86140d1c196SAlpana Kumari             // Take failure postAction
86240d1c196SAlpana Kumari             executePostFailAction(json, file);
86340d1c196SAlpana Kumari 
86440d1c196SAlpana Kumari             return false;
86540d1c196SAlpana Kumari         }
866735dee9bSAlpana Kumari     }
86753b38ed0SSantosh Puranik     return std::optional<bool>{};
86853b38ed0SSantosh Puranik }
86953b38ed0SSantosh Puranik 
870e008432aSPriyanga Ramasamy bool executePreAction(const nlohmann::json& json, const std::string& file)
87153b38ed0SSantosh Puranik {
87253b38ed0SSantosh Puranik     auto present = isPresent(json, file);
87353b38ed0SSantosh Puranik     if (present && !present.value())
87453b38ed0SSantosh Puranik     {
87553b38ed0SSantosh Puranik         executePostFailAction(json, file);
87653b38ed0SSantosh Puranik         return false;
87753b38ed0SSantosh Puranik     }
878735dee9bSAlpana Kumari 
879735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("preAction") !=
880735dee9bSAlpana Kumari         json["frus"][file].at(0).end())
881735dee9bSAlpana Kumari     {
882735dee9bSAlpana Kumari         if (((json["frus"][file].at(0)["preAction"]).find("pin") !=
883735dee9bSAlpana Kumari              json["frus"][file].at(0)["preAction"].end()) &&
884735dee9bSAlpana Kumari             ((json["frus"][file].at(0)["preAction"]).find("value") !=
885735dee9bSAlpana Kumari              json["frus"][file].at(0)["preAction"].end()))
886735dee9bSAlpana Kumari         {
887e008432aSPriyanga Ramasamy             std::string pinName = json["frus"][file].at(0)["preAction"]["pin"];
888735dee9bSAlpana Kumari             // Get the value to set
889735dee9bSAlpana Kumari             Byte pinValue = json["frus"][file].at(0)["preAction"]["value"];
890735dee9bSAlpana Kumari 
891e008432aSPriyanga Ramasamy             std::cout << "Setting GPIO: " << pinName << " to " << (int)pinValue
892e008432aSPriyanga Ramasamy                       << std::endl;
893735dee9bSAlpana Kumari             try
894735dee9bSAlpana Kumari             {
895735dee9bSAlpana Kumari                 gpiod::line outputLine = gpiod::find_line(pinName);
896735dee9bSAlpana Kumari 
897735dee9bSAlpana Kumari                 if (!outputLine)
898735dee9bSAlpana Kumari                 {
899e008432aSPriyanga Ramasamy                     std::cerr << "Couldn't find the line for output pin - "
900e008432aSPriyanga Ramasamy                               << pinName << std::endl;
901a2ddc96eSSunny Srivastava                     throw GpioException(
9026bd095f9SAlpana Kumari                         "Couldn't find output line for the GPIO. "
9036bd095f9SAlpana Kumari                         "Skipping this GPIO action.");
904735dee9bSAlpana Kumari                 }
905735dee9bSAlpana Kumari                 outputLine.request({"FRU pre-action",
906735dee9bSAlpana Kumari                                     ::gpiod::line_request::DIRECTION_OUTPUT, 0},
907735dee9bSAlpana Kumari                                    pinValue);
908735dee9bSAlpana Kumari             }
909e008432aSPriyanga Ramasamy             catch (const std::exception& e)
910735dee9bSAlpana Kumari             {
911e008432aSPriyanga Ramasamy                 std::string i2cBusAddr;
912e008432aSPriyanga Ramasamy                 std::string errMsg = e.what();
9136bd095f9SAlpana Kumari                 errMsg += " GPIO : " + pinName;
9146bd095f9SAlpana Kumari 
9156bd095f9SAlpana Kumari                 if ((json["frus"][file].at(0)["preAction"])
9166bd095f9SAlpana Kumari                         .find("gpioI2CAddress") !=
9176bd095f9SAlpana Kumari                     json["frus"][file].at(0)["preAction"].end())
9186bd095f9SAlpana Kumari                 {
9196bd095f9SAlpana Kumari                     i2cBusAddr =
9206bd095f9SAlpana Kumari                         json["frus"][file].at(0)["preAction"]["gpioI2CAddress"];
921fdf9ff2aSSunny Srivastava                     errMsg += " i2cBusAddress: " + i2cBusAddr;
9226bd095f9SAlpana Kumari                 }
9236bd095f9SAlpana Kumari 
92440d1c196SAlpana Kumari                 // Take failure postAction
92540d1c196SAlpana Kumari                 executePostFailAction(json, file);
926a2ddc96eSSunny Srivastava                 throw GpioException(errMsg);
927735dee9bSAlpana Kumari             }
928735dee9bSAlpana Kumari         }
92940d1c196SAlpana Kumari         else
93040d1c196SAlpana Kumari         {
93140d1c196SAlpana Kumari             // missing required informations
932e008432aSPriyanga Ramasamy             std::cerr
93340d1c196SAlpana Kumari                 << "VPD inventory JSON missing basic informations of preAction "
93440d1c196SAlpana Kumari                    "for this FRU : ["
935e008432aSPriyanga Ramasamy                 << file << "]. Executing executePostFailAction." << std::endl;
93640d1c196SAlpana Kumari 
93740d1c196SAlpana Kumari             // Take failure postAction
93840d1c196SAlpana Kumari             executePostFailAction(json, file);
93940d1c196SAlpana Kumari             return false;
94040d1c196SAlpana Kumari         }
941735dee9bSAlpana Kumari     }
942735dee9bSAlpana Kumari     return true;
943735dee9bSAlpana Kumari }
944735dee9bSAlpana Kumari 
945aa8a893eSPriyanga Ramasamy void insertOrMerge(inventory::InterfaceMap& map,
946aa8a893eSPriyanga Ramasamy                    const inventory::Interface& interface,
947aa8a893eSPriyanga Ramasamy                    inventory::PropertyMap&& property)
948aa8a893eSPriyanga Ramasamy {
949aa8a893eSPriyanga Ramasamy     if (map.find(interface) != map.end())
950aa8a893eSPriyanga Ramasamy     {
951aa8a893eSPriyanga Ramasamy         auto& prop = map.at(interface);
952aa8a893eSPriyanga Ramasamy         prop.insert(property.begin(), property.end());
953aa8a893eSPriyanga Ramasamy     }
954aa8a893eSPriyanga Ramasamy     else
955aa8a893eSPriyanga Ramasamy     {
956aa8a893eSPriyanga Ramasamy         map.emplace(interface, property);
957aa8a893eSPriyanga Ramasamy     }
958aa8a893eSPriyanga Ramasamy }
959f2d3b53dSSantosh Puranik 
960f2d3b53dSSantosh Puranik BIOSAttrValueType readBIOSAttribute(const std::string& attrName)
961f2d3b53dSSantosh Puranik {
962f2d3b53dSSantosh Puranik     std::tuple<std::string, BIOSAttrValueType, BIOSAttrValueType> attrVal;
963f2d3b53dSSantosh Puranik     auto bus = sdbusplus::bus::new_default();
964f2d3b53dSSantosh Puranik     auto method = bus.new_method_call(
965f2d3b53dSSantosh Puranik         "xyz.openbmc_project.BIOSConfigManager",
966f2d3b53dSSantosh Puranik         "/xyz/openbmc_project/bios_config/manager",
967f2d3b53dSSantosh Puranik         "xyz.openbmc_project.BIOSConfig.Manager", "GetAttribute");
968f2d3b53dSSantosh Puranik     method.append(attrName);
969f2d3b53dSSantosh Puranik     try
970f2d3b53dSSantosh Puranik     {
971f2d3b53dSSantosh Puranik         auto result = bus.call(method);
972f2d3b53dSSantosh Puranik         result.read(std::get<0>(attrVal), std::get<1>(attrVal),
973f2d3b53dSSantosh Puranik                     std::get<2>(attrVal));
974f2d3b53dSSantosh Puranik     }
975f2d3b53dSSantosh Puranik     catch (const sdbusplus::exception::SdBusError& e)
976f2d3b53dSSantosh Puranik     {
977f2d3b53dSSantosh Puranik         std::cerr << "Failed to read BIOS Attribute: " << attrName << std::endl;
978f2d3b53dSSantosh Puranik         std::cerr << e.what() << std::endl;
979f2d3b53dSSantosh Puranik     }
980f2d3b53dSSantosh Puranik     return std::get<1>(attrVal);
981f2d3b53dSSantosh Puranik }
982335873f6SPriyanga Ramasamy 
983335873f6SPriyanga Ramasamy std::string getPowerState()
984335873f6SPriyanga Ramasamy {
985335873f6SPriyanga Ramasamy     // TODO: How do we handle multiple chassis?
986e008432aSPriyanga Ramasamy     std::string powerState{};
987335873f6SPriyanga Ramasamy     auto bus = sdbusplus::bus::new_default();
988*c78d887cSPatrick Williams     auto properties = bus.new_method_call("xyz.openbmc_project.State.Chassis",
989335873f6SPriyanga Ramasamy                                           "/xyz/openbmc_project/state/chassis0",
990*c78d887cSPatrick Williams                                           "org.freedesktop.DBus.Properties",
991*c78d887cSPatrick Williams                                           "Get");
992335873f6SPriyanga Ramasamy     properties.append("xyz.openbmc_project.State.Chassis");
993335873f6SPriyanga Ramasamy     properties.append("CurrentPowerState");
994335873f6SPriyanga Ramasamy     auto result = bus.call(properties);
995335873f6SPriyanga Ramasamy     if (!result.is_method_error())
996335873f6SPriyanga Ramasamy     {
997e008432aSPriyanga Ramasamy         std::variant<std::string> val;
998335873f6SPriyanga Ramasamy         result.read(val);
999e008432aSPriyanga Ramasamy         if (auto pVal = std::get_if<std::string>(&val))
1000335873f6SPriyanga Ramasamy         {
1001335873f6SPriyanga Ramasamy             powerState = *pVal;
1002335873f6SPriyanga Ramasamy         }
1003335873f6SPriyanga Ramasamy     }
1004e008432aSPriyanga Ramasamy     std::cout << "Power state is: " << powerState << std::endl;
1005335873f6SPriyanga Ramasamy     return powerState;
1006335873f6SPriyanga Ramasamy }
10076b2b5374SSantosh Puranik 
10086b2b5374SSantosh Puranik Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file)
10096b2b5374SSantosh Puranik {
10106b2b5374SSantosh Puranik     uint32_t offset = 0;
10116b2b5374SSantosh Puranik     // check if offset present?
10126b2b5374SSantosh Puranik     for (const auto& item : js["frus"][file])
10136b2b5374SSantosh Puranik     {
10146b2b5374SSantosh Puranik         if (item.find("offset") != item.end())
10156b2b5374SSantosh Puranik         {
10166b2b5374SSantosh Puranik             offset = item["offset"];
10176b2b5374SSantosh Puranik         }
10186b2b5374SSantosh Puranik     }
10196b2b5374SSantosh Puranik 
10206b2b5374SSantosh Puranik     // TODO: Figure out a better way to get max possible VPD size.
10216b2b5374SSantosh Puranik     auto maxVPDSize = std::min(std::filesystem::file_size(file),
10226b2b5374SSantosh Puranik                                static_cast<uintmax_t>(65504));
10236b2b5374SSantosh Puranik 
10246b2b5374SSantosh Puranik     Binary vpdVector;
10256b2b5374SSantosh Puranik     vpdVector.resize(maxVPDSize);
1026e008432aSPriyanga Ramasamy     std::ifstream vpdFile;
1027e008432aSPriyanga Ramasamy     vpdFile.open(file, std::ios::binary);
10286b2b5374SSantosh Puranik 
1029e008432aSPriyanga Ramasamy     vpdFile.seekg(offset, std::ios_base::cur);
10306b2b5374SSantosh Puranik     vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), maxVPDSize);
10316b2b5374SSantosh Puranik     vpdVector.resize(vpdFile.gcount());
10326b2b5374SSantosh Puranik 
10336b2b5374SSantosh Puranik     // Make sure we reset the EEPROM pointer to a "safe" location if it was DIMM
10346b2b5374SSantosh Puranik     // SPD that we just read.
10356b2b5374SSantosh Puranik     for (const auto& item : js["frus"][file])
10366b2b5374SSantosh Puranik     {
10376b2b5374SSantosh Puranik         if (item.find("extraInterfaces") != item.end())
10386b2b5374SSantosh Puranik         {
10396b2b5374SSantosh Puranik             if (item["extraInterfaces"].find(
10406b2b5374SSantosh Puranik                     "xyz.openbmc_project.Inventory.Item.Dimm") !=
10416b2b5374SSantosh Puranik                 item["extraInterfaces"].end())
10426b2b5374SSantosh Puranik             {
10436b2b5374SSantosh Puranik                 // moves the EEPROM pointer to 2048 'th byte.
10446b2b5374SSantosh Puranik                 vpdFile.seekg(2047, std::ios::beg);
10456b2b5374SSantosh Puranik                 // Read that byte and discard - to affirm the move
10466b2b5374SSantosh Puranik                 // operation.
10476b2b5374SSantosh Puranik                 char ch;
10486b2b5374SSantosh Puranik                 vpdFile.read(&ch, sizeof(ch));
10496b2b5374SSantosh Puranik                 break;
10506b2b5374SSantosh Puranik             }
10516b2b5374SSantosh Puranik         }
10526b2b5374SSantosh Puranik     }
10536b2b5374SSantosh Puranik 
10546b2b5374SSantosh Puranik     return vpdVector;
10556b2b5374SSantosh Puranik }
10565629fbc0SPriyanga Ramasamy 
10575629fbc0SPriyanga Ramasamy std::string getDbusNameForThisKw(const std::string& keyword)
10585629fbc0SPriyanga Ramasamy {
10595629fbc0SPriyanga Ramasamy     if (keyword[0] == constants::POUND_KW)
10605629fbc0SPriyanga Ramasamy     {
10615629fbc0SPriyanga Ramasamy         return (std::string(constants::POUND_KW_PREFIX) + keyword[1]);
10625629fbc0SPriyanga Ramasamy     }
10635629fbc0SPriyanga Ramasamy     else if (isdigit(keyword[0]))
10645629fbc0SPriyanga Ramasamy     {
10655629fbc0SPriyanga Ramasamy         return (std::string(constants::NUMERIC_KW_PREFIX) + keyword);
10665629fbc0SPriyanga Ramasamy     }
10675629fbc0SPriyanga Ramasamy     return keyword;
10685629fbc0SPriyanga Ramasamy }
10695629fbc0SPriyanga Ramasamy 
10706c71c9dcSSunny Srivastava } // namespace vpd
10716c71c9dcSSunny Srivastava } // namespace openpower
1072