1abb87edaSPriyangaRamasamy #include "config.h" 2abb87edaSPriyangaRamasamy 3abb87edaSPriyangaRamasamy #include "defines.hpp" 4e12b181bSSunnySrivastava1984 #include "ipz_parser.hpp" 5abb87edaSPriyangaRamasamy #include "keyword_vpd_parser.hpp" 6a00936f8SAlpana Kumari #include "memory_vpd_parser.hpp" 7e12b181bSSunnySrivastava1984 #include "parser_factory.hpp" 8abb87edaSPriyangaRamasamy #include "utils.hpp" 9a20be8ecSSunnySrivastava1984 #include "vpd_exceptions.hpp" 10abb87edaSPriyangaRamasamy 118ea3f6d0SAlpana Kumari #include <ctype.h> 128ea3f6d0SAlpana Kumari 13abb87edaSPriyangaRamasamy #include <CLI/CLI.hpp> 1488edeb6fSSantosh Puranik #include <algorithm> 1565b83601SAlpana Kumari #include <cstdarg> 16abb87edaSPriyangaRamasamy #include <exception> 1783a1d5deSPriyangaRamasamy #include <filesystem> 18abb87edaSPriyangaRamasamy #include <fstream> 19abb87edaSPriyangaRamasamy #include <iostream> 20abb87edaSPriyangaRamasamy #include <iterator> 21abb87edaSPriyangaRamasamy #include <nlohmann/json.hpp> 22280197e3SAndrew Geissler #include <phosphor-logging/log.hpp> 23abb87edaSPriyangaRamasamy 24abb87edaSPriyangaRamasamy using namespace std; 25abb87edaSPriyangaRamasamy using namespace openpower::vpd; 26abb87edaSPriyangaRamasamy using namespace CLI; 27abb87edaSPriyangaRamasamy using namespace vpd::keyword::parser; 2883a1d5deSPriyangaRamasamy using namespace openpower::vpd::constants; 2983a1d5deSPriyangaRamasamy namespace fs = filesystem; 3083a1d5deSPriyangaRamasamy using json = nlohmann::json; 31e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::factory; 32945a02d3SSunnySrivastava1984 using namespace openpower::vpd::inventory; 33a00936f8SAlpana Kumari using namespace openpower::vpd::memory::parser; 34e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::interface; 35a20be8ecSSunnySrivastava1984 using namespace openpower::vpd::exceptions; 36280197e3SAndrew Geissler using namespace phosphor::logging; 37abb87edaSPriyangaRamasamy 3865b83601SAlpana Kumari static const deviceTreeMap deviceTreeSystemTypeMap = { 39*4641bff5SSantosh Puranik {RAINIER_2U, "conf@aspeed-bmc-ibm-rainier.dtb"}, 40*4641bff5SSantosh Puranik {RAINIER_4U, "conf@aspeed-bmc-ibm-rainier-4u.dtb"}, 41*4641bff5SSantosh Puranik {EVEREST, "conf@aspeed-bmc-ibm-everest.dtb"}}; 4265b83601SAlpana Kumari 4388edeb6fSSantosh Puranik /** 4488edeb6fSSantosh Puranik * @brief Expands location codes 4588edeb6fSSantosh Puranik */ 4688edeb6fSSantosh Puranik static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap, 4788edeb6fSSantosh Puranik bool isSystemVpd) 4888edeb6fSSantosh Puranik { 4988edeb6fSSantosh Puranik auto expanded{unexpanded}; 5088edeb6fSSantosh Puranik static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard"; 5188edeb6fSSantosh Puranik static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN"; 5288edeb6fSSantosh Puranik static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS"; 5388edeb6fSSantosh Puranik size_t idx = expanded.find("fcs"); 5488edeb6fSSantosh Puranik try 5588edeb6fSSantosh Puranik { 5688edeb6fSSantosh Puranik if (idx != string::npos) 5788edeb6fSSantosh Puranik { 5888edeb6fSSantosh Puranik string fc{}; 5988edeb6fSSantosh Puranik string se{}; 6088edeb6fSSantosh Puranik if (isSystemVpd) 6188edeb6fSSantosh Puranik { 6288edeb6fSSantosh Puranik const auto& fcData = vpdMap.at("VCEN").at("FC"); 6388edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VCEN").at("SE"); 6488edeb6fSSantosh Puranik fc = string(fcData.data(), fcData.size()); 6588edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 6688edeb6fSSantosh Puranik } 6788edeb6fSSantosh Puranik else 6888edeb6fSSantosh Puranik { 6988edeb6fSSantosh Puranik fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC"); 7088edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE"); 7188edeb6fSSantosh Puranik } 7288edeb6fSSantosh Puranik 7388edeb6fSSantosh Puranik // TODO: See if ND1 can be placed in the JSON 7488edeb6fSSantosh Puranik expanded.replace(idx, 3, fc.substr(0, 4) + ".ND1." + se); 7588edeb6fSSantosh Puranik } 7688edeb6fSSantosh Puranik else 7788edeb6fSSantosh Puranik { 7888edeb6fSSantosh Puranik idx = expanded.find("mts"); 7988edeb6fSSantosh Puranik if (idx != string::npos) 8088edeb6fSSantosh Puranik { 8188edeb6fSSantosh Puranik string mt{}; 8288edeb6fSSantosh Puranik string se{}; 8388edeb6fSSantosh Puranik if (isSystemVpd) 8488edeb6fSSantosh Puranik { 8588edeb6fSSantosh Puranik const auto& mtData = vpdMap.at("VSYS").at("TM"); 8688edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VSYS").at("SE"); 8788edeb6fSSantosh Puranik mt = string(mtData.data(), mtData.size()); 8888edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 8988edeb6fSSantosh Puranik } 9088edeb6fSSantosh Puranik else 9188edeb6fSSantosh Puranik { 9288edeb6fSSantosh Puranik mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM"); 9388edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE"); 9488edeb6fSSantosh Puranik } 9588edeb6fSSantosh Puranik 9688edeb6fSSantosh Puranik replace(mt.begin(), mt.end(), '-', '.'); 9788edeb6fSSantosh Puranik expanded.replace(idx, 3, mt + "." + se); 9888edeb6fSSantosh Puranik } 9988edeb6fSSantosh Puranik } 10088edeb6fSSantosh Puranik } 10158e22145SAlpana Kumari catch (exception& e) 10288edeb6fSSantosh Puranik { 10358e22145SAlpana Kumari cerr << "Failed to expand location code with exception: " << e.what() 10458e22145SAlpana Kumari << "\n"; 10588edeb6fSSantosh Puranik } 10688edeb6fSSantosh Puranik return expanded; 10788edeb6fSSantosh Puranik } 108abb87edaSPriyangaRamasamy /** 109abb87edaSPriyangaRamasamy * @brief Populate FRU specific interfaces. 110abb87edaSPriyangaRamasamy * 111abb87edaSPriyangaRamasamy * This is a common method which handles both 112abb87edaSPriyangaRamasamy * ipz and keyword specific interfaces thus, 113abb87edaSPriyangaRamasamy * reducing the code redundancy. 114abb87edaSPriyangaRamasamy * @param[in] map - Reference to the innermost keyword-value map. 115abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Reference to the interface string. 116abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map. 117abb87edaSPriyangaRamasamy */ 118abb87edaSPriyangaRamasamy template <typename T> 119abb87edaSPriyangaRamasamy static void populateFruSpecificInterfaces(const T& map, 120abb87edaSPriyangaRamasamy const string& preIntrStr, 121abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces) 122abb87edaSPriyangaRamasamy { 123abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 124abb87edaSPriyangaRamasamy 125abb87edaSPriyangaRamasamy for (const auto& kwVal : map) 126abb87edaSPriyangaRamasamy { 12758e22145SAlpana Kumari vector<uint8_t> vec(kwVal.second.begin(), kwVal.second.end()); 128abb87edaSPriyangaRamasamy 129abb87edaSPriyangaRamasamy auto kw = kwVal.first; 130abb87edaSPriyangaRamasamy 131abb87edaSPriyangaRamasamy if (kw[0] == '#') 132abb87edaSPriyangaRamasamy { 13358e22145SAlpana Kumari kw = string("PD_") + kw[1]; 134abb87edaSPriyangaRamasamy } 1358ea3f6d0SAlpana Kumari else if (isdigit(kw[0])) 1368ea3f6d0SAlpana Kumari { 13758e22145SAlpana Kumari kw = string("N_") + kw; 1388ea3f6d0SAlpana Kumari } 139abb87edaSPriyangaRamasamy prop.emplace(move(kw), move(vec)); 140abb87edaSPriyangaRamasamy } 141abb87edaSPriyangaRamasamy 142abb87edaSPriyangaRamasamy interfaces.emplace(preIntrStr, move(prop)); 143abb87edaSPriyangaRamasamy } 144abb87edaSPriyangaRamasamy 145abb87edaSPriyangaRamasamy /** 146abb87edaSPriyangaRamasamy * @brief Populate Interfaces. 147abb87edaSPriyangaRamasamy * 148abb87edaSPriyangaRamasamy * This method populates common and extra interfaces to dbus. 149abb87edaSPriyangaRamasamy * @param[in] js - json object 150abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map 151abb87edaSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map. 15288edeb6fSSantosh Puranik * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD. 153abb87edaSPriyangaRamasamy */ 154abb87edaSPriyangaRamasamy template <typename T> 155abb87edaSPriyangaRamasamy static void populateInterfaces(const nlohmann::json& js, 156abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces, 15788edeb6fSSantosh Puranik const T& vpdMap, bool isSystemVpd) 158abb87edaSPriyangaRamasamy { 159abb87edaSPriyangaRamasamy for (const auto& ifs : js.items()) 160abb87edaSPriyangaRamasamy { 16188edeb6fSSantosh Puranik string inf = ifs.key(); 162abb87edaSPriyangaRamasamy inventory::PropertyMap props; 163abb87edaSPriyangaRamasamy 164abb87edaSPriyangaRamasamy for (const auto& itr : ifs.value().items()) 165abb87edaSPriyangaRamasamy { 16688edeb6fSSantosh Puranik const string& busProp = itr.key(); 16788edeb6fSSantosh Puranik 16831970dedSAlpana Kumari if (itr.value().is_boolean()) 16931970dedSAlpana Kumari { 17088edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<bool>()); 17188edeb6fSSantosh Puranik } 17288edeb6fSSantosh Puranik else if (itr.value().is_string()) 17388edeb6fSSantosh Puranik { 17458e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 17588edeb6fSSantosh Puranik { 17688edeb6fSSantosh Puranik if (busProp == "LocationCode" && 17788edeb6fSSantosh Puranik inf == "com.ibm.ipzvpd.Location") 17888edeb6fSSantosh Puranik { 17988edeb6fSSantosh Puranik auto prop = expandLocationCode( 18088edeb6fSSantosh Puranik itr.value().get<string>(), vpdMap, isSystemVpd); 18188edeb6fSSantosh Puranik props.emplace(busProp, prop); 18288edeb6fSSantosh Puranik } 18388edeb6fSSantosh Puranik else 18488edeb6fSSantosh Puranik { 18588edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 18688edeb6fSSantosh Puranik } 18788edeb6fSSantosh Puranik } 18888edeb6fSSantosh Puranik else 18988edeb6fSSantosh Puranik { 19088edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 19188edeb6fSSantosh Puranik } 19231970dedSAlpana Kumari } 19331970dedSAlpana Kumari else if (itr.value().is_object()) 19431970dedSAlpana Kumari { 195abb87edaSPriyangaRamasamy const string& rec = itr.value().value("recordName", ""); 196abb87edaSPriyangaRamasamy const string& kw = itr.value().value("keywordName", ""); 197abb87edaSPriyangaRamasamy const string& encoding = itr.value().value("encoding", ""); 198abb87edaSPriyangaRamasamy 19958e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 200abb87edaSPriyangaRamasamy { 20188edeb6fSSantosh Puranik if (!rec.empty() && !kw.empty() && vpdMap.count(rec) && 20288edeb6fSSantosh Puranik vpdMap.at(rec).count(kw)) 203abb87edaSPriyangaRamasamy { 204abb87edaSPriyangaRamasamy auto encoded = 205abb87edaSPriyangaRamasamy encodeKeyword(vpdMap.at(rec).at(kw), encoding); 20688edeb6fSSantosh Puranik props.emplace(busProp, encoded); 207abb87edaSPriyangaRamasamy } 208abb87edaSPriyangaRamasamy } 20958e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 210abb87edaSPriyangaRamasamy { 211abb87edaSPriyangaRamasamy if (!kw.empty() && vpdMap.count(kw)) 212abb87edaSPriyangaRamasamy { 213abb87edaSPriyangaRamasamy auto prop = 214abb87edaSPriyangaRamasamy string(vpdMap.at(kw).begin(), vpdMap.at(kw).end()); 215abb87edaSPriyangaRamasamy auto encoded = encodeKeyword(prop, encoding); 21688edeb6fSSantosh Puranik props.emplace(busProp, encoded); 217abb87edaSPriyangaRamasamy } 218abb87edaSPriyangaRamasamy } 219abb87edaSPriyangaRamasamy } 22031970dedSAlpana Kumari } 221abb87edaSPriyangaRamasamy interfaces.emplace(inf, move(props)); 222abb87edaSPriyangaRamasamy } 223abb87edaSPriyangaRamasamy } 224abb87edaSPriyangaRamasamy 22558e22145SAlpana Kumari Binary getVpdDataInVector(nlohmann::json& js, const string& file) 22658e22145SAlpana Kumari { 22758e22145SAlpana Kumari uint32_t offset = 0; 22858e22145SAlpana Kumari // check if offset present? 22958e22145SAlpana Kumari for (const auto& item : js["frus"][file]) 23058e22145SAlpana Kumari { 23158e22145SAlpana Kumari if (item.find("offset") != item.end()) 23258e22145SAlpana Kumari { 23358e22145SAlpana Kumari offset = item["offset"]; 23458e22145SAlpana Kumari } 23558e22145SAlpana Kumari } 23658e22145SAlpana Kumari 23758e22145SAlpana Kumari // TODO: Figure out a better way to get max possible VPD size. 23858e22145SAlpana Kumari Binary vpdVector; 23958e22145SAlpana Kumari vpdVector.resize(65504); 24058e22145SAlpana Kumari ifstream vpdFile; 24158e22145SAlpana Kumari vpdFile.open(file, ios::binary); 24258e22145SAlpana Kumari 24358e22145SAlpana Kumari vpdFile.seekg(offset, ios_base::cur); 24458e22145SAlpana Kumari vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), 65504); 24558e22145SAlpana Kumari vpdVector.resize(vpdFile.gcount()); 24658e22145SAlpana Kumari 24758e22145SAlpana Kumari return vpdVector; 24858e22145SAlpana Kumari } 24958e22145SAlpana Kumari 250abb87edaSPriyangaRamasamy /** 2518e140a1cSPriyangaRamasamy * @brief Prime the Inventory 2528e140a1cSPriyangaRamasamy * Prime the inventory by populating only the location code, 2538e140a1cSPriyangaRamasamy * type interface and the inventory object for the frus 2548e140a1cSPriyangaRamasamy * which are not system vpd fru. 255abb87edaSPriyangaRamasamy * 2568e140a1cSPriyangaRamasamy * @param[in] jsObject - Reference to vpd inventory json object 2578e140a1cSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map 2588e140a1cSPriyangaRamasamy * 2598e140a1cSPriyangaRamasamy * @returns Map of items in extraInterface. 2608e140a1cSPriyangaRamasamy */ 2618e140a1cSPriyangaRamasamy template <typename T> 2628e140a1cSPriyangaRamasamy inventory::ObjectMap primeInventory(const nlohmann::json& jsObject, 2638e140a1cSPriyangaRamasamy const T& vpdMap) 2648e140a1cSPriyangaRamasamy { 2658e140a1cSPriyangaRamasamy inventory::ObjectMap objects; 2668e140a1cSPriyangaRamasamy 2678e140a1cSPriyangaRamasamy for (auto& itemFRUS : jsObject["frus"].items()) 2688e140a1cSPriyangaRamasamy { 2698e140a1cSPriyangaRamasamy for (auto& itemEEPROM : itemFRUS.value()) 2708e140a1cSPriyangaRamasamy { 2718e140a1cSPriyangaRamasamy inventory::InterfaceMap interfaces; 2728e140a1cSPriyangaRamasamy auto isSystemVpd = itemEEPROM.value("isSystemVpd", false); 2738e140a1cSPriyangaRamasamy inventory::Object object(itemEEPROM.at("inventoryPath")); 2748e140a1cSPriyangaRamasamy 2758e140a1cSPriyangaRamasamy if (!isSystemVpd && !itemEEPROM.value("noprime", false)) 2768e140a1cSPriyangaRamasamy { 2778e140a1cSPriyangaRamasamy if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end()) 2788e140a1cSPriyangaRamasamy { 2798e140a1cSPriyangaRamasamy for (const auto& eI : itemEEPROM["extraInterfaces"].items()) 2808e140a1cSPriyangaRamasamy { 2818e140a1cSPriyangaRamasamy inventory::PropertyMap props; 2828e140a1cSPriyangaRamasamy if (eI.key() == 2838e140a1cSPriyangaRamasamy openpower::vpd::constants::LOCATION_CODE_INF) 2848e140a1cSPriyangaRamasamy { 2858e140a1cSPriyangaRamasamy if constexpr (std::is_same<T, Parsed>::value) 2868e140a1cSPriyangaRamasamy { 2878e140a1cSPriyangaRamasamy for (auto& lC : eI.value().items()) 2888e140a1cSPriyangaRamasamy { 2898e140a1cSPriyangaRamasamy auto propVal = expandLocationCode( 2908e140a1cSPriyangaRamasamy lC.value().get<string>(), vpdMap, true); 2918e140a1cSPriyangaRamasamy 2928e140a1cSPriyangaRamasamy props.emplace(move(lC.key()), 2938e140a1cSPriyangaRamasamy move(propVal)); 2948e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), 2958e140a1cSPriyangaRamasamy move(props)); 2968e140a1cSPriyangaRamasamy } 2978e140a1cSPriyangaRamasamy } 2988e140a1cSPriyangaRamasamy } 2998e140a1cSPriyangaRamasamy else if (eI.key().find("Inventory.Item.") != 3008e140a1cSPriyangaRamasamy string::npos) 3018e140a1cSPriyangaRamasamy { 3028e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), move(props)); 3038e140a1cSPriyangaRamasamy } 3048e140a1cSPriyangaRamasamy } 3058e140a1cSPriyangaRamasamy } 3068e140a1cSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 3078e140a1cSPriyangaRamasamy } 3088e140a1cSPriyangaRamasamy } 3098e140a1cSPriyangaRamasamy } 3108e140a1cSPriyangaRamasamy return objects; 3118e140a1cSPriyangaRamasamy } 3128e140a1cSPriyangaRamasamy 31365b83601SAlpana Kumari /* It does nothing. Just an empty function to return null 31465b83601SAlpana Kumari * at the end of variadic template args 31565b83601SAlpana Kumari */ 31665b83601SAlpana Kumari string getCommand() 31765b83601SAlpana Kumari { 31865b83601SAlpana Kumari return ""; 31965b83601SAlpana Kumari } 32065b83601SAlpana Kumari 32165b83601SAlpana Kumari /* This function to arrange all arguments to make command 32265b83601SAlpana Kumari */ 32365b83601SAlpana Kumari template <typename T, typename... Types> 32465b83601SAlpana Kumari string getCommand(T arg1, Types... args) 32565b83601SAlpana Kumari { 32665b83601SAlpana Kumari string cmd = " " + arg1 + getCommand(args...); 32765b83601SAlpana Kumari 32865b83601SAlpana Kumari return cmd; 32965b83601SAlpana Kumari } 33065b83601SAlpana Kumari 33165b83601SAlpana Kumari /* This API takes arguments and run that command 33265b83601SAlpana Kumari * returns output of that command 33365b83601SAlpana Kumari */ 33465b83601SAlpana Kumari template <typename T, typename... Types> 33565b83601SAlpana Kumari static vector<string> executeCmd(T& path, Types... args) 33665b83601SAlpana Kumari { 33765b83601SAlpana Kumari vector<string> stdOutput; 33865b83601SAlpana Kumari array<char, 128> buffer; 33965b83601SAlpana Kumari 34065b83601SAlpana Kumari string cmd = path + getCommand(args...); 34165b83601SAlpana Kumari 34265b83601SAlpana Kumari unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose); 34365b83601SAlpana Kumari if (!pipe) 34465b83601SAlpana Kumari { 34565b83601SAlpana Kumari throw runtime_error("popen() failed!"); 34665b83601SAlpana Kumari } 34765b83601SAlpana Kumari while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 34865b83601SAlpana Kumari { 34965b83601SAlpana Kumari stdOutput.emplace_back(buffer.data()); 35065b83601SAlpana Kumari } 35165b83601SAlpana Kumari 35265b83601SAlpana Kumari return stdOutput; 35365b83601SAlpana Kumari } 35465b83601SAlpana Kumari 35565b83601SAlpana Kumari /** 35665b83601SAlpana Kumari * @brief This API executes command to set environment variable 35765b83601SAlpana Kumari * And then reboot the system 35865b83601SAlpana Kumari * @param[in] key -env key to set new value 35965b83601SAlpana Kumari * @param[in] value -value to set. 36065b83601SAlpana Kumari */ 36165b83601SAlpana Kumari void setEnvAndReboot(const string& key, const string& value) 36265b83601SAlpana Kumari { 36365b83601SAlpana Kumari // set env and reboot and break. 36465b83601SAlpana Kumari executeCmd("/sbin/fw_setenv", key, value); 365280197e3SAndrew Geissler log<level::INFO>("Rebooting BMC to pick up new device tree"); 36665b83601SAlpana Kumari // make dbus call to reboot 36765b83601SAlpana Kumari auto bus = sdbusplus::bus::new_default_system(); 36865b83601SAlpana Kumari auto method = bus.new_method_call( 36965b83601SAlpana Kumari "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 37065b83601SAlpana Kumari "org.freedesktop.systemd1.Manager", "Reboot"); 37165b83601SAlpana Kumari bus.call_noreply(method); 37265b83601SAlpana Kumari } 37365b83601SAlpana Kumari 37465b83601SAlpana Kumari /* 37565b83601SAlpana Kumari * @brief This API checks for env var fitconfig. 37665b83601SAlpana Kumari * If not initialised OR updated as per the current system type, 37765b83601SAlpana Kumari * update this env var and reboot the system. 37865b83601SAlpana Kumari * 37965b83601SAlpana Kumari * @param[in] systemType IM kwd in vpd tells about which system type it is. 38065b83601SAlpana Kumari * */ 38165b83601SAlpana Kumari void setDevTreeEnv(const string& systemType) 38265b83601SAlpana Kumari { 38365b83601SAlpana Kumari string newDeviceTree; 38465b83601SAlpana Kumari 38565b83601SAlpana Kumari if (deviceTreeSystemTypeMap.find(systemType) != 38665b83601SAlpana Kumari deviceTreeSystemTypeMap.end()) 38765b83601SAlpana Kumari { 38865b83601SAlpana Kumari newDeviceTree = deviceTreeSystemTypeMap.at(systemType); 38965b83601SAlpana Kumari } 39065b83601SAlpana Kumari 39165b83601SAlpana Kumari string readVarValue; 39265b83601SAlpana Kumari bool envVarFound = false; 39365b83601SAlpana Kumari 39465b83601SAlpana Kumari vector<string> output = executeCmd("/sbin/fw_printenv"); 39565b83601SAlpana Kumari for (const auto& entry : output) 39665b83601SAlpana Kumari { 39765b83601SAlpana Kumari size_t pos = entry.find("="); 39865b83601SAlpana Kumari string key = entry.substr(0, pos); 39965b83601SAlpana Kumari if (key != "fitconfig") 40065b83601SAlpana Kumari { 40165b83601SAlpana Kumari continue; 40265b83601SAlpana Kumari } 40365b83601SAlpana Kumari 40465b83601SAlpana Kumari envVarFound = true; 40565b83601SAlpana Kumari if (pos + 1 < entry.size()) 40665b83601SAlpana Kumari { 40765b83601SAlpana Kumari readVarValue = entry.substr(pos + 1); 40865b83601SAlpana Kumari if (readVarValue.find(newDeviceTree) != string::npos) 40965b83601SAlpana Kumari { 41065b83601SAlpana Kumari // fitconfig is Updated. No action needed 41165b83601SAlpana Kumari break; 41265b83601SAlpana Kumari } 41365b83601SAlpana Kumari } 41465b83601SAlpana Kumari // set env and reboot and break. 41565b83601SAlpana Kumari setEnvAndReboot(key, newDeviceTree); 41665b83601SAlpana Kumari exit(0); 41765b83601SAlpana Kumari } 41865b83601SAlpana Kumari 41965b83601SAlpana Kumari // check If env var Not found 42065b83601SAlpana Kumari if (!envVarFound) 42165b83601SAlpana Kumari { 42265b83601SAlpana Kumari setEnvAndReboot("fitconfig", newDeviceTree); 42365b83601SAlpana Kumari } 42465b83601SAlpana Kumari } 42565b83601SAlpana Kumari 4268e140a1cSPriyangaRamasamy /** 4278e140a1cSPriyangaRamasamy * @brief Populate Dbus. 428abb87edaSPriyangaRamasamy * This method invokes all the populateInterface functions 429abb87edaSPriyangaRamasamy * and notifies PIM about dbus object. 4308e140a1cSPriyangaRamasamy * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the 4318e140a1cSPriyangaRamasamy * input. 432abb87edaSPriyangaRamasamy * @param[in] js - Inventory json object 433abb87edaSPriyangaRamasamy * @param[in] filePath - Path of the vpd file 434abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Interface string 435abb87edaSPriyangaRamasamy */ 436abb87edaSPriyangaRamasamy template <typename T> 437abb87edaSPriyangaRamasamy static void populateDbus(const T& vpdMap, nlohmann::json& js, 43865b83601SAlpana Kumari const string& filePath) 439abb87edaSPriyangaRamasamy { 440abb87edaSPriyangaRamasamy inventory::InterfaceMap interfaces; 441abb87edaSPriyangaRamasamy inventory::ObjectMap objects; 442abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 443abb87edaSPriyangaRamasamy 444e12b181bSSunnySrivastava1984 bool isSystemVpd = false; 445abb87edaSPriyangaRamasamy for (const auto& item : js["frus"][filePath]) 446abb87edaSPriyangaRamasamy { 447abb87edaSPriyangaRamasamy const auto& objectPath = item["inventoryPath"]; 448abb87edaSPriyangaRamasamy sdbusplus::message::object_path object(objectPath); 4498e140a1cSPriyangaRamasamy isSystemVpd = item.value("isSystemVpd", false); 450abb87edaSPriyangaRamasamy // Populate the VPD keywords and the common interfaces only if we 451abb87edaSPriyangaRamasamy // are asked to inherit that data from the VPD, else only add the 452abb87edaSPriyangaRamasamy // extraInterfaces. 453abb87edaSPriyangaRamasamy if (item.value("inherit", true)) 454abb87edaSPriyangaRamasamy { 45558e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 456abb87edaSPriyangaRamasamy { 4578e140a1cSPriyangaRamasamy // Each record in the VPD becomes an interface and all 4588e140a1cSPriyangaRamasamy // keyword within the record are properties under that 4598e140a1cSPriyangaRamasamy // interface. 460abb87edaSPriyangaRamasamy for (const auto& record : vpdMap) 461abb87edaSPriyangaRamasamy { 462abb87edaSPriyangaRamasamy populateFruSpecificInterfaces( 463e12b181bSSunnySrivastava1984 record.second, ipzVpdInf + record.first, interfaces); 464abb87edaSPriyangaRamasamy } 465abb87edaSPriyangaRamasamy } 46658e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 467abb87edaSPriyangaRamasamy { 468e12b181bSSunnySrivastava1984 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces); 469abb87edaSPriyangaRamasamy } 47088edeb6fSSantosh Puranik if (js.find("commonInterfaces") != js.end()) 47188edeb6fSSantosh Puranik { 47288edeb6fSSantosh Puranik populateInterfaces(js["commonInterfaces"], interfaces, vpdMap, 47388edeb6fSSantosh Puranik isSystemVpd); 47488edeb6fSSantosh Puranik } 475abb87edaSPriyangaRamasamy } 4760859eb65SSantosh Puranik else 4770859eb65SSantosh Puranik { 4780859eb65SSantosh Puranik // Check if we have been asked to inherit specific record(s) 47958e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 4800859eb65SSantosh Puranik { 4810859eb65SSantosh Puranik if (item.find("copyRecords") != item.end()) 4820859eb65SSantosh Puranik { 4830859eb65SSantosh Puranik for (const auto& record : item["copyRecords"]) 4840859eb65SSantosh Puranik { 4850859eb65SSantosh Puranik const string& recordName = record; 4860859eb65SSantosh Puranik if (vpdMap.find(recordName) != vpdMap.end()) 4870859eb65SSantosh Puranik { 4880859eb65SSantosh Puranik populateFruSpecificInterfaces( 489e12b181bSSunnySrivastava1984 vpdMap.at(recordName), ipzVpdInf + recordName, 4900859eb65SSantosh Puranik interfaces); 4910859eb65SSantosh Puranik } 4920859eb65SSantosh Puranik } 4930859eb65SSantosh Puranik } 4940859eb65SSantosh Puranik } 4950859eb65SSantosh Puranik } 496abb87edaSPriyangaRamasamy 49758e22145SAlpana Kumari if (item.value("inheritEI", true)) 49858e22145SAlpana Kumari { 499abb87edaSPriyangaRamasamy // Populate interfaces and properties that are common to every FRU 5008e140a1cSPriyangaRamasamy // and additional interface that might be defined on a per-FRU 5018e140a1cSPriyangaRamasamy // basis. 502abb87edaSPriyangaRamasamy if (item.find("extraInterfaces") != item.end()) 503abb87edaSPriyangaRamasamy { 50488edeb6fSSantosh Puranik populateInterfaces(item["extraInterfaces"], interfaces, vpdMap, 50588edeb6fSSantosh Puranik isSystemVpd); 506abb87edaSPriyangaRamasamy } 50758e22145SAlpana Kumari } 508abb87edaSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 509abb87edaSPriyangaRamasamy } 510abb87edaSPriyangaRamasamy 5118e140a1cSPriyangaRamasamy if (isSystemVpd) 5128e140a1cSPriyangaRamasamy { 51383a1d5deSPriyangaRamasamy vector<uint8_t> imVal; 51483a1d5deSPriyangaRamasamy if constexpr (is_same<T, Parsed>::value) 51583a1d5deSPriyangaRamasamy { 51683a1d5deSPriyangaRamasamy auto property = vpdMap.find("VSBP"); 51783a1d5deSPriyangaRamasamy if (property != vpdMap.end()) 51883a1d5deSPriyangaRamasamy { 51983a1d5deSPriyangaRamasamy auto value = (property->second).find("IM"); 52083a1d5deSPriyangaRamasamy if (value != (property->second).end()) 52183a1d5deSPriyangaRamasamy { 52283a1d5deSPriyangaRamasamy copy(value->second.begin(), value->second.end(), 52383a1d5deSPriyangaRamasamy back_inserter(imVal)); 52483a1d5deSPriyangaRamasamy } 52583a1d5deSPriyangaRamasamy } 52683a1d5deSPriyangaRamasamy } 52783a1d5deSPriyangaRamasamy 52883a1d5deSPriyangaRamasamy fs::path target; 52983a1d5deSPriyangaRamasamy fs::path link = INVENTORY_JSON_SYM_LINK; 53083a1d5deSPriyangaRamasamy 53183a1d5deSPriyangaRamasamy ostringstream oss; 53283a1d5deSPriyangaRamasamy for (auto& i : imVal) 53383a1d5deSPriyangaRamasamy { 53483a1d5deSPriyangaRamasamy oss << setw(2) << setfill('0') << hex << static_cast<int>(i); 53583a1d5deSPriyangaRamasamy } 53683a1d5deSPriyangaRamasamy string imValStr = oss.str(); 53783a1d5deSPriyangaRamasamy 53865b83601SAlpana Kumari if (imValStr == RAINIER_4U) // 4U 53983a1d5deSPriyangaRamasamy { 54083a1d5deSPriyangaRamasamy target = INVENTORY_JSON_4U; 54183a1d5deSPriyangaRamasamy } 54265b83601SAlpana Kumari else if (imValStr == RAINIER_2U) // 2U 54383a1d5deSPriyangaRamasamy { 54483a1d5deSPriyangaRamasamy target = INVENTORY_JSON_2U; 54583a1d5deSPriyangaRamasamy } 546*4641bff5SSantosh Puranik else if (imValStr == EVEREST) 547*4641bff5SSantosh Puranik { 548*4641bff5SSantosh Puranik target = INVENTORY_JSON_EVEREST; 549*4641bff5SSantosh Puranik } 55083a1d5deSPriyangaRamasamy 5510246a4d7SSantosh Puranik // Create the directory for hosting the symlink 5520246a4d7SSantosh Puranik fs::create_directories(VPD_FILES_PATH); 5530246a4d7SSantosh Puranik // unlink the symlink previously created (if any) 55483a1d5deSPriyangaRamasamy remove(INVENTORY_JSON_SYM_LINK); 55583a1d5deSPriyangaRamasamy // create a new symlink based on the system 55683a1d5deSPriyangaRamasamy fs::create_symlink(target, link); 55783a1d5deSPriyangaRamasamy 55883a1d5deSPriyangaRamasamy // Reloading the json 55983a1d5deSPriyangaRamasamy ifstream inventoryJson(link); 56083a1d5deSPriyangaRamasamy auto js = json::parse(inventoryJson); 56183a1d5deSPriyangaRamasamy inventoryJson.close(); 56283a1d5deSPriyangaRamasamy 5638e140a1cSPriyangaRamasamy inventory::ObjectMap primeObject = primeInventory(js, vpdMap); 5648e140a1cSPriyangaRamasamy objects.insert(primeObject.begin(), primeObject.end()); 56565b83601SAlpana Kumari 56665b83601SAlpana Kumari // set the U-boot environment variable for device-tree 56765b83601SAlpana Kumari setDevTreeEnv(imValStr); 5688e140a1cSPriyangaRamasamy } 5698e140a1cSPriyangaRamasamy 570abb87edaSPriyangaRamasamy // Notify PIM 571abb87edaSPriyangaRamasamy inventory::callPIM(move(objects)); 572abb87edaSPriyangaRamasamy } 573abb87edaSPriyangaRamasamy 574abb87edaSPriyangaRamasamy int main(int argc, char** argv) 575abb87edaSPriyangaRamasamy { 576abb87edaSPriyangaRamasamy int rc = 0; 577a20be8ecSSunnySrivastava1984 string file{}; 578a20be8ecSSunnySrivastava1984 json js{}; 579a20be8ecSSunnySrivastava1984 580a20be8ecSSunnySrivastava1984 // map to hold additional data in case of logging pel 581a20be8ecSSunnySrivastava1984 PelAdditionalData additionalData{}; 582a20be8ecSSunnySrivastava1984 583a20be8ecSSunnySrivastava1984 // this is needed to hold base fru inventory path in case there is ECC or 584a20be8ecSSunnySrivastava1984 // vpd exception while parsing the file 585a20be8ecSSunnySrivastava1984 std::string baseFruInventoryPath = {}; 586abb87edaSPriyangaRamasamy 587abb87edaSPriyangaRamasamy try 588abb87edaSPriyangaRamasamy { 589abb87edaSPriyangaRamasamy App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store " 590abb87edaSPriyangaRamasamy "in DBUS"}; 591abb87edaSPriyangaRamasamy string file{}; 592abb87edaSPriyangaRamasamy 593abb87edaSPriyangaRamasamy app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)") 594abb87edaSPriyangaRamasamy ->required() 595abb87edaSPriyangaRamasamy ->check(ExistingFile); 596abb87edaSPriyangaRamasamy 597abb87edaSPriyangaRamasamy CLI11_PARSE(app, argc, argv); 598abb87edaSPriyangaRamasamy 5990246a4d7SSantosh Puranik auto jsonToParse = INVENTORY_JSON_DEFAULT; 6000246a4d7SSantosh Puranik 6010246a4d7SSantosh Puranik // If the symlink exists, it means it has been setup for us, switch the 6020246a4d7SSantosh Puranik // path 6030246a4d7SSantosh Puranik if (fs::exists(INVENTORY_JSON_SYM_LINK)) 6040246a4d7SSantosh Puranik { 6050246a4d7SSantosh Puranik jsonToParse = INVENTORY_JSON_SYM_LINK; 6060246a4d7SSantosh Puranik } 6070246a4d7SSantosh Puranik 608abb87edaSPriyangaRamasamy // Make sure that the file path we get is for a supported EEPROM 6090246a4d7SSantosh Puranik ifstream inventoryJson(jsonToParse); 610a20be8ecSSunnySrivastava1984 if (!inventoryJson) 611a20be8ecSSunnySrivastava1984 { 612a20be8ecSSunnySrivastava1984 throw( 613a20be8ecSSunnySrivastava1984 (VpdJsonException("Failed to access Json path", jsonToParse))); 614a20be8ecSSunnySrivastava1984 } 615a20be8ecSSunnySrivastava1984 616a20be8ecSSunnySrivastava1984 try 617a20be8ecSSunnySrivastava1984 { 618a20be8ecSSunnySrivastava1984 js = json::parse(inventoryJson); 619a20be8ecSSunnySrivastava1984 } 620a20be8ecSSunnySrivastava1984 catch (json::parse_error& ex) 621a20be8ecSSunnySrivastava1984 { 622a20be8ecSSunnySrivastava1984 throw((VpdJsonException("Json parsing failed", jsonToParse))); 623a20be8ecSSunnySrivastava1984 } 624abb87edaSPriyangaRamasamy 625abb87edaSPriyangaRamasamy if ((js.find("frus") == js.end()) || 626abb87edaSPriyangaRamasamy (js["frus"].find(file) == js["frus"].end())) 627abb87edaSPriyangaRamasamy { 62858e22145SAlpana Kumari cout << "Device path not in JSON, ignoring" << endl; 62988edeb6fSSantosh Puranik return 0; 630abb87edaSPriyangaRamasamy } 631abb87edaSPriyangaRamasamy 632a20be8ecSSunnySrivastava1984 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"]; 633a20be8ecSSunnySrivastava1984 634e12b181bSSunnySrivastava1984 Binary vpdVector = getVpdDataInVector(js, file); 63565b83601SAlpana Kumari ParserInterface* parser = ParserFactory::getParser(move(vpdVector)); 636e12b181bSSunnySrivastava1984 637e12b181bSSunnySrivastava1984 variant<KeywordVpdMap, Store> parseResult; 638e12b181bSSunnySrivastava1984 parseResult = parser->parse(); 639e12b181bSSunnySrivastava1984 640e12b181bSSunnySrivastava1984 if (auto pVal = get_if<Store>(&parseResult)) 641abb87edaSPriyangaRamasamy { 642e12b181bSSunnySrivastava1984 populateDbus(pVal->getVpdMap(), js, file); 643e12b181bSSunnySrivastava1984 } 644e12b181bSSunnySrivastava1984 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult)) 645abb87edaSPriyangaRamasamy { 646e12b181bSSunnySrivastava1984 populateDbus(*pVal, js, file); 647abb87edaSPriyangaRamasamy } 648abb87edaSPriyangaRamasamy 649e12b181bSSunnySrivastava1984 // release the parser object 650e12b181bSSunnySrivastava1984 ParserFactory::freeParser(parser); 651abb87edaSPriyangaRamasamy } 652a20be8ecSSunnySrivastava1984 catch (const VpdJsonException& ex) 653a20be8ecSSunnySrivastava1984 { 654a20be8ecSSunnySrivastava1984 additionalData.emplace("JSON_PATH", ex.getJsonPath()); 655a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", ex.what()); 656a20be8ecSSunnySrivastava1984 createPEL(additionalData, errIntfForJsonFailure); 657a20be8ecSSunnySrivastava1984 658a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 659a20be8ecSSunnySrivastava1984 rc = -1; 660a20be8ecSSunnySrivastava1984 } 661a20be8ecSSunnySrivastava1984 catch (const VpdEccException& ex) 662a20be8ecSSunnySrivastava1984 { 663a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "ECC check failed"); 664a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 665a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 666a20be8ecSSunnySrivastava1984 createPEL(additionalData, errIntfForEccCheckFail); 667a20be8ecSSunnySrivastava1984 668a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 669a20be8ecSSunnySrivastava1984 rc = -1; 670a20be8ecSSunnySrivastava1984 } 671a20be8ecSSunnySrivastava1984 catch (const VpdDataException& ex) 672a20be8ecSSunnySrivastava1984 { 673a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "Invalid VPD data"); 674a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 675a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 676a20be8ecSSunnySrivastava1984 createPEL(additionalData, errIntfForInvalidVPD); 677a20be8ecSSunnySrivastava1984 678a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 679a20be8ecSSunnySrivastava1984 rc = -1; 680a20be8ecSSunnySrivastava1984 } 681abb87edaSPriyangaRamasamy catch (exception& e) 682abb87edaSPriyangaRamasamy { 683abb87edaSPriyangaRamasamy cerr << e.what() << "\n"; 684abb87edaSPriyangaRamasamy rc = -1; 685abb87edaSPriyangaRamasamy } 686abb87edaSPriyangaRamasamy 687abb87edaSPriyangaRamasamy return rc; 688abb87edaSPriyangaRamasamy } 689