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>
10c2fe40f8SPriyangaRamasamy #include <filesystem>
116c71c9dcSSunny Srivastava #include <fstream>
12735dee9bSAlpana Kumari #include <gpiod.hpp>
136c71c9dcSSunny Srivastava #include <iomanip>
146c71c9dcSSunny Srivastava #include <nlohmann/json.hpp>
156c71c9dcSSunny Srivastava #include <phosphor-logging/elog-errors.hpp>
166c71c9dcSSunny Srivastava #include <phosphor-logging/log.hpp>
17647868edSPriyangaRamasamy #include <regex>
186c71c9dcSSunny Srivastava #include <sdbusplus/server.hpp>
196c71c9dcSSunny Srivastava #include <sstream>
206c71c9dcSSunny Srivastava #include <vector>
216c71c9dcSSunny Srivastava #include <xyz/openbmc_project/Common/error.hpp>
226c71c9dcSSunny Srivastava 
236c71c9dcSSunny Srivastava using json = nlohmann::json;
246c71c9dcSSunny Srivastava 
256c71c9dcSSunny Srivastava namespace openpower
266c71c9dcSSunny Srivastava {
276c71c9dcSSunny Srivastava namespace vpd
286c71c9dcSSunny Srivastava {
296c71c9dcSSunny Srivastava using namespace openpower::vpd::constants;
306c71c9dcSSunny Srivastava using namespace inventory;
316c71c9dcSSunny Srivastava using namespace phosphor::logging;
326c71c9dcSSunny Srivastava using namespace sdbusplus::xyz::openbmc_project::Common::Error;
336c71c9dcSSunny Srivastava using namespace record;
346c71c9dcSSunny Srivastava using namespace openpower::vpd::exceptions;
356c71c9dcSSunny Srivastava using namespace common::utility;
360746eeebSSunny Srivastava using Severity = openpower::vpd::constants::PelSeverity;
37c2fe40f8SPriyangaRamasamy namespace fs = std::filesystem;
380746eeebSSunny Srivastava 
390746eeebSSunny Srivastava // mapping of severity enum to severity interface
400746eeebSSunny Srivastava static std::unordered_map<Severity, std::string> sevMap = {
410746eeebSSunny Srivastava     {Severity::INFORMATIONAL,
420746eeebSSunny Srivastava      "xyz.openbmc_project.Logging.Entry.Level.Informational"},
430746eeebSSunny Srivastava     {Severity::DEBUG, "xyz.openbmc_project.Logging.Entry.Level.Debug"},
440746eeebSSunny Srivastava     {Severity::NOTICE, "xyz.openbmc_project.Logging.Entry.Level.Notice"},
450746eeebSSunny Srivastava     {Severity::WARNING, "xyz.openbmc_project.Logging.Entry.Level.Warning"},
460746eeebSSunny Srivastava     {Severity::CRITICAL, "xyz.openbmc_project.Logging.Entry.Level.Critical"},
470746eeebSSunny Srivastava     {Severity::EMERGENCY, "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
480746eeebSSunny Srivastava     {Severity::ERROR, "xyz.openbmc_project.Logging.Entry.Level.Error"},
490746eeebSSunny Srivastava     {Severity::ALERT, "xyz.openbmc_project.Logging.Entry.Level.Alert"}};
500746eeebSSunny Srivastava 
516c71c9dcSSunny Srivastava namespace inventory
526c71c9dcSSunny Srivastava {
536c71c9dcSSunny Srivastava 
546c71c9dcSSunny Srivastava MapperResponse
556c71c9dcSSunny Srivastava     getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
566c71c9dcSSunny Srivastava                                   const std::vector<std::string>& interfaces)
576c71c9dcSSunny Srivastava {
586c71c9dcSSunny Srivastava     auto bus = sdbusplus::bus::new_default();
596c71c9dcSSunny Srivastava     auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath,
606c71c9dcSSunny Srivastava                                           mapperInterface, "GetSubTree");
616c71c9dcSSunny Srivastava     mapperCall.append(root);
626c71c9dcSSunny Srivastava     mapperCall.append(depth);
636c71c9dcSSunny Srivastava     mapperCall.append(interfaces);
646c71c9dcSSunny Srivastava 
656c71c9dcSSunny Srivastava     MapperResponse result = {};
666c71c9dcSSunny Srivastava 
676c71c9dcSSunny Srivastava     try
686c71c9dcSSunny Srivastava     {
696c71c9dcSSunny Srivastava         auto response = bus.call(mapperCall);
706c71c9dcSSunny Srivastava 
716c71c9dcSSunny Srivastava         response.read(result);
726c71c9dcSSunny Srivastava     }
73*2eb0176cSPatrick Williams     catch (const sdbusplus::exception_t& e)
746c71c9dcSSunny Srivastava     {
756c71c9dcSSunny Srivastava         log<level::ERR>("Error in mapper GetSubTree",
766c71c9dcSSunny Srivastava                         entry("ERROR=%s", e.what()));
776c71c9dcSSunny Srivastava     }
786c71c9dcSSunny Srivastava 
796c71c9dcSSunny Srivastava     return result;
806c71c9dcSSunny Srivastava }
816c71c9dcSSunny Srivastava 
826c71c9dcSSunny Srivastava } // namespace inventory
836c71c9dcSSunny Srivastava 
846c71c9dcSSunny Srivastava LE2ByteData readUInt16LE(Binary::const_iterator iterator)
856c71c9dcSSunny Srivastava {
866c71c9dcSSunny Srivastava     LE2ByteData lowByte = *iterator;
876c71c9dcSSunny Srivastava     LE2ByteData highByte = *(iterator + 1);
886c71c9dcSSunny Srivastava     lowByte |= (highByte << 8);
896c71c9dcSSunny Srivastava     return lowByte;
906c71c9dcSSunny Srivastava }
916c71c9dcSSunny Srivastava 
926c71c9dcSSunny Srivastava /** @brief Encodes a keyword for D-Bus.
936c71c9dcSSunny Srivastava  */
946c71c9dcSSunny Srivastava string encodeKeyword(const string& kw, const string& encoding)
956c71c9dcSSunny Srivastava {
966c71c9dcSSunny Srivastava     if (encoding == "MAC")
976c71c9dcSSunny Srivastava     {
986c71c9dcSSunny Srivastava         string res{};
996c71c9dcSSunny Srivastava         size_t first = kw[0];
1006c71c9dcSSunny Srivastava         res += toHex(first >> 4);
1016c71c9dcSSunny Srivastava         res += toHex(first & 0x0f);
1026c71c9dcSSunny Srivastava         for (size_t i = 1; i < kw.size(); ++i)
1036c71c9dcSSunny Srivastava         {
1046c71c9dcSSunny Srivastava             res += ":";
1056c71c9dcSSunny Srivastava             res += toHex(kw[i] >> 4);
1066c71c9dcSSunny Srivastava             res += toHex(kw[i] & 0x0f);
1076c71c9dcSSunny Srivastava         }
1086c71c9dcSSunny Srivastava         return res;
1096c71c9dcSSunny Srivastava     }
1106c71c9dcSSunny Srivastava     else if (encoding == "DATE")
1116c71c9dcSSunny Srivastava     {
1126c71c9dcSSunny Srivastava         // Date, represent as
1136c71c9dcSSunny Srivastava         // <year>-<month>-<day> <hour>:<min>
1146c71c9dcSSunny Srivastava         string res{};
1156c71c9dcSSunny Srivastava         static constexpr uint8_t skipPrefix = 3;
1166c71c9dcSSunny Srivastava 
1176c71c9dcSSunny Srivastava         auto strItr = kw.begin();
1186c71c9dcSSunny Srivastava         advance(strItr, skipPrefix);
1196c71c9dcSSunny Srivastava         for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
1206c71c9dcSSunny Srivastava 
1216c71c9dcSSunny Srivastava         res.insert(BD_YEAR_END, 1, '-');
1226c71c9dcSSunny Srivastava         res.insert(BD_MONTH_END, 1, '-');
1236c71c9dcSSunny Srivastava         res.insert(BD_DAY_END, 1, ' ');
1246c71c9dcSSunny Srivastava         res.insert(BD_HOUR_END, 1, ':');
1256c71c9dcSSunny Srivastava 
1266c71c9dcSSunny Srivastava         return res;
1276c71c9dcSSunny Srivastava     }
1286c71c9dcSSunny Srivastava     else // default to string encoding
1296c71c9dcSSunny Srivastava     {
1306c71c9dcSSunny Srivastava         return string(kw.begin(), kw.end());
1316c71c9dcSSunny Srivastava     }
1326c71c9dcSSunny Srivastava }
1336c71c9dcSSunny Srivastava 
1346c71c9dcSSunny Srivastava string readBusProperty(const string& obj, const string& inf, const string& prop)
1356c71c9dcSSunny Srivastava {
1366c71c9dcSSunny Srivastava     std::string propVal{};
1376c71c9dcSSunny Srivastava     std::string object = INVENTORY_PATH + obj;
1386c71c9dcSSunny Srivastava     auto bus = sdbusplus::bus::new_default();
1396c71c9dcSSunny Srivastava     auto properties = bus.new_method_call(
1406c71c9dcSSunny Srivastava         "xyz.openbmc_project.Inventory.Manager", object.c_str(),
1416c71c9dcSSunny Srivastava         "org.freedesktop.DBus.Properties", "Get");
1426c71c9dcSSunny Srivastava     properties.append(inf);
1436c71c9dcSSunny Srivastava     properties.append(prop);
1446c71c9dcSSunny Srivastava     auto result = bus.call(properties);
1456c71c9dcSSunny Srivastava     if (!result.is_method_error())
1466c71c9dcSSunny Srivastava     {
1476c71c9dcSSunny Srivastava         variant<Binary, string> val;
1486c71c9dcSSunny Srivastava         result.read(val);
1496c71c9dcSSunny Srivastava         if (auto pVal = get_if<Binary>(&val))
1506c71c9dcSSunny Srivastava         {
1516c71c9dcSSunny Srivastava             propVal.assign(reinterpret_cast<const char*>(pVal->data()),
1526c71c9dcSSunny Srivastava                            pVal->size());
1536c71c9dcSSunny Srivastava         }
1546c71c9dcSSunny Srivastava         else if (auto pVal = get_if<string>(&val))
1556c71c9dcSSunny Srivastava         {
1566c71c9dcSSunny Srivastava             propVal.assign(pVal->data(), pVal->size());
1576c71c9dcSSunny Srivastava         }
1586c71c9dcSSunny Srivastava     }
1596c71c9dcSSunny Srivastava     return propVal;
1606c71c9dcSSunny Srivastava }
1616c71c9dcSSunny Srivastava 
1626c71c9dcSSunny Srivastava void createPEL(const std::map<std::string, std::string>& additionalData,
1630746eeebSSunny Srivastava                const Severity& sev, const std::string& errIntf)
1646c71c9dcSSunny Srivastava {
1656c71c9dcSSunny Srivastava     try
1666c71c9dcSSunny Srivastava     {
1670746eeebSSunny Srivastava         std::string pelSeverity =
1680746eeebSSunny Srivastava             "xyz.openbmc_project.Logging.Entry.Level.Error";
1696c71c9dcSSunny Srivastava         auto bus = sdbusplus::bus::new_default();
1706c71c9dcSSunny Srivastava         auto service = getService(bus, loggerObjectPath, loggerCreateInterface);
1716c71c9dcSSunny Srivastava         auto method = bus.new_method_call(service.c_str(), loggerObjectPath,
1726c71c9dcSSunny Srivastava                                           loggerCreateInterface, "Create");
1736c71c9dcSSunny Srivastava 
1740746eeebSSunny Srivastava         auto itr = sevMap.find(sev);
1750746eeebSSunny Srivastava         if (itr != sevMap.end())
1760746eeebSSunny Srivastava         {
1770746eeebSSunny Srivastava             pelSeverity = itr->second;
1780746eeebSSunny Srivastava         }
1790746eeebSSunny Srivastava 
1800746eeebSSunny Srivastava         method.append(errIntf, pelSeverity, additionalData);
1816c71c9dcSSunny Srivastava         auto resp = bus.call(method);
1826c71c9dcSSunny Srivastava     }
183*2eb0176cSPatrick Williams     catch (const sdbusplus::exception_t& e)
1846c71c9dcSSunny Srivastava     {
1856c71c9dcSSunny Srivastava         throw std::runtime_error(
1866c71c9dcSSunny Srivastava             "Error in invoking D-Bus logging create interface to register PEL");
1876c71c9dcSSunny Srivastava     }
1886c71c9dcSSunny Srivastava }
1896c71c9dcSSunny Srivastava 
1906c71c9dcSSunny Srivastava inventory::VPDfilepath getVpdFilePath(const string& jsonFile,
1916c71c9dcSSunny Srivastava                                       const std::string& ObjPath)
1926c71c9dcSSunny Srivastava {
1936c71c9dcSSunny Srivastava     ifstream inventoryJson(jsonFile);
1946c71c9dcSSunny Srivastava     const auto& jsonObject = json::parse(inventoryJson);
1956c71c9dcSSunny Srivastava     inventory::VPDfilepath filePath{};
1966c71c9dcSSunny Srivastava 
1976c71c9dcSSunny Srivastava     if (jsonObject.find("frus") == jsonObject.end())
1986c71c9dcSSunny Srivastava     {
1996c71c9dcSSunny Srivastava         throw(VpdJsonException(
2006c71c9dcSSunny Srivastava             "Invalid JSON structure - frus{} object not found in ", jsonFile));
2016c71c9dcSSunny Srivastava     }
2026c71c9dcSSunny Srivastava 
2036c71c9dcSSunny Srivastava     const nlohmann::json& groupFRUS =
2046c71c9dcSSunny Srivastava         jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
2056c71c9dcSSunny Srivastava     for (const auto& itemFRUS : groupFRUS.items())
2066c71c9dcSSunny Srivastava     {
2076c71c9dcSSunny Srivastava         const std::vector<nlohmann::json>& groupEEPROM =
2086c71c9dcSSunny Srivastava             itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
2096c71c9dcSSunny Srivastava         for (const auto& itemEEPROM : groupEEPROM)
2106c71c9dcSSunny Srivastava         {
2116c71c9dcSSunny Srivastava             if (itemEEPROM["inventoryPath"]
2126c71c9dcSSunny Srivastava                     .get_ref<const nlohmann::json::string_t&>() == ObjPath)
2136c71c9dcSSunny Srivastava             {
2146c71c9dcSSunny Srivastava                 filePath = itemFRUS.key();
2156c71c9dcSSunny Srivastava                 return filePath;
2166c71c9dcSSunny Srivastava             }
2176c71c9dcSSunny Srivastava         }
2186c71c9dcSSunny Srivastava     }
2196c71c9dcSSunny Srivastava 
2206c71c9dcSSunny Srivastava     return filePath;
2216c71c9dcSSunny Srivastava }
2226c71c9dcSSunny Srivastava 
2236c71c9dcSSunny Srivastava bool isPathInJson(const std::string& eepromPath)
2246c71c9dcSSunny Srivastava {
2256c71c9dcSSunny Srivastava     bool present = false;
2266c71c9dcSSunny Srivastava     ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
2276c71c9dcSSunny Srivastava 
2286c71c9dcSSunny Srivastava     try
2296c71c9dcSSunny Srivastava     {
2306c71c9dcSSunny Srivastava         auto js = json::parse(inventoryJson);
2316c71c9dcSSunny Srivastava         if (js.find("frus") == js.end())
2326c71c9dcSSunny Srivastava         {
2336c71c9dcSSunny Srivastava             throw(VpdJsonException(
2346c71c9dcSSunny Srivastava                 "Invalid JSON structure - frus{} object not found in ",
2356c71c9dcSSunny Srivastava                 INVENTORY_JSON_SYM_LINK));
2366c71c9dcSSunny Srivastava         }
2376c71c9dcSSunny Srivastava         json fruJson = js["frus"];
2386c71c9dcSSunny Srivastava 
2396c71c9dcSSunny Srivastava         if (fruJson.find(eepromPath) != fruJson.end())
2406c71c9dcSSunny Srivastava         {
2416c71c9dcSSunny Srivastava             present = true;
2426c71c9dcSSunny Srivastava         }
2436c71c9dcSSunny Srivastava     }
2448e15b93aSPatrick Williams     catch (const json::parse_error& ex)
2456c71c9dcSSunny Srivastava     {
2466c71c9dcSSunny Srivastava         throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
2476c71c9dcSSunny Srivastava     }
2486c71c9dcSSunny Srivastava     return present;
2496c71c9dcSSunny Srivastava }
2506c71c9dcSSunny Srivastava 
2516c71c9dcSSunny Srivastava bool isRecKwInDbusJson(const std::string& recordName,
2526c71c9dcSSunny Srivastava                        const std::string& keyword)
2536c71c9dcSSunny Srivastava {
2546c71c9dcSSunny Srivastava     ifstream propertyJson(DBUS_PROP_JSON);
2556c71c9dcSSunny Srivastava     json dbusProperty;
2566c71c9dcSSunny Srivastava     bool present = false;
2576c71c9dcSSunny Srivastava 
2586c71c9dcSSunny Srivastava     if (propertyJson.is_open())
2596c71c9dcSSunny Srivastava     {
2606c71c9dcSSunny Srivastava         try
2616c71c9dcSSunny Srivastava         {
2626c71c9dcSSunny Srivastava             auto dbusPropertyJson = json::parse(propertyJson);
2636c71c9dcSSunny Srivastava             if (dbusPropertyJson.find("dbusProperties") ==
2646c71c9dcSSunny Srivastava                 dbusPropertyJson.end())
2656c71c9dcSSunny Srivastava             {
2666c71c9dcSSunny Srivastava                 throw(VpdJsonException("dbusProperties{} object not found in "
2676c71c9dcSSunny Srivastava                                        "DbusProperties json : ",
2686c71c9dcSSunny Srivastava                                        DBUS_PROP_JSON));
2696c71c9dcSSunny Srivastava             }
2706c71c9dcSSunny Srivastava 
2716c71c9dcSSunny Srivastava             dbusProperty = dbusPropertyJson["dbusProperties"];
2726c71c9dcSSunny Srivastava             if (dbusProperty.contains(recordName))
2736c71c9dcSSunny Srivastava             {
2746c71c9dcSSunny Srivastava                 const vector<string>& kwdsToPublish = dbusProperty[recordName];
2756c71c9dcSSunny Srivastava                 if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
2766c71c9dcSSunny Srivastava                     kwdsToPublish.end()) // present
2776c71c9dcSSunny Srivastava                 {
2786c71c9dcSSunny Srivastava                     present = true;
2796c71c9dcSSunny Srivastava                 }
2806c71c9dcSSunny Srivastava             }
2816c71c9dcSSunny Srivastava         }
2828e15b93aSPatrick Williams         catch (const json::parse_error& ex)
2836c71c9dcSSunny Srivastava         {
2846c71c9dcSSunny Srivastava             throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
2856c71c9dcSSunny Srivastava         }
2866c71c9dcSSunny Srivastava     }
2876c71c9dcSSunny Srivastava     else
2886c71c9dcSSunny Srivastava     {
2896c71c9dcSSunny Srivastava         // If dbus properties json is not available, we assume the given
2906c71c9dcSSunny Srivastava         // record-keyword is part of dbus-properties json. So setting the bool
2916c71c9dcSSunny Srivastava         // variable to true.
2926c71c9dcSSunny Srivastava         present = true;
2936c71c9dcSSunny Srivastava     }
2946c71c9dcSSunny Srivastava     return present;
2956c71c9dcSSunny Srivastava }
2966c71c9dcSSunny Srivastava 
2976c71c9dcSSunny Srivastava vpdType vpdTypeCheck(const Binary& vpdVector)
2986c71c9dcSSunny Srivastava {
2996c71c9dcSSunny Srivastava     // Read first 3 Bytes to check the 11S bar code format
3006c71c9dcSSunny Srivastava     std::string is11SFormat = "";
3016c71c9dcSSunny Srivastava     for (uint8_t i = 0; i < FORMAT_11S_LEN; i++)
3026c71c9dcSSunny Srivastava     {
3036c71c9dcSSunny Srivastava         is11SFormat += vpdVector[MEMORY_VPD_DATA_START + i];
3046c71c9dcSSunny Srivastava     }
3056c71c9dcSSunny Srivastava 
3066c71c9dcSSunny Srivastava     if (vpdVector[IPZ_DATA_START] == KW_VAL_PAIR_START_TAG)
3076c71c9dcSSunny Srivastava     {
3086c71c9dcSSunny Srivastava         // IPZ VPD FORMAT
3096c71c9dcSSunny Srivastava         return vpdType::IPZ_VPD;
3106c71c9dcSSunny Srivastava     }
3116c71c9dcSSunny Srivastava     else if (vpdVector[KW_VPD_DATA_START] == KW_VPD_START_TAG)
3126c71c9dcSSunny Srivastava     {
3136c71c9dcSSunny Srivastava         // KEYWORD VPD FORMAT
3146c71c9dcSSunny Srivastava         return vpdType::KEYWORD_VPD;
3156c71c9dcSSunny Srivastava     }
3166c71c9dcSSunny Srivastava     else if (is11SFormat.compare(MEMORY_VPD_START_TAG) == 0)
3176c71c9dcSSunny Srivastava     {
3186c71c9dcSSunny Srivastava         // Memory VPD format
3196c71c9dcSSunny Srivastava         return vpdType::MEMORY_VPD;
3206c71c9dcSSunny Srivastava     }
3216c71c9dcSSunny Srivastava 
3226c71c9dcSSunny Srivastava     // INVALID VPD FORMAT
3236c71c9dcSSunny Srivastava     return vpdType::INVALID_VPD_FORMAT;
3246c71c9dcSSunny Srivastava }
3256c71c9dcSSunny Srivastava 
326f05effdbSAlpana Kumari const string getIM(const Parsed& vpdMap)
327f05effdbSAlpana Kumari {
328f05effdbSAlpana Kumari     Binary imVal;
329f05effdbSAlpana Kumari     auto property = vpdMap.find("VSBP");
330f05effdbSAlpana Kumari     if (property != vpdMap.end())
331f05effdbSAlpana Kumari     {
332f05effdbSAlpana Kumari         auto kw = (property->second).find("IM");
333f05effdbSAlpana Kumari         if (kw != (property->second).end())
334f05effdbSAlpana Kumari         {
335f05effdbSAlpana Kumari             copy(kw->second.begin(), kw->second.end(), back_inserter(imVal));
336f05effdbSAlpana Kumari         }
337f05effdbSAlpana Kumari     }
338f05effdbSAlpana Kumari 
339f05effdbSAlpana Kumari     ostringstream oss;
340f05effdbSAlpana Kumari     for (auto& i : imVal)
341f05effdbSAlpana Kumari     {
342f05effdbSAlpana Kumari         oss << setw(2) << setfill('0') << hex << static_cast<int>(i);
343f05effdbSAlpana Kumari     }
344f05effdbSAlpana Kumari 
345f05effdbSAlpana Kumari     return oss.str();
346f05effdbSAlpana Kumari }
347f05effdbSAlpana Kumari 
348f05effdbSAlpana Kumari const string getHW(const Parsed& vpdMap)
349f05effdbSAlpana Kumari {
350f05effdbSAlpana Kumari     Binary hwVal;
351f05effdbSAlpana Kumari     auto prop = vpdMap.find("VINI");
352f05effdbSAlpana Kumari     if (prop != vpdMap.end())
353f05effdbSAlpana Kumari     {
354f05effdbSAlpana Kumari         auto kw = (prop->second).find("HW");
355f05effdbSAlpana Kumari         if (kw != (prop->second).end())
356f05effdbSAlpana Kumari         {
357f05effdbSAlpana Kumari             copy(kw->second.begin(), kw->second.end(), back_inserter(hwVal));
358f05effdbSAlpana Kumari         }
359f05effdbSAlpana Kumari     }
360f05effdbSAlpana Kumari 
36188d2ae82SAlpana Kumari     // The planar pass only comes from the LSB of the HW keyword,
36288d2ae82SAlpana Kumari     // where as the MSB is used for other purposes such as signifying clock
36388d2ae82SAlpana Kumari     // termination.
36488d2ae82SAlpana Kumari     hwVal[0] = 0x00;
36588d2ae82SAlpana Kumari 
366f05effdbSAlpana Kumari     ostringstream hwString;
367f05effdbSAlpana Kumari     for (auto& i : hwVal)
368f05effdbSAlpana Kumari     {
369f05effdbSAlpana Kumari         hwString << setw(2) << setfill('0') << hex << static_cast<int>(i);
370f05effdbSAlpana Kumari     }
371f05effdbSAlpana Kumari 
372f05effdbSAlpana Kumari     return hwString.str();
373f05effdbSAlpana Kumari }
374f05effdbSAlpana Kumari 
375f05effdbSAlpana Kumari string getSystemsJson(const Parsed& vpdMap)
376f05effdbSAlpana Kumari {
377f05effdbSAlpana Kumari     string jsonPath = "/usr/share/vpd/";
378f05effdbSAlpana Kumari     string jsonName{};
379f05effdbSAlpana Kumari 
380f05effdbSAlpana Kumari     ifstream systemJson(SYSTEM_JSON);
381f05effdbSAlpana Kumari     if (!systemJson)
382f05effdbSAlpana Kumari     {
383f05effdbSAlpana Kumari         throw((VpdJsonException("Failed to access Json path", SYSTEM_JSON)));
384f05effdbSAlpana Kumari     }
385f05effdbSAlpana Kumari 
386f05effdbSAlpana Kumari     try
387f05effdbSAlpana Kumari     {
388f05effdbSAlpana Kumari         auto js = json::parse(systemJson);
389f05effdbSAlpana Kumari 
3901b026119SAlpana Kumari         string hwKeyword = getHW(vpdMap);
391f05effdbSAlpana Kumari         const string imKeyword = getIM(vpdMap);
392f05effdbSAlpana Kumari 
3931b026119SAlpana Kumari         transform(hwKeyword.begin(), hwKeyword.end(), hwKeyword.begin(),
3941b026119SAlpana Kumari                   ::toupper);
3951b026119SAlpana Kumari 
396f05effdbSAlpana Kumari         if (js.find("system") == js.end())
397f05effdbSAlpana Kumari         {
398f05effdbSAlpana Kumari             throw runtime_error("Invalid systems Json");
399f05effdbSAlpana Kumari         }
400f05effdbSAlpana Kumari 
401f05effdbSAlpana Kumari         if (js["system"].find(imKeyword) == js["system"].end())
402f05effdbSAlpana Kumari         {
403f05effdbSAlpana Kumari             throw runtime_error(
404f05effdbSAlpana Kumari                 "Invalid system. This system type is not present "
405f05effdbSAlpana Kumari                 "in the systemsJson. IM: " +
406f05effdbSAlpana Kumari                 imKeyword);
407f05effdbSAlpana Kumari         }
408f05effdbSAlpana Kumari 
409f05effdbSAlpana Kumari         if ((js["system"][imKeyword].find("constraint") !=
410f05effdbSAlpana Kumari              js["system"][imKeyword].end()) &&
4111b026119SAlpana Kumari             js["system"][imKeyword]["constraint"].find("HW") !=
4121b026119SAlpana Kumari                 js["system"][imKeyword]["constraint"].end())
4131b026119SAlpana Kumari         {
4141b026119SAlpana Kumari             // collect hw versions from json, and check hwKeyword  is part of it
4151b026119SAlpana Kumari             // if hwKeyword is found there then load respective json
4161b026119SAlpana Kumari             // otherwise load default one.
4171b026119SAlpana Kumari             for (const auto& hwVersion :
4181b026119SAlpana Kumari                  js["system"][imKeyword]["constraint"]["HW"])
4191b026119SAlpana Kumari             {
4201b026119SAlpana Kumari                 string hw = hwVersion;
4211b026119SAlpana Kumari                 transform(hw.begin(), hw.end(), hw.begin(), ::toupper);
4221b026119SAlpana Kumari 
4231b026119SAlpana Kumari                 if (hw == hwKeyword)
424f05effdbSAlpana Kumari                 {
425f05effdbSAlpana Kumari                     jsonName = js["system"][imKeyword]["constraint"]["json"];
4261b026119SAlpana Kumari                     break;
4271b026119SAlpana Kumari                 }
4281b026119SAlpana Kumari             }
4291b026119SAlpana Kumari 
4301b026119SAlpana Kumari             if (jsonName.empty() && js["system"][imKeyword].find("default") !=
4311b026119SAlpana Kumari                                         js["system"][imKeyword].end())
4321b026119SAlpana Kumari             {
4331b026119SAlpana Kumari                 jsonName = js["system"][imKeyword]["default"];
4341b026119SAlpana Kumari             }
435f05effdbSAlpana Kumari         }
436f05effdbSAlpana Kumari         else if (js["system"][imKeyword].find("default") !=
437f05effdbSAlpana Kumari                  js["system"][imKeyword].end())
438f05effdbSAlpana Kumari         {
439f05effdbSAlpana Kumari             jsonName = js["system"][imKeyword]["default"];
440f05effdbSAlpana Kumari         }
441f05effdbSAlpana Kumari         else
442f05effdbSAlpana Kumari         {
443f05effdbSAlpana Kumari             throw runtime_error(
444f05effdbSAlpana Kumari                 "Bad System json. Neither constraint nor default found");
445f05effdbSAlpana Kumari         }
446f05effdbSAlpana Kumari 
447f05effdbSAlpana Kumari         jsonPath += jsonName;
448f05effdbSAlpana Kumari     }
449f05effdbSAlpana Kumari 
4508e15b93aSPatrick Williams     catch (const json::parse_error& ex)
451f05effdbSAlpana Kumari     {
452f05effdbSAlpana Kumari         throw(VpdJsonException("Json Parsing failed", SYSTEM_JSON));
453f05effdbSAlpana Kumari     }
454f05effdbSAlpana Kumari     return jsonPath;
455f05effdbSAlpana Kumari }
456f05effdbSAlpana Kumari 
457647868edSPriyangaRamasamy void udevToGenericPath(string& file)
458647868edSPriyangaRamasamy {
459647868edSPriyangaRamasamy     // Sample udevEvent i2c path :
460647868edSPriyangaRamasamy     // "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem"
461647868edSPriyangaRamasamy     // find if the path contains the word i2c in it.
462647868edSPriyangaRamasamy     if (file.find("i2c") != string::npos)
463647868edSPriyangaRamasamy     {
464647868edSPriyangaRamasamy         string i2cBusAddr{};
465647868edSPriyangaRamasamy 
466647868edSPriyangaRamasamy         // Every udev i2c path should have the common pattern
467647868edSPriyangaRamasamy         // "i2c-bus_number/bus_number-vpd_address". Search for
468647868edSPriyangaRamasamy         // "bus_number-vpd_address".
469647868edSPriyangaRamasamy         regex i2cPattern("((i2c)-[0-9]+\\/)([0-9]+-[0-9]{4})");
470647868edSPriyangaRamasamy         smatch match;
471647868edSPriyangaRamasamy         if (regex_search(file, match, i2cPattern))
472647868edSPriyangaRamasamy         {
473647868edSPriyangaRamasamy             i2cBusAddr = match.str(3);
474647868edSPriyangaRamasamy         }
475647868edSPriyangaRamasamy         else
476647868edSPriyangaRamasamy         {
477647868edSPriyangaRamasamy             cerr << "The given udev path < " << file
478647868edSPriyangaRamasamy                  << " > doesn't match the required pattern. Skipping VPD "
479647868edSPriyangaRamasamy                     "collection."
480647868edSPriyangaRamasamy                  << endl;
481647868edSPriyangaRamasamy             exit(EXIT_SUCCESS);
482647868edSPriyangaRamasamy         }
483647868edSPriyangaRamasamy         // Forming the generic file path
484647868edSPriyangaRamasamy         file = i2cPathPrefix + i2cBusAddr + "/eeprom";
485647868edSPriyangaRamasamy     }
486647868edSPriyangaRamasamy     // Sample udevEvent spi path :
487647868edSPriyangaRamasamy     // "/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"
488647868edSPriyangaRamasamy     // find if the path contains the word spi in it.
489647868edSPriyangaRamasamy     else if (file.find("spi") != string::npos)
490647868edSPriyangaRamasamy     {
491647868edSPriyangaRamasamy         // Every udev spi path will have common pattern "spi<Digit>/", which
492647868edSPriyangaRamasamy         // describes the spi bus number at which the fru is connected; Followed
493647868edSPriyangaRamasamy         // by a slash following the vpd address of the fru. Taking the above
494647868edSPriyangaRamasamy         // input as a common key, we try to search for the pattern "spi<Digit>/"
495647868edSPriyangaRamasamy         // using regular expression.
496647868edSPriyangaRamasamy         regex spiPattern("((spi)[0-9]+)(\\/)");
497647868edSPriyangaRamasamy         string spiBus{};
498647868edSPriyangaRamasamy         smatch match;
499647868edSPriyangaRamasamy         if (regex_search(file, match, spiPattern))
500647868edSPriyangaRamasamy         {
501647868edSPriyangaRamasamy             spiBus = match.str(1);
502647868edSPriyangaRamasamy         }
503647868edSPriyangaRamasamy         else
504647868edSPriyangaRamasamy         {
505647868edSPriyangaRamasamy             cerr << "The given udev path < " << file
506647868edSPriyangaRamasamy                  << " > doesn't match the required pattern. Skipping VPD "
507647868edSPriyangaRamasamy                     "collection."
508647868edSPriyangaRamasamy                  << endl;
509647868edSPriyangaRamasamy             exit(EXIT_SUCCESS);
510647868edSPriyangaRamasamy         }
511647868edSPriyangaRamasamy         // Forming the generic path
512647868edSPriyangaRamasamy         file = spiPathPrefix + spiBus + ".0/eeprom";
513647868edSPriyangaRamasamy     }
514647868edSPriyangaRamasamy     else
515647868edSPriyangaRamasamy     {
516647868edSPriyangaRamasamy         cerr << "\n The given EEPROM path < " << file
517647868edSPriyangaRamasamy              << " > is not valid. It's neither I2C nor "
518647868edSPriyangaRamasamy                 "SPI path. Skipping VPD collection.."
519647868edSPriyangaRamasamy              << endl;
520647868edSPriyangaRamasamy         exit(EXIT_SUCCESS);
521647868edSPriyangaRamasamy     }
522647868edSPriyangaRamasamy }
523c2fe40f8SPriyangaRamasamy string getBadVpdName(const string& file)
524c2fe40f8SPriyangaRamasamy {
525c2fe40f8SPriyangaRamasamy     string badVpd = BAD_VPD_DIR;
526c2fe40f8SPriyangaRamasamy     if (file.find("i2c") != string::npos)
527c2fe40f8SPriyangaRamasamy     {
528c2fe40f8SPriyangaRamasamy         badVpd += "i2c-";
529c2fe40f8SPriyangaRamasamy         regex i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
530c2fe40f8SPriyangaRamasamy         smatch match;
531c2fe40f8SPriyangaRamasamy         if (regex_search(file, match, i2cPattern))
532c2fe40f8SPriyangaRamasamy         {
533c2fe40f8SPriyangaRamasamy             badVpd += match.str(2);
534c2fe40f8SPriyangaRamasamy         }
535c2fe40f8SPriyangaRamasamy     }
536c2fe40f8SPriyangaRamasamy     else if (file.find("spi") != string::npos)
537c2fe40f8SPriyangaRamasamy     {
538c2fe40f8SPriyangaRamasamy         regex spiPattern("((spi)[0-9]+)(.0)");
539c2fe40f8SPriyangaRamasamy         smatch match;
540c2fe40f8SPriyangaRamasamy         if (regex_search(file, match, spiPattern))
541c2fe40f8SPriyangaRamasamy         {
542c2fe40f8SPriyangaRamasamy             badVpd += match.str(1);
543c2fe40f8SPriyangaRamasamy         }
544c2fe40f8SPriyangaRamasamy     }
545c2fe40f8SPriyangaRamasamy     return badVpd;
546c2fe40f8SPriyangaRamasamy }
547c2fe40f8SPriyangaRamasamy 
548c2fe40f8SPriyangaRamasamy void dumpBadVpd(const string& file, const Binary& vpdVector)
549c2fe40f8SPriyangaRamasamy {
550c2fe40f8SPriyangaRamasamy     fs::path badVpdDir = BAD_VPD_DIR;
551c2fe40f8SPriyangaRamasamy     fs::create_directory(badVpdDir);
552c2fe40f8SPriyangaRamasamy     string badVpdPath = getBadVpdName(file);
553c2fe40f8SPriyangaRamasamy     if (fs::exists(badVpdPath))
554c2fe40f8SPriyangaRamasamy     {
555c2fe40f8SPriyangaRamasamy         std::error_code ec;
556c2fe40f8SPriyangaRamasamy         fs::remove(badVpdPath, ec);
557c2fe40f8SPriyangaRamasamy         if (ec) // error code
558c2fe40f8SPriyangaRamasamy         {
559c2fe40f8SPriyangaRamasamy             string error = "Error removing the existing broken vpd in ";
560c2fe40f8SPriyangaRamasamy             error += badVpdPath;
561c2fe40f8SPriyangaRamasamy             error += ". Error code : ";
562c2fe40f8SPriyangaRamasamy             error += ec.value();
563c2fe40f8SPriyangaRamasamy             error += ". Error message : ";
564c2fe40f8SPriyangaRamasamy             error += ec.message();
565c2fe40f8SPriyangaRamasamy             throw runtime_error(error);
566c2fe40f8SPriyangaRamasamy         }
567c2fe40f8SPriyangaRamasamy     }
568c2fe40f8SPriyangaRamasamy     ofstream badVpdFileStream(badVpdPath, ofstream::binary);
569c2fe40f8SPriyangaRamasamy     if (!badVpdFileStream)
570c2fe40f8SPriyangaRamasamy     {
571c2fe40f8SPriyangaRamasamy         throw runtime_error("Failed to open bad vpd file path in /tmp/bad-vpd. "
572c2fe40f8SPriyangaRamasamy                             "Unable to dump the broken/bad vpd file.");
573c2fe40f8SPriyangaRamasamy     }
574c2fe40f8SPriyangaRamasamy     badVpdFileStream.write(reinterpret_cast<const char*>(vpdVector.data()),
575c2fe40f8SPriyangaRamasamy                            vpdVector.size());
576c2fe40f8SPriyangaRamasamy }
5777ce68724Salpana07 
5787ce68724Salpana07 const string getKwVal(const Parsed& vpdMap, const string& rec,
5797ce68724Salpana07                       const string& kwd)
5807ce68724Salpana07 {
5817ce68724Salpana07     string kwVal{};
5827ce68724Salpana07 
5837ce68724Salpana07     auto findRec = vpdMap.find(rec);
5847ce68724Salpana07 
5857ce68724Salpana07     // check if record is found in map we got by parser
5867ce68724Salpana07     if (findRec != vpdMap.end())
5877ce68724Salpana07     {
5887ce68724Salpana07         auto findKwd = findRec->second.find(kwd);
5897ce68724Salpana07 
5907ce68724Salpana07         if (findKwd != findRec->second.end())
5917ce68724Salpana07         {
5927ce68724Salpana07             kwVal = findKwd->second;
5937ce68724Salpana07         }
5947ce68724Salpana07     }
5957ce68724Salpana07 
5967ce68724Salpana07     return kwVal;
5977ce68724Salpana07 }
5987ce68724Salpana07 
599c9ecf8eaSPriyanga Ramasamy string byteArrayToHexString(const Binary& vec)
60002434931SPriyanga Ramasamy {
60102434931SPriyanga Ramasamy     stringstream ss;
60202434931SPriyanga Ramasamy     string hexRep = "0x";
60302434931SPriyanga Ramasamy     ss << hexRep;
604c9ecf8eaSPriyanga Ramasamy     string str = ss.str();
60502434931SPriyanga Ramasamy 
606c9ecf8eaSPriyanga Ramasamy     // convert Decimal to Hex string
60702434931SPriyanga Ramasamy     for (auto& v : vec)
60802434931SPriyanga Ramasamy     {
60902434931SPriyanga Ramasamy         ss << setfill('0') << setw(2) << hex << (int)v;
61002434931SPriyanga Ramasamy         str = ss.str();
61102434931SPriyanga Ramasamy     }
612c9ecf8eaSPriyanga Ramasamy     return str;
613c9ecf8eaSPriyanga Ramasamy }
614c9ecf8eaSPriyanga Ramasamy 
615c9ecf8eaSPriyanga Ramasamy string getPrintableValue(const Binary& vec)
616c9ecf8eaSPriyanga Ramasamy {
617c9ecf8eaSPriyanga Ramasamy     string str{};
618c9ecf8eaSPriyanga Ramasamy 
619c9ecf8eaSPriyanga Ramasamy     // find for a non printable value in the vector
620c9ecf8eaSPriyanga Ramasamy     const auto it = std::find_if(vec.begin(), vec.end(),
621c9ecf8eaSPriyanga Ramasamy                                  [](const auto& ele) { return !isprint(ele); });
622c9ecf8eaSPriyanga Ramasamy 
623c9ecf8eaSPriyanga Ramasamy     if (it != vec.end()) // if the given vector has any non printable value
624c9ecf8eaSPriyanga Ramasamy     {
625c9ecf8eaSPriyanga Ramasamy         for (auto itr = it; itr != vec.end(); itr++)
626c9ecf8eaSPriyanga Ramasamy         {
627c9ecf8eaSPriyanga Ramasamy             if (*itr != 0x00)
628c9ecf8eaSPriyanga Ramasamy             {
629c9ecf8eaSPriyanga Ramasamy                 str = byteArrayToHexString(vec);
630c9ecf8eaSPriyanga Ramasamy                 return str;
631c9ecf8eaSPriyanga Ramasamy             }
632c9ecf8eaSPriyanga Ramasamy         }
633c9ecf8eaSPriyanga Ramasamy         str = string(vec.begin(), it);
63402434931SPriyanga Ramasamy     }
63502434931SPriyanga Ramasamy     else
63602434931SPriyanga Ramasamy     {
63702434931SPriyanga Ramasamy         str = string(vec.begin(), vec.end());
63802434931SPriyanga Ramasamy     }
63902434931SPriyanga Ramasamy     return str;
64002434931SPriyanga Ramasamy }
64102434931SPriyanga Ramasamy 
6426bd095f9SAlpana Kumari /*
6436bd095f9SAlpana Kumari  * @brief Log PEL for GPIO exception
6446bd095f9SAlpana Kumari  *
6456bd095f9SAlpana Kumari  * @param[in] gpioErr gpioError type exception
6466bd095f9SAlpana Kumari  * @param[in] i2cBusAddr I2C bus and address
6476bd095f9SAlpana Kumari  */
6486bd095f9SAlpana Kumari void logGpioPel(const string& gpioErr, const string& i2cBusAddr)
6496bd095f9SAlpana Kumari {
6506bd095f9SAlpana Kumari     // Get the IIC details
6516bd095f9SAlpana Kumari     vector<string> i2cReg;
6526bd095f9SAlpana Kumari     boost::split(i2cReg, i2cBusAddr, boost::is_any_of("-"));
6536bd095f9SAlpana Kumari 
6546bd095f9SAlpana Kumari     PelAdditionalData additionalData{};
6556bd095f9SAlpana Kumari     if (i2cReg.size() == 2)
6566bd095f9SAlpana Kumari     {
6576bd095f9SAlpana Kumari         additionalData.emplace("CALLOUT_IIC_BUS", i2cReg[0]);
6586bd095f9SAlpana Kumari         additionalData.emplace("CALLOUT_IIC_ADDR", "0x" + i2cReg[1]);
6596bd095f9SAlpana Kumari     }
6606bd095f9SAlpana Kumari 
6616bd095f9SAlpana Kumari     additionalData.emplace("DESCRIPTION", gpioErr);
6626bd095f9SAlpana Kumari     createPEL(additionalData, PelSeverity::WARNING, errIntfForGpioError);
6636bd095f9SAlpana Kumari }
6646bd095f9SAlpana Kumari 
665735dee9bSAlpana Kumari void executePostFailAction(const nlohmann::json& json, const string& file)
666735dee9bSAlpana Kumari {
667735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("postActionFail") ==
668735dee9bSAlpana Kumari         json["frus"][file].at(0).end())
669735dee9bSAlpana Kumari     {
670735dee9bSAlpana Kumari         return;
671735dee9bSAlpana Kumari     }
672735dee9bSAlpana Kumari 
673735dee9bSAlpana Kumari     uint8_t pinValue = 0;
674735dee9bSAlpana Kumari     string pinName;
675735dee9bSAlpana Kumari 
676735dee9bSAlpana Kumari     for (const auto& postAction :
677735dee9bSAlpana Kumari          (json["frus"][file].at(0))["postActionFail"].items())
678735dee9bSAlpana Kumari     {
679735dee9bSAlpana Kumari         if (postAction.key() == "pin")
680735dee9bSAlpana Kumari         {
681735dee9bSAlpana Kumari             pinName = postAction.value();
682735dee9bSAlpana Kumari         }
683735dee9bSAlpana Kumari         else if (postAction.key() == "value")
684735dee9bSAlpana Kumari         {
685735dee9bSAlpana Kumari             // Get the value to set
686735dee9bSAlpana Kumari             pinValue = postAction.value();
687735dee9bSAlpana Kumari         }
688735dee9bSAlpana Kumari     }
689735dee9bSAlpana Kumari 
690735dee9bSAlpana Kumari     cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl;
691735dee9bSAlpana Kumari 
692735dee9bSAlpana Kumari     try
693735dee9bSAlpana Kumari     {
694735dee9bSAlpana Kumari         gpiod::line outputLine = gpiod::find_line(pinName);
695735dee9bSAlpana Kumari 
696735dee9bSAlpana Kumari         if (!outputLine)
697735dee9bSAlpana Kumari         {
6986bd095f9SAlpana Kumari             throw runtime_error(
6996bd095f9SAlpana Kumari                 "Couldn't find output line for the GPIO. Skipping "
7006bd095f9SAlpana Kumari                 "this GPIO action.");
701735dee9bSAlpana Kumari         }
702735dee9bSAlpana Kumari         outputLine.request(
703735dee9bSAlpana Kumari             {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
704735dee9bSAlpana Kumari             pinValue);
705735dee9bSAlpana Kumari     }
7066bd095f9SAlpana Kumari     catch (const exception& e)
707735dee9bSAlpana Kumari     {
7086bd095f9SAlpana Kumari         string i2cBusAddr;
7096bd095f9SAlpana Kumari         string errMsg = e.what();
7106bd095f9SAlpana Kumari         errMsg += "\nGPIO: " + pinName;
7116bd095f9SAlpana Kumari 
7126bd095f9SAlpana Kumari         if ((json["frus"][file].at(0)["postActionFail"].find(
7136bd095f9SAlpana Kumari                 "gpioI2CAddress")) !=
7146bd095f9SAlpana Kumari             json["frus"][file].at(0)["postActionFail"].end())
7156bd095f9SAlpana Kumari         {
7166bd095f9SAlpana Kumari             i2cBusAddr =
7176bd095f9SAlpana Kumari                 json["frus"][file].at(0)["postActionFail"]["gpioI2CAddress"];
718735dee9bSAlpana Kumari         }
7196bd095f9SAlpana Kumari 
7206bd095f9SAlpana Kumari         logGpioPel(errMsg, i2cBusAddr);
7216bd095f9SAlpana Kumari     }
7226bd095f9SAlpana Kumari 
7236bd095f9SAlpana Kumari     return;
724735dee9bSAlpana Kumari }
725735dee9bSAlpana Kumari 
72653b38ed0SSantosh Puranik std::optional<bool> isPresent(const nlohmann::json& json, const string& file)
72753b38ed0SSantosh Puranik 
728735dee9bSAlpana Kumari {
729735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("presence") !=
730735dee9bSAlpana Kumari         json["frus"][file].at(0).end())
731735dee9bSAlpana Kumari     {
732735dee9bSAlpana Kumari         if (((json["frus"][file].at(0)["presence"]).find("pin") !=
733735dee9bSAlpana Kumari              json["frus"][file].at(0)["presence"].end()) &&
734735dee9bSAlpana Kumari             ((json["frus"][file].at(0)["presence"]).find("value") !=
735735dee9bSAlpana Kumari              json["frus"][file].at(0)["presence"].end()))
736735dee9bSAlpana Kumari         {
737735dee9bSAlpana Kumari             string presPinName = json["frus"][file].at(0)["presence"]["pin"];
738735dee9bSAlpana Kumari             Byte presPinValue = json["frus"][file].at(0)["presence"]["value"];
739735dee9bSAlpana Kumari 
740735dee9bSAlpana Kumari             try
741735dee9bSAlpana Kumari             {
742735dee9bSAlpana Kumari                 gpiod::line presenceLine = gpiod::find_line(presPinName);
743735dee9bSAlpana Kumari 
744735dee9bSAlpana Kumari                 if (!presenceLine)
745735dee9bSAlpana Kumari                 {
74640d1c196SAlpana Kumari                     cerr << "Couldn't find the presence line for - "
74740d1c196SAlpana Kumari                          << presPinName << endl;
74840d1c196SAlpana Kumari 
7496bd095f9SAlpana Kumari                     throw runtime_error(
7506bd095f9SAlpana Kumari                         "Couldn't find the presence line for the "
7516bd095f9SAlpana Kumari                         "GPIO. Skipping this GPIO action.");
752735dee9bSAlpana Kumari                 }
753735dee9bSAlpana Kumari 
754735dee9bSAlpana Kumari                 presenceLine.request({"Read the presence line",
755735dee9bSAlpana Kumari                                       gpiod::line_request::DIRECTION_INPUT, 0});
756735dee9bSAlpana Kumari 
757735dee9bSAlpana Kumari                 Byte gpioData = presenceLine.get_value();
758735dee9bSAlpana Kumari 
75953b38ed0SSantosh Puranik                 return (gpioData == presPinValue);
760735dee9bSAlpana Kumari             }
7616bd095f9SAlpana Kumari             catch (const exception& e)
762735dee9bSAlpana Kumari             {
7636bd095f9SAlpana Kumari                 string i2cBusAddr;
7646bd095f9SAlpana Kumari                 string errMsg = e.what();
7656bd095f9SAlpana Kumari                 errMsg += " GPIO : " + presPinName;
7666bd095f9SAlpana Kumari 
7676bd095f9SAlpana Kumari                 if ((json["frus"][file].at(0)["presence"])
7686bd095f9SAlpana Kumari                         .find("gpioI2CAddress") !=
7696bd095f9SAlpana Kumari                     json["frus"][file].at(0)["presence"].end())
7706bd095f9SAlpana Kumari                 {
7716bd095f9SAlpana Kumari                     i2cBusAddr =
7726bd095f9SAlpana Kumari                         json["frus"][file].at(0)["presence"]["gpioI2CAddress"];
7736bd095f9SAlpana Kumari                 }
7746bd095f9SAlpana Kumari 
7756bd095f9SAlpana Kumari                 logGpioPel(errMsg, i2cBusAddr);
77640d1c196SAlpana Kumari                 // Take failure postAction
77740d1c196SAlpana Kumari                 executePostFailAction(json, file);
778735dee9bSAlpana Kumari                 return false;
779735dee9bSAlpana Kumari             }
780735dee9bSAlpana Kumari         }
78140d1c196SAlpana Kumari         else
78240d1c196SAlpana Kumari         {
78340d1c196SAlpana Kumari             // missing required informations
78440d1c196SAlpana Kumari             cerr << "VPD inventory JSON missing basic informations of presence "
78540d1c196SAlpana Kumari                     "for this FRU : ["
78640d1c196SAlpana Kumari                  << file << "]. Executing executePostFailAction." << endl;
78740d1c196SAlpana Kumari 
78840d1c196SAlpana Kumari             // Take failure postAction
78940d1c196SAlpana Kumari             executePostFailAction(json, file);
79040d1c196SAlpana Kumari 
79140d1c196SAlpana Kumari             return false;
79240d1c196SAlpana Kumari         }
793735dee9bSAlpana Kumari     }
79453b38ed0SSantosh Puranik     return std::optional<bool>{};
79553b38ed0SSantosh Puranik }
79653b38ed0SSantosh Puranik 
79753b38ed0SSantosh Puranik bool executePreAction(const nlohmann::json& json, const string& file)
79853b38ed0SSantosh Puranik {
79953b38ed0SSantosh Puranik     auto present = isPresent(json, file);
80053b38ed0SSantosh Puranik     if (present && !present.value())
80153b38ed0SSantosh Puranik     {
80253b38ed0SSantosh Puranik         executePostFailAction(json, file);
80353b38ed0SSantosh Puranik         return false;
80453b38ed0SSantosh Puranik     }
805735dee9bSAlpana Kumari 
806735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("preAction") !=
807735dee9bSAlpana Kumari         json["frus"][file].at(0).end())
808735dee9bSAlpana Kumari     {
809735dee9bSAlpana Kumari         if (((json["frus"][file].at(0)["preAction"]).find("pin") !=
810735dee9bSAlpana Kumari              json["frus"][file].at(0)["preAction"].end()) &&
811735dee9bSAlpana Kumari             ((json["frus"][file].at(0)["preAction"]).find("value") !=
812735dee9bSAlpana Kumari              json["frus"][file].at(0)["preAction"].end()))
813735dee9bSAlpana Kumari         {
814735dee9bSAlpana Kumari             string pinName = json["frus"][file].at(0)["preAction"]["pin"];
815735dee9bSAlpana Kumari             // Get the value to set
816735dee9bSAlpana Kumari             Byte pinValue = json["frus"][file].at(0)["preAction"]["value"];
817735dee9bSAlpana Kumari 
818735dee9bSAlpana Kumari             cout << "Setting GPIO: " << pinName << " to " << (int)pinValue
819735dee9bSAlpana Kumari                  << endl;
820735dee9bSAlpana Kumari             try
821735dee9bSAlpana Kumari             {
822735dee9bSAlpana Kumari                 gpiod::line outputLine = gpiod::find_line(pinName);
823735dee9bSAlpana Kumari 
824735dee9bSAlpana Kumari                 if (!outputLine)
825735dee9bSAlpana Kumari                 {
82640d1c196SAlpana Kumari                     cerr << "Couldn't find the line for output pin - "
82740d1c196SAlpana Kumari                          << pinName << endl;
8286bd095f9SAlpana Kumari                     throw runtime_error(
8296bd095f9SAlpana Kumari                         "Couldn't find output line for the GPIO. "
8306bd095f9SAlpana Kumari                         "Skipping this GPIO action.");
831735dee9bSAlpana Kumari                 }
832735dee9bSAlpana Kumari                 outputLine.request({"FRU pre-action",
833735dee9bSAlpana Kumari                                     ::gpiod::line_request::DIRECTION_OUTPUT, 0},
834735dee9bSAlpana Kumari                                    pinValue);
835735dee9bSAlpana Kumari             }
8366bd095f9SAlpana Kumari             catch (const exception& e)
837735dee9bSAlpana Kumari             {
8386bd095f9SAlpana Kumari                 string i2cBusAddr;
8396bd095f9SAlpana Kumari                 string errMsg = e.what();
8406bd095f9SAlpana Kumari                 errMsg += " GPIO : " + pinName;
8416bd095f9SAlpana Kumari 
8426bd095f9SAlpana Kumari                 if ((json["frus"][file].at(0)["preAction"])
8436bd095f9SAlpana Kumari                         .find("gpioI2CAddress") !=
8446bd095f9SAlpana Kumari                     json["frus"][file].at(0)["preAction"].end())
8456bd095f9SAlpana Kumari                 {
8466bd095f9SAlpana Kumari                     i2cBusAddr =
8476bd095f9SAlpana Kumari                         json["frus"][file].at(0)["preAction"]["gpioI2CAddress"];
8486bd095f9SAlpana Kumari                 }
8496bd095f9SAlpana Kumari 
8506bd095f9SAlpana Kumari                 logGpioPel(errMsg, i2cBusAddr);
85140d1c196SAlpana Kumari 
85240d1c196SAlpana Kumari                 // Take failure postAction
85340d1c196SAlpana Kumari                 executePostFailAction(json, file);
85440d1c196SAlpana Kumari 
855735dee9bSAlpana Kumari                 return false;
856735dee9bSAlpana Kumari             }
857735dee9bSAlpana Kumari         }
85840d1c196SAlpana Kumari         else
85940d1c196SAlpana Kumari         {
86040d1c196SAlpana Kumari             // missing required informations
86140d1c196SAlpana Kumari             cerr
86240d1c196SAlpana Kumari                 << "VPD inventory JSON missing basic informations of preAction "
86340d1c196SAlpana Kumari                    "for this FRU : ["
86440d1c196SAlpana Kumari                 << file << "]. Executing executePostFailAction." << endl;
86540d1c196SAlpana Kumari 
86640d1c196SAlpana Kumari             // Take failure postAction
86740d1c196SAlpana Kumari             executePostFailAction(json, file);
86840d1c196SAlpana Kumari 
86940d1c196SAlpana Kumari             return false;
87040d1c196SAlpana Kumari         }
871735dee9bSAlpana Kumari     }
872735dee9bSAlpana Kumari     return true;
873735dee9bSAlpana Kumari }
874735dee9bSAlpana Kumari 
875aa8a893eSPriyanga Ramasamy void insertOrMerge(inventory::InterfaceMap& map,
876aa8a893eSPriyanga Ramasamy                    const inventory::Interface& interface,
877aa8a893eSPriyanga Ramasamy                    inventory::PropertyMap&& property)
878aa8a893eSPriyanga Ramasamy {
879aa8a893eSPriyanga Ramasamy     if (map.find(interface) != map.end())
880aa8a893eSPriyanga Ramasamy     {
881aa8a893eSPriyanga Ramasamy         auto& prop = map.at(interface);
882aa8a893eSPriyanga Ramasamy         prop.insert(property.begin(), property.end());
883aa8a893eSPriyanga Ramasamy     }
884aa8a893eSPriyanga Ramasamy     else
885aa8a893eSPriyanga Ramasamy     {
886aa8a893eSPriyanga Ramasamy         map.emplace(interface, property);
887aa8a893eSPriyanga Ramasamy     }
888aa8a893eSPriyanga Ramasamy }
889f2d3b53dSSantosh Puranik 
890f2d3b53dSSantosh Puranik BIOSAttrValueType readBIOSAttribute(const std::string& attrName)
891f2d3b53dSSantosh Puranik {
892f2d3b53dSSantosh Puranik     std::tuple<std::string, BIOSAttrValueType, BIOSAttrValueType> attrVal;
893f2d3b53dSSantosh Puranik     auto bus = sdbusplus::bus::new_default();
894f2d3b53dSSantosh Puranik     auto method = bus.new_method_call(
895f2d3b53dSSantosh Puranik         "xyz.openbmc_project.BIOSConfigManager",
896f2d3b53dSSantosh Puranik         "/xyz/openbmc_project/bios_config/manager",
897f2d3b53dSSantosh Puranik         "xyz.openbmc_project.BIOSConfig.Manager", "GetAttribute");
898f2d3b53dSSantosh Puranik     method.append(attrName);
899f2d3b53dSSantosh Puranik     try
900f2d3b53dSSantosh Puranik     {
901f2d3b53dSSantosh Puranik         auto result = bus.call(method);
902f2d3b53dSSantosh Puranik         result.read(std::get<0>(attrVal), std::get<1>(attrVal),
903f2d3b53dSSantosh Puranik                     std::get<2>(attrVal));
904f2d3b53dSSantosh Puranik     }
905f2d3b53dSSantosh Puranik     catch (const sdbusplus::exception::SdBusError& e)
906f2d3b53dSSantosh Puranik     {
907f2d3b53dSSantosh Puranik         std::cerr << "Failed to read BIOS Attribute: " << attrName << std::endl;
908f2d3b53dSSantosh Puranik         std::cerr << e.what() << std::endl;
909f2d3b53dSSantosh Puranik     }
910f2d3b53dSSantosh Puranik     return std::get<1>(attrVal);
911f2d3b53dSSantosh Puranik }
912335873f6SPriyanga Ramasamy 
913335873f6SPriyanga Ramasamy std::string getPowerState()
914335873f6SPriyanga Ramasamy {
915335873f6SPriyanga Ramasamy     // TODO: How do we handle multiple chassis?
916335873f6SPriyanga Ramasamy     string powerState{};
917335873f6SPriyanga Ramasamy     auto bus = sdbusplus::bus::new_default();
918335873f6SPriyanga Ramasamy     auto properties =
919335873f6SPriyanga Ramasamy         bus.new_method_call("xyz.openbmc_project.State.Chassis",
920335873f6SPriyanga Ramasamy                             "/xyz/openbmc_project/state/chassis0",
921335873f6SPriyanga Ramasamy                             "org.freedesktop.DBus.Properties", "Get");
922335873f6SPriyanga Ramasamy     properties.append("xyz.openbmc_project.State.Chassis");
923335873f6SPriyanga Ramasamy     properties.append("CurrentPowerState");
924335873f6SPriyanga Ramasamy     auto result = bus.call(properties);
925335873f6SPriyanga Ramasamy     if (!result.is_method_error())
926335873f6SPriyanga Ramasamy     {
927335873f6SPriyanga Ramasamy         variant<string> val;
928335873f6SPriyanga Ramasamy         result.read(val);
929335873f6SPriyanga Ramasamy         if (auto pVal = get_if<string>(&val))
930335873f6SPriyanga Ramasamy         {
931335873f6SPriyanga Ramasamy             powerState = *pVal;
932335873f6SPriyanga Ramasamy         }
933335873f6SPriyanga Ramasamy     }
934335873f6SPriyanga Ramasamy     cout << "Power state is: " << powerState << endl;
935335873f6SPriyanga Ramasamy     return powerState;
936335873f6SPriyanga Ramasamy }
9376b2b5374SSantosh Puranik 
9386b2b5374SSantosh Puranik Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file)
9396b2b5374SSantosh Puranik {
9406b2b5374SSantosh Puranik     uint32_t offset = 0;
9416b2b5374SSantosh Puranik     // check if offset present?
9426b2b5374SSantosh Puranik     for (const auto& item : js["frus"][file])
9436b2b5374SSantosh Puranik     {
9446b2b5374SSantosh Puranik         if (item.find("offset") != item.end())
9456b2b5374SSantosh Puranik         {
9466b2b5374SSantosh Puranik             offset = item["offset"];
9476b2b5374SSantosh Puranik         }
9486b2b5374SSantosh Puranik     }
9496b2b5374SSantosh Puranik 
9506b2b5374SSantosh Puranik     // TODO: Figure out a better way to get max possible VPD size.
9516b2b5374SSantosh Puranik     auto maxVPDSize = std::min(std::filesystem::file_size(file),
9526b2b5374SSantosh Puranik                                static_cast<uintmax_t>(65504));
9536b2b5374SSantosh Puranik 
9546b2b5374SSantosh Puranik     Binary vpdVector;
9556b2b5374SSantosh Puranik     vpdVector.resize(maxVPDSize);
9566b2b5374SSantosh Puranik     ifstream vpdFile;
9576b2b5374SSantosh Puranik     vpdFile.open(file, ios::binary);
9586b2b5374SSantosh Puranik 
9596b2b5374SSantosh Puranik     vpdFile.seekg(offset, ios_base::cur);
9606b2b5374SSantosh Puranik     vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), maxVPDSize);
9616b2b5374SSantosh Puranik     vpdVector.resize(vpdFile.gcount());
9626b2b5374SSantosh Puranik 
9636b2b5374SSantosh Puranik     // Make sure we reset the EEPROM pointer to a "safe" location if it was DIMM
9646b2b5374SSantosh Puranik     // SPD that we just read.
9656b2b5374SSantosh Puranik     for (const auto& item : js["frus"][file])
9666b2b5374SSantosh Puranik     {
9676b2b5374SSantosh Puranik         if (item.find("extraInterfaces") != item.end())
9686b2b5374SSantosh Puranik         {
9696b2b5374SSantosh Puranik             if (item["extraInterfaces"].find(
9706b2b5374SSantosh Puranik                     "xyz.openbmc_project.Inventory.Item.Dimm") !=
9716b2b5374SSantosh Puranik                 item["extraInterfaces"].end())
9726b2b5374SSantosh Puranik             {
9736b2b5374SSantosh Puranik                 // moves the EEPROM pointer to 2048 'th byte.
9746b2b5374SSantosh Puranik                 vpdFile.seekg(2047, std::ios::beg);
9756b2b5374SSantosh Puranik                 // Read that byte and discard - to affirm the move
9766b2b5374SSantosh Puranik                 // operation.
9776b2b5374SSantosh Puranik                 char ch;
9786b2b5374SSantosh Puranik                 vpdFile.read(&ch, sizeof(ch));
9796b2b5374SSantosh Puranik                 break;
9806b2b5374SSantosh Puranik             }
9816b2b5374SSantosh Puranik         }
9826b2b5374SSantosh Puranik     }
9836b2b5374SSantosh Puranik 
9846b2b5374SSantosh Puranik     return vpdVector;
9856b2b5374SSantosh Puranik }
9866c71c9dcSSunny Srivastava } // namespace vpd
9876c71c9dcSSunny Srivastava } // namespace openpower
988