1099543e4SBrad Bishop // SPDX-License-Identifier: Apache-2.0 2099543e4SBrad Bishop 3099543e4SBrad Bishop /**@file functions.cpp*/ 4099543e4SBrad Bishop 556f538caSAdriana Kobylak #include "config.h" 656f538caSAdriana Kobylak 7099543e4SBrad Bishop #include "functions.hpp" 8099543e4SBrad Bishop 9ae0998f1SAdriana Kobylak #include <nlohmann/json.hpp> 1056f538caSAdriana Kobylak #include <phosphor-logging/log.hpp> 11099543e4SBrad Bishop #include <sdbusplus/bus.hpp> 12099543e4SBrad Bishop #include <sdbusplus/bus/match.hpp> 13c79fa915SAdriana Kobylak #include <sdbusplus/exception.hpp> 14099543e4SBrad Bishop #include <sdbusplus/message.hpp> 15099543e4SBrad Bishop #include <sdeventplus/event.hpp> 162b78eb0eSAdriana Kobylak #include <xyz/openbmc_project/Common/error.hpp> 17099543e4SBrad Bishop 18099543e4SBrad Bishop #include <filesystem> 19ae0998f1SAdriana Kobylak #include <fstream> 20099543e4SBrad Bishop #include <functional> 21099543e4SBrad Bishop #include <iostream> 22099543e4SBrad Bishop #include <map> 23099543e4SBrad Bishop #include <memory> 24099543e4SBrad Bishop #include <string> 25099543e4SBrad Bishop #include <variant> 26099543e4SBrad Bishop #include <vector> 27099543e4SBrad Bishop 28099543e4SBrad Bishop namespace functions 29099543e4SBrad Bishop { 30099543e4SBrad Bishop namespace process_hostfirmware 31099543e4SBrad Bishop { 32099543e4SBrad Bishop 3356f538caSAdriana Kobylak using namespace phosphor::logging; 34ebf67bf7SAdriana Kobylak using InterfacesPropertiesMap = 35ebf67bf7SAdriana Kobylak std::map<std::string, 36ebf67bf7SAdriana Kobylak std::map<std::string, std::variant<std::vector<std::string>>>>; 37ebf67bf7SAdriana Kobylak using ManagedObjectType = 38ebf67bf7SAdriana Kobylak std::map<sdbusplus::message::object_path, InterfacesPropertiesMap>; 3956f538caSAdriana Kobylak 40*f3b0c288SAdriana Kobylak constexpr auto tocName = "pnor.toc"; 41*f3b0c288SAdriana Kobylak 42099543e4SBrad Bishop /** 43ebf67bf7SAdriana Kobylak * @brief Returns the managed objects for a given service 44ebf67bf7SAdriana Kobylak */ 450dea1992SPatrick Williams ManagedObjectType getManagedObjects(sdbusplus::bus_t& bus, 4675352b42SNan Zhou const std::string& service, 4775352b42SNan Zhou const std::string& managerPath) 4875352b42SNan Zhou 49ebf67bf7SAdriana Kobylak { 5075352b42SNan Zhou auto method = bus.new_method_call(service.c_str(), managerPath.c_str(), 51ebf67bf7SAdriana Kobylak "org.freedesktop.DBus.ObjectManager", 52ebf67bf7SAdriana Kobylak "GetManagedObjects"); 53ebf67bf7SAdriana Kobylak 54ebf67bf7SAdriana Kobylak ManagedObjectType objects; 55ebf67bf7SAdriana Kobylak 56ebf67bf7SAdriana Kobylak try 57ebf67bf7SAdriana Kobylak { 58ebf67bf7SAdriana Kobylak auto reply = bus.call(method); 59ebf67bf7SAdriana Kobylak reply.read(objects); 60ebf67bf7SAdriana Kobylak } 610dea1992SPatrick Williams catch (const sdbusplus::exception_t& e) 62ebf67bf7SAdriana Kobylak { 63ebf67bf7SAdriana Kobylak return ManagedObjectType{}; 64ebf67bf7SAdriana Kobylak } 65ebf67bf7SAdriana Kobylak return objects; 66ebf67bf7SAdriana Kobylak } 67ebf67bf7SAdriana Kobylak 68ebf67bf7SAdriana Kobylak /** 69099543e4SBrad Bishop * @brief Issue callbacks safely 70099543e4SBrad Bishop * 71099543e4SBrad Bishop * std::function can be empty, so this wrapper method checks for that prior to 72099543e4SBrad Bishop * calling it to avoid std::bad_function_call 73099543e4SBrad Bishop * 74099543e4SBrad Bishop * @tparam Sig the types of the std::function arguments 75099543e4SBrad Bishop * @tparam Args the deduced argument types 76099543e4SBrad Bishop * @param[in] callback the callback being wrapped 77099543e4SBrad Bishop * @param[in] args the callback arguments 78099543e4SBrad Bishop */ 79099543e4SBrad Bishop template <typename... Sig, typename... Args> 80099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args) 81099543e4SBrad Bishop { 82099543e4SBrad Bishop if (callback) 83099543e4SBrad Bishop { 84099543e4SBrad Bishop callback(std::forward<Args>(args)...); 85099543e4SBrad Bishop } 86099543e4SBrad Bishop } 87099543e4SBrad Bishop 88099543e4SBrad Bishop /** 89749bdcc9SAdriana Kobylak * @brief Get file extensions for Compatible 90099543e4SBrad Bishop * 91099543e4SBrad Bishop * IBM host firmware can be deployed as blobs (files) in a filesystem. Host 92099543e4SBrad Bishop * firmware blobs for different values of 93749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible are packaged with 94749bdcc9SAdriana Kobylak * different filename extensions. getExtensionsForIbmCompatibleSystem maintains 95749bdcc9SAdriana Kobylak * the mapping from a given value of 96749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible to an array of filename 97749bdcc9SAdriana Kobylak * extensions. 98099543e4SBrad Bishop * 99099543e4SBrad Bishop * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and 100749bdcc9SAdriana Kobylak * the extensions parameter is reset with the map entry. If no mapping is found 101749bdcc9SAdriana Kobylak * getExtensionsForIbmCompatibleSystem returns false and extensions is 102099543e4SBrad Bishop * unmodified. 103099543e4SBrad Bishop * 104099543e4SBrad Bishop * @param[in] extensionMap a map of 105749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file 106749bdcc9SAdriana Kobylak * extensions. 107099543e4SBrad Bishop * @param[in] ibmCompatibleSystem The names property of an instance of 108749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible 10996442c88SManojkiran Eda * @param[out] extensions the host firmware blob file extensions 110099543e4SBrad Bishop * @return true if an entry was found, otherwise false 111099543e4SBrad Bishop */ 112099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem( 113099543e4SBrad Bishop const std::map<std::string, std::vector<std::string>>& extensionMap, 114099543e4SBrad Bishop const std::vector<std::string>& ibmCompatibleSystem, 115099543e4SBrad Bishop std::vector<std::string>& extensions) 116099543e4SBrad Bishop { 117099543e4SBrad Bishop for (const auto& system : ibmCompatibleSystem) 118099543e4SBrad Bishop { 119099543e4SBrad Bishop auto extensionMapIterator = extensionMap.find(system); 120099543e4SBrad Bishop if (extensionMapIterator != extensionMap.end()) 121099543e4SBrad Bishop { 122099543e4SBrad Bishop extensions = extensionMapIterator->second; 123099543e4SBrad Bishop return true; 124099543e4SBrad Bishop } 125099543e4SBrad Bishop } 126099543e4SBrad Bishop 127099543e4SBrad Bishop return false; 128099543e4SBrad Bishop } 129099543e4SBrad Bishop 130099543e4SBrad Bishop /** 131099543e4SBrad Bishop * @brief Write host firmware well-known name 132099543e4SBrad Bishop * 133099543e4SBrad Bishop * A wrapper around std::filesystem::create_symlink that avoids EEXIST by 134099543e4SBrad Bishop * deleting any pre-existing file. 135099543e4SBrad Bishop * 136099543e4SBrad Bishop * @param[in] linkTarget The link target argument to 137099543e4SBrad Bishop * std::filesystem::create_symlink 138099543e4SBrad Bishop * @param[in] linkPath The link path argument to std::filesystem::create_symlink 139099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 140099543e4SBrad Bishop */ 141099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget, 142099543e4SBrad Bishop const std::filesystem::path& linkPath, 143099543e4SBrad Bishop const ErrorCallbackType& errorCallback) 144099543e4SBrad Bishop { 145099543e4SBrad Bishop std::error_code ec; 146099543e4SBrad Bishop 147099543e4SBrad Bishop // remove files with the same name as the symlink to be created, 148099543e4SBrad Bishop // otherwise symlink will fail with EEXIST. 149099543e4SBrad Bishop if (!std::filesystem::remove(linkPath, ec)) 150099543e4SBrad Bishop { 151099543e4SBrad Bishop if (ec) 152099543e4SBrad Bishop { 153099543e4SBrad Bishop makeCallback(errorCallback, linkPath, ec); 154099543e4SBrad Bishop return; 155099543e4SBrad Bishop } 156099543e4SBrad Bishop } 157099543e4SBrad Bishop 158099543e4SBrad Bishop std::filesystem::create_symlink(linkTarget, linkPath, ec); 159099543e4SBrad Bishop if (ec) 160099543e4SBrad Bishop { 161099543e4SBrad Bishop makeCallback(errorCallback, linkPath, ec); 162099543e4SBrad Bishop return; 163099543e4SBrad Bishop } 164099543e4SBrad Bishop } 165099543e4SBrad Bishop 166099543e4SBrad Bishop /** 167099543e4SBrad Bishop * @brief Find host firmware blob files that need well-known names 168099543e4SBrad Bishop * 169099543e4SBrad Bishop * The IBM host firmware runtime looks for data and/or additional code while 17096442c88SManojkiran Eda * bootstrapping in files with well-known names. findLinks uses the provided 171099543e4SBrad Bishop * extensions argument to find host firmware blob files that require a 172099543e4SBrad Bishop * well-known name. When a blob is found, issue the provided callback 173099543e4SBrad Bishop * (typically a function that will write a symlink). 174099543e4SBrad Bishop * 175099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which findLinks should 176099543e4SBrad Bishop * look for host firmware blob files that need well-known names. 17796442c88SManojkiran Eda * @param[in] extensions The extensions of the firmware blob files denote a 178099543e4SBrad Bishop * host firmware blob file requires a well-known name. 179099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 180099543e4SBrad Bishop * @param[in] linkCallback A callback made when host firmware blob files 181099543e4SBrad Bishop * needing a well known name are found. 182099543e4SBrad Bishop */ 183099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory, 184099543e4SBrad Bishop const std::vector<std::string>& extensions, 185099543e4SBrad Bishop const ErrorCallbackType& errorCallback, 186099543e4SBrad Bishop const LinkCallbackType& linkCallback) 187099543e4SBrad Bishop { 188099543e4SBrad Bishop std::error_code ec; 189f8e02429SPatrick Williams std::filesystem::directory_iterator directoryIterator( 190f8e02429SPatrick Williams hostFirmwareDirectory, ec); 191099543e4SBrad Bishop if (ec) 192099543e4SBrad Bishop { 193099543e4SBrad Bishop makeCallback(errorCallback, hostFirmwareDirectory, ec); 194099543e4SBrad Bishop return; 195099543e4SBrad Bishop } 196099543e4SBrad Bishop 1974e82bc84SAdriana Kobylak // Create a symlink for pnor.toc 1984e82bc84SAdriana Kobylak static const auto tocLid = "81e00994.lid"; 1994e82bc84SAdriana Kobylak auto tocLidPath = hostFirmwareDirectory / tocLid; 2004e82bc84SAdriana Kobylak if (std::filesystem::exists(tocLidPath)) 2014e82bc84SAdriana Kobylak { 2024e82bc84SAdriana Kobylak auto tocLinkPath = hostFirmwareDirectory / tocName; 2034e82bc84SAdriana Kobylak makeCallback(linkCallback, tocLid, tocLinkPath, errorCallback); 2044e82bc84SAdriana Kobylak } 2054e82bc84SAdriana Kobylak 206099543e4SBrad Bishop for (; directoryIterator != std::filesystem::end(directoryIterator); 207099543e4SBrad Bishop directoryIterator.increment(ec)) 208099543e4SBrad Bishop { 209099543e4SBrad Bishop const auto& file = directoryIterator->path(); 210099543e4SBrad Bishop if (ec) 211099543e4SBrad Bishop { 212099543e4SBrad Bishop makeCallback(errorCallback, file, ec); 213099543e4SBrad Bishop // quit here if the increment call failed otherwise the loop may 214099543e4SBrad Bishop // never finish 215099543e4SBrad Bishop break; 216099543e4SBrad Bishop } 217099543e4SBrad Bishop 218099543e4SBrad Bishop if (std::find(extensions.begin(), extensions.end(), file.extension()) == 219099543e4SBrad Bishop extensions.end()) 220099543e4SBrad Bishop { 221099543e4SBrad Bishop // this file doesn't have an extension or doesn't match any of the 222099543e4SBrad Bishop // provided extensions. 223099543e4SBrad Bishop continue; 224099543e4SBrad Bishop } 225099543e4SBrad Bishop 226099543e4SBrad Bishop auto linkPath(file.parent_path().append( 227099543e4SBrad Bishop static_cast<const std::string&>(file.stem()))); 228099543e4SBrad Bishop 229099543e4SBrad Bishop makeCallback(linkCallback, file.filename(), linkPath, errorCallback); 230099543e4SBrad Bishop } 231099543e4SBrad Bishop } 232099543e4SBrad Bishop 233099543e4SBrad Bishop /** 234ae0998f1SAdriana Kobylak * @brief Parse the elements json file and construct a string with the data to 235ae0998f1SAdriana Kobylak * be used to update the bios attribute table. 236ae0998f1SAdriana Kobylak * 237ae0998f1SAdriana Kobylak * @param[in] elementsJsonFilePath - The path to the host firmware json file. 238ae0998f1SAdriana Kobylak * @param[in] extensions - The extensions of the firmware blob files. 23953a27395SAdriana Kobylak */ 240ae0998f1SAdriana Kobylak std::string getBiosAttrStr(const std::filesystem::path& elementsJsonFilePath, 241ae0998f1SAdriana Kobylak const std::vector<std::string>& extensions) 24256f538caSAdriana Kobylak { 24356f538caSAdriana Kobylak std::string biosAttrStr{}; 24456f538caSAdriana Kobylak 245ae0998f1SAdriana Kobylak std::ifstream jsonFile(elementsJsonFilePath.c_str()); 246ae0998f1SAdriana Kobylak if (!jsonFile) 247ae0998f1SAdriana Kobylak { 248ae0998f1SAdriana Kobylak return {}; 249ae0998f1SAdriana Kobylak } 250ae0998f1SAdriana Kobylak 251ae0998f1SAdriana Kobylak std::map<std::string, std::string> attr; 252ae0998f1SAdriana Kobylak auto data = nlohmann::json::parse(jsonFile, nullptr, false); 253ae0998f1SAdriana Kobylak if (data.is_discarded()) 254ae0998f1SAdriana Kobylak { 255ae0998f1SAdriana Kobylak log<level::ERR>("Error parsing JSON file", 256ae0998f1SAdriana Kobylak entry("FILE=%s", elementsJsonFilePath.c_str())); 257ae0998f1SAdriana Kobylak return {}; 258ae0998f1SAdriana Kobylak } 259ae0998f1SAdriana Kobylak 260ae0998f1SAdriana Kobylak // .get requires a non-const iterator 261ae0998f1SAdriana Kobylak for (auto& iter : data["lids"]) 262ae0998f1SAdriana Kobylak { 263ae0998f1SAdriana Kobylak std::string name{}; 264ae0998f1SAdriana Kobylak std::string lid{}; 265ae0998f1SAdriana Kobylak 266ae0998f1SAdriana Kobylak try 267ae0998f1SAdriana Kobylak { 268ae0998f1SAdriana Kobylak name = iter["element_name"].get<std::string>(); 269ae0998f1SAdriana Kobylak lid = iter["short_lid_name"].get<std::string>(); 270ae0998f1SAdriana Kobylak } 27197a709b0SPatrick Williams catch (const std::exception& e) 272ae0998f1SAdriana Kobylak { 273ae0998f1SAdriana Kobylak // Possibly the element or lid name field was not found 274ae0998f1SAdriana Kobylak log<level::ERR>("Error reading JSON field", 275ae0998f1SAdriana Kobylak entry("FILE=%s", elementsJsonFilePath.c_str()), 276ae0998f1SAdriana Kobylak entry("ERROR=%s", e.what())); 277ae0998f1SAdriana Kobylak continue; 278ae0998f1SAdriana Kobylak } 279ae0998f1SAdriana Kobylak 280ae0998f1SAdriana Kobylak // The elements with the ipl extension have higher priority. Therefore 2819cbc06b1SAdriana Kobylak // Use operator[] to overwrite value if an entry for it already exists, 2829cbc06b1SAdriana Kobylak // and create a second entry with key name element_RT to specify it as 2839cbc06b1SAdriana Kobylak // a runtime element. 2849cbc06b1SAdriana Kobylak // Ex: if the JSON contains an entry A.P10 with lid name X, it'll create 2859cbc06b1SAdriana Kobylak // and try A=X. If the JSON also contained an entry A.P10.iplTime with 2869cbc06b1SAdriana Kobylak // lid name Y, the A entry would be overwritten to be A=Y and a second 2879cbc06b1SAdriana Kobylak // entry A_RT=X would be created. 288ae0998f1SAdriana Kobylak constexpr auto iplExtension = ".iplTime"; 2899cbc06b1SAdriana Kobylak constexpr auto runtimeSuffix = "_RT"; 290ae0998f1SAdriana Kobylak std::filesystem::path path(name); 291ae0998f1SAdriana Kobylak if (path.extension() == iplExtension) 292ae0998f1SAdriana Kobylak { 293ae0998f1SAdriana Kobylak // Some elements have an additional extension, ex: .P10.iplTime 294ae0998f1SAdriana Kobylak // Strip off the ipl extension with stem(), then check if there is 295ae0998f1SAdriana Kobylak // an additional extension with extension(). 296ae0998f1SAdriana Kobylak if (!path.stem().extension().empty()) 297ae0998f1SAdriana Kobylak { 298ae0998f1SAdriana Kobylak // Check if the extension matches the extensions for this system 299ae0998f1SAdriana Kobylak if (std::find(extensions.begin(), extensions.end(), 300ae0998f1SAdriana Kobylak path.stem().extension()) == extensions.end()) 301ae0998f1SAdriana Kobylak { 302ae0998f1SAdriana Kobylak continue; 303ae0998f1SAdriana Kobylak } 304ae0998f1SAdriana Kobylak } 305ae0998f1SAdriana Kobylak // Get the element name without extensions by calling stem() twice 306ae0998f1SAdriana Kobylak // since stem() returns the base name if no periods are found. 307ae0998f1SAdriana Kobylak // Therefore both "element.P10" and "element.P10.iplTime" would 308ae0998f1SAdriana Kobylak // become "element". 3099cbc06b1SAdriana Kobylak auto keyName = path.stem().stem(); 3109cbc06b1SAdriana Kobylak auto attrIt = attr.find(keyName); 3119cbc06b1SAdriana Kobylak if (attrIt != attr.end()) 3129cbc06b1SAdriana Kobylak { 3139cbc06b1SAdriana Kobylak // Copy the existing entry to a runtime entry 3149cbc06b1SAdriana Kobylak auto runtimeKeyName = keyName.string() + runtimeSuffix; 3159cbc06b1SAdriana Kobylak attr.insert({runtimeKeyName, attrIt->second}); 3169cbc06b1SAdriana Kobylak } 31796442c88SManojkiran Eda // Overwrite the existing element with the ipl entry 3189cbc06b1SAdriana Kobylak attr[keyName] = lid; 319ae0998f1SAdriana Kobylak continue; 320ae0998f1SAdriana Kobylak } 321ae0998f1SAdriana Kobylak 322ae0998f1SAdriana Kobylak // Process all other extensions. The extension should match the list of 323ae0998f1SAdriana Kobylak // supported extensions for this system. Use .insert() to only add 324ae0998f1SAdriana Kobylak // entries that do not exist, so to not overwrite the values that may 325ae0998f1SAdriana Kobylak // had been added that had the ipl extension. 326ae0998f1SAdriana Kobylak if (std::find(extensions.begin(), extensions.end(), path.extension()) != 327ae0998f1SAdriana Kobylak extensions.end()) 328ae0998f1SAdriana Kobylak { 3299cbc06b1SAdriana Kobylak auto keyName = path.stem(); 3309cbc06b1SAdriana Kobylak auto attrIt = attr.find(keyName); 3319cbc06b1SAdriana Kobylak if (attrIt != attr.end()) 3329cbc06b1SAdriana Kobylak { 3339cbc06b1SAdriana Kobylak // The existing entry is an ipl entry, therefore create this 3349cbc06b1SAdriana Kobylak // entry as a runtime one. 3359cbc06b1SAdriana Kobylak auto runtimeKeyName = keyName.string() + runtimeSuffix; 3369cbc06b1SAdriana Kobylak attr.insert({runtimeKeyName, lid}); 3379cbc06b1SAdriana Kobylak } 3389cbc06b1SAdriana Kobylak else 3399cbc06b1SAdriana Kobylak { 340ae0998f1SAdriana Kobylak attr.insert({path.stem(), lid}); 341ae0998f1SAdriana Kobylak } 342ae0998f1SAdriana Kobylak } 3439cbc06b1SAdriana Kobylak } 344ae0998f1SAdriana Kobylak for (const auto& a : attr) 345ae0998f1SAdriana Kobylak { 346ae0998f1SAdriana Kobylak // Build the bios attribute string with format: 347ae0998f1SAdriana Kobylak // "element1=lid1,element2=lid2,elementN=lidN," 348ae0998f1SAdriana Kobylak biosAttrStr += a.first + "=" + a.second + ","; 3495dc5d6ccSAdriana Kobylak 3505dc5d6ccSAdriana Kobylak std::error_code ec; 3515dc5d6ccSAdriana Kobylak auto lidName = a.second + ".lid"; 352*f3b0c288SAdriana Kobylak auto elementFilePath = 353*f3b0c288SAdriana Kobylak std::filesystem::path("/media/hostfw/running") / a.first; 354*f3b0c288SAdriana Kobylak 355*f3b0c288SAdriana Kobylak // Remove the symlink if the target does not match so that it gets 356*f3b0c288SAdriana Kobylak // recreated. Ignore pnor.toc, this symlink is manually created by the 357*f3b0c288SAdriana Kobylak // function findLinks(). 358*f3b0c288SAdriana Kobylak if ((a.first != tocName) && 359*f3b0c288SAdriana Kobylak std::filesystem::is_symlink(elementFilePath, ec)) 360*f3b0c288SAdriana Kobylak { 361*f3b0c288SAdriana Kobylak auto target = std::filesystem::read_symlink(elementFilePath, ec); 362*f3b0c288SAdriana Kobylak if (target != lidName) 363*f3b0c288SAdriana Kobylak { 364*f3b0c288SAdriana Kobylak log<level::INFO>("Removing mismatched symlilnk", 365*f3b0c288SAdriana Kobylak entry("LINK=%s", elementFilePath.c_str()), 366*f3b0c288SAdriana Kobylak entry("TARGET=%s", target.c_str()), 367*f3b0c288SAdriana Kobylak entry("EXPECTED:%s", lidName.c_str())); 368*f3b0c288SAdriana Kobylak std::filesystem::remove(elementFilePath, ec); 369*f3b0c288SAdriana Kobylak } 370*f3b0c288SAdriana Kobylak } 371*f3b0c288SAdriana Kobylak 372*f3b0c288SAdriana Kobylak // Create symlinks from the hostfw elements to their corresponding 373*f3b0c288SAdriana Kobylak // lid files if they don't exist 374*f3b0c288SAdriana Kobylak if (!std::filesystem::exists(elementFilePath)) 375*f3b0c288SAdriana Kobylak { 3765dc5d6ccSAdriana Kobylak std::filesystem::create_symlink(lidName, elementFilePath, ec); 3775dc5d6ccSAdriana Kobylak if (ec) 3785dc5d6ccSAdriana Kobylak { 3795dc5d6ccSAdriana Kobylak log<level::ERR>("Error creating symlink", 3805dc5d6ccSAdriana Kobylak entry("TARGET=%s", lidName.c_str()), 3815dc5d6ccSAdriana Kobylak entry("LINK=%s", elementFilePath.c_str())); 3825dc5d6ccSAdriana Kobylak } 3835dc5d6ccSAdriana Kobylak } 384ae0998f1SAdriana Kobylak } 385ae0998f1SAdriana Kobylak 386a38f6e65SGeorge Liu // Delete the last comma of the bios attribute string 387a38f6e65SGeorge Liu if (biosAttrStr.back() == ',') 388a38f6e65SGeorge Liu { 389a38f6e65SGeorge Liu return biosAttrStr.substr(0, biosAttrStr.length() - 1); 390a38f6e65SGeorge Liu } 391a38f6e65SGeorge Liu 392ae0998f1SAdriana Kobylak return biosAttrStr; 393ae0998f1SAdriana Kobylak } 394ae0998f1SAdriana Kobylak 395ae0998f1SAdriana Kobylak /** 396ae0998f1SAdriana Kobylak * @brief Set the bios attribute table with details of the host firmware data 397ae0998f1SAdriana Kobylak * for this system. 398ae0998f1SAdriana Kobylak * 399ae0998f1SAdriana Kobylak * @param[in] elementsJsonFilePath - The path to the host firmware json file. 40096442c88SManojkiran Eda * @param[in] extensions - The extensions of the firmware blob files. 401ae0998f1SAdriana Kobylak */ 402ae0998f1SAdriana Kobylak void setBiosAttr(const std::filesystem::path& elementsJsonFilePath, 403ae0998f1SAdriana Kobylak const std::vector<std::string>& extensions) 404ae0998f1SAdriana Kobylak { 405ae0998f1SAdriana Kobylak auto biosAttrStr = getBiosAttrStr(elementsJsonFilePath, extensions); 406ae0998f1SAdriana Kobylak 40756f538caSAdriana Kobylak constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager"; 40856f538caSAdriana Kobylak constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager"; 40956f538caSAdriana Kobylak constexpr auto dbusAttrName = "hb_lid_ids"; 41056f538caSAdriana Kobylak constexpr auto dbusAttrType = 41156f538caSAdriana Kobylak "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String"; 41256f538caSAdriana Kobylak 41356f538caSAdriana Kobylak using PendingAttributesType = std::vector<std::pair< 41456f538caSAdriana Kobylak std::string, std::tuple<std::string, std::variant<std::string>>>>; 41556f538caSAdriana Kobylak PendingAttributesType pendingAttributes; 41656f538caSAdriana Kobylak pendingAttributes.emplace_back(std::make_pair( 41756f538caSAdriana Kobylak dbusAttrName, std::make_tuple(dbusAttrType, biosAttrStr))); 41856f538caSAdriana Kobylak 41956f538caSAdriana Kobylak auto bus = sdbusplus::bus::new_default(); 42056f538caSAdriana Kobylak auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 42156f538caSAdriana Kobylak MAPPER_INTERFACE, "GetObject"); 42256f538caSAdriana Kobylak method.append(biosConfigPath, std::vector<std::string>({biosConfigIntf})); 42356f538caSAdriana Kobylak std::vector<std::pair<std::string, std::vector<std::string>>> response; 42456f538caSAdriana Kobylak try 42556f538caSAdriana Kobylak { 42656f538caSAdriana Kobylak auto reply = bus.call(method); 42756f538caSAdriana Kobylak reply.read(response); 42856f538caSAdriana Kobylak if (response.empty()) 42956f538caSAdriana Kobylak { 4302b78eb0eSAdriana Kobylak log<level::INFO>("Error reading mapper response", 43156f538caSAdriana Kobylak entry("PATH=%s", biosConfigPath), 43256f538caSAdriana Kobylak entry("INTERFACE=%s", biosConfigIntf)); 4332b78eb0eSAdriana Kobylak throw sdbusplus::xyz::openbmc_project::Common::Error:: 4342b78eb0eSAdriana Kobylak InternalFailure(); 43556f538caSAdriana Kobylak } 43656f538caSAdriana Kobylak auto method = bus.new_method_call((response.begin()->first).c_str(), 43756f538caSAdriana Kobylak biosConfigPath, 43856f538caSAdriana Kobylak SYSTEMD_PROPERTY_INTERFACE, "Set"); 43956f538caSAdriana Kobylak method.append(biosConfigIntf, "PendingAttributes", 44056f538caSAdriana Kobylak std::variant<PendingAttributesType>(pendingAttributes)); 44156f538caSAdriana Kobylak bus.call(method); 44256f538caSAdriana Kobylak } 4430dea1992SPatrick Williams catch (const sdbusplus::exception_t& e) 44456f538caSAdriana Kobylak { 4452b78eb0eSAdriana Kobylak log<level::INFO>("Error setting the bios attribute", 44656f538caSAdriana Kobylak entry("ERROR=%s", e.what()), 44756f538caSAdriana Kobylak entry("ATTRIBUTE=%s", dbusAttrName)); 4482b78eb0eSAdriana Kobylak throw; 44956f538caSAdriana Kobylak } 45056f538caSAdriana Kobylak } 45153a27395SAdriana Kobylak 45253a27395SAdriana Kobylak /** 453099543e4SBrad Bishop * @brief Make callbacks on 454749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible instances. 455099543e4SBrad Bishop * 456749bdcc9SAdriana Kobylak * Look for an instance of xyz.openbmc_project.Inventory.Decorator.Compatible in 457749bdcc9SAdriana Kobylak * the provided argument and if found, issue the provided callback. 458099543e4SBrad Bishop * 459099543e4SBrad Bishop * @param[in] interfacesAndProperties the interfaces in which to look for an 460749bdcc9SAdriana Kobylak * instance of xyz.openbmc_project.Inventory.Decorator.Compatible 461099543e4SBrad Bishop * @param[in] callback the user callback to make if 462749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible is found in 463099543e4SBrad Bishop * interfacesAndProperties 464099543e4SBrad Bishop * @return true if interfacesAndProperties contained an instance of 465749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible, false otherwise 466099543e4SBrad Bishop */ 467f8e02429SPatrick Williams bool maybeCall( 468f8e02429SPatrick Williams const std::map< 469f8e02429SPatrick Williams std::string, 470f8e02429SPatrick Williams std::map<std::string, std::variant<std::vector<std::string>>>>& 471099543e4SBrad Bishop interfacesAndProperties, 472099543e4SBrad Bishop const MaybeCallCallbackType& callback) 473099543e4SBrad Bishop { 474099543e4SBrad Bishop using namespace std::string_literals; 475099543e4SBrad Bishop 476099543e4SBrad Bishop static const auto interfaceName = 477749bdcc9SAdriana Kobylak "xyz.openbmc_project.Inventory.Decorator.Compatible"s; 478099543e4SBrad Bishop auto interfaceIterator = interfacesAndProperties.find(interfaceName); 479099543e4SBrad Bishop if (interfaceIterator == interfacesAndProperties.cend()) 480099543e4SBrad Bishop { 481749bdcc9SAdriana Kobylak // Compatible interface not found, so instruct the caller to keep 482749bdcc9SAdriana Kobylak // waiting or try again later. 483099543e4SBrad Bishop return false; 484099543e4SBrad Bishop } 485099543e4SBrad Bishop auto propertyIterator = interfaceIterator->second.find("Names"s); 486099543e4SBrad Bishop if (propertyIterator == interfaceIterator->second.cend()) 487099543e4SBrad Bishop { 488099543e4SBrad Bishop // The interface exists but the property doesn't. This is a bug in the 489749bdcc9SAdriana Kobylak // Compatible implementation. The caller should not try again. 490099543e4SBrad Bishop std::cerr << "Names property not implemented on " << interfaceName 491099543e4SBrad Bishop << "\n"; 492099543e4SBrad Bishop return true; 493099543e4SBrad Bishop } 494099543e4SBrad Bishop 495099543e4SBrad Bishop const auto& ibmCompatibleSystem = 496099543e4SBrad Bishop std::get<std::vector<std::string>>(propertyIterator->second); 497099543e4SBrad Bishop if (callback) 498099543e4SBrad Bishop { 4992b78eb0eSAdriana Kobylak try 5002b78eb0eSAdriana Kobylak { 501099543e4SBrad Bishop callback(ibmCompatibleSystem); 502099543e4SBrad Bishop } 5030dea1992SPatrick Williams catch (const sdbusplus::exception_t& e) 5042b78eb0eSAdriana Kobylak { 5052b78eb0eSAdriana Kobylak return false; 5062b78eb0eSAdriana Kobylak } 5072b78eb0eSAdriana Kobylak } 508099543e4SBrad Bishop 509749bdcc9SAdriana Kobylak // Compatible found and callback issued. 510099543e4SBrad Bishop return true; 511099543e4SBrad Bishop } 512099543e4SBrad Bishop 513099543e4SBrad Bishop /** 514099543e4SBrad Bishop * @brief Make callbacks on 515749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible instances. 516099543e4SBrad Bishop * 517749bdcc9SAdriana Kobylak * Look for an instance ofxyz.openbmc_project.Inventory.Decorator.Compatible in 518749bdcc9SAdriana Kobylak * the provided argument and if found, issue the provided callback. 519099543e4SBrad Bishop * 520099543e4SBrad Bishop * @param[in] message the DBus message in which to look for an instance of 521749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible 522099543e4SBrad Bishop * @param[in] callback the user callback to make if 523749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible is found in message 524099543e4SBrad Bishop * @return true if message contained an instance of 525749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible, false otherwise 526099543e4SBrad Bishop */ 5270dea1992SPatrick Williams bool maybeCallMessage(sdbusplus::message_t& message, 528099543e4SBrad Bishop const MaybeCallCallbackType& callback) 529099543e4SBrad Bishop { 530099543e4SBrad Bishop std::map<std::string, 531099543e4SBrad Bishop std::map<std::string, std::variant<std::vector<std::string>>>> 532099543e4SBrad Bishop interfacesAndProperties; 533099543e4SBrad Bishop sdbusplus::message::object_path _; 534099543e4SBrad Bishop message.read(_, interfacesAndProperties); 535099543e4SBrad Bishop return maybeCall(interfacesAndProperties, callback); 536099543e4SBrad Bishop } 537099543e4SBrad Bishop 538099543e4SBrad Bishop /** 539099543e4SBrad Bishop * @brief Determine system support for host firmware well-known names. 540099543e4SBrad Bishop * 541099543e4SBrad Bishop * Using the provided extensionMap and 542749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible, determine if well-known 54396442c88SManojkiran Eda * names for host firmware blob files are necessary and if so, create them. 544099543e4SBrad Bishop * 545099543e4SBrad Bishop * @param[in] extensionMap a map of 546749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file 547749bdcc9SAdriana Kobylak * extensions. 548749bdcc9SAdriana Kobylak * @param[in] hostFirmwareDirectory The directory in which findLinks should look 549749bdcc9SAdriana Kobylak * for host firmware blob files that need well-known names. 550099543e4SBrad Bishop * @param[in] ibmCompatibleSystem The names property of an instance of 551749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible 552099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 553099543e4SBrad Bishop */ 554099543e4SBrad Bishop void maybeMakeLinks( 555099543e4SBrad Bishop const std::map<std::string, std::vector<std::string>>& extensionMap, 556099543e4SBrad Bishop const std::filesystem::path& hostFirmwareDirectory, 557099543e4SBrad Bishop const std::vector<std::string>& ibmCompatibleSystem, 558099543e4SBrad Bishop const ErrorCallbackType& errorCallback) 559099543e4SBrad Bishop { 560099543e4SBrad Bishop std::vector<std::string> extensions; 561099543e4SBrad Bishop if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 562099543e4SBrad Bishop extensions)) 563099543e4SBrad Bishop { 564099543e4SBrad Bishop findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink); 565099543e4SBrad Bishop } 566099543e4SBrad Bishop } 567099543e4SBrad Bishop 568099543e4SBrad Bishop /** 56953a27395SAdriana Kobylak * @brief Determine system support for updating the bios attribute table. 57053a27395SAdriana Kobylak * 57153a27395SAdriana Kobylak * Using the provided extensionMap and 572749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible, determine if the bios 57353a27395SAdriana Kobylak * attribute table needs to be updated. 57453a27395SAdriana Kobylak * 57553a27395SAdriana Kobylak * @param[in] extensionMap a map of 576749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file 577749bdcc9SAdriana Kobylak * extensions. 578ae0998f1SAdriana Kobylak * @param[in] elementsJsonFilePath The file path to the json file 57953a27395SAdriana Kobylak * @param[in] ibmCompatibleSystem The names property of an instance of 580749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible 58153a27395SAdriana Kobylak */ 58253a27395SAdriana Kobylak void maybeSetBiosAttr( 58353a27395SAdriana Kobylak const std::map<std::string, std::vector<std::string>>& extensionMap, 584ae0998f1SAdriana Kobylak const std::filesystem::path& elementsJsonFilePath, 58553a27395SAdriana Kobylak const std::vector<std::string>& ibmCompatibleSystem) 58653a27395SAdriana Kobylak { 58753a27395SAdriana Kobylak std::vector<std::string> extensions; 58853a27395SAdriana Kobylak if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 58953a27395SAdriana Kobylak extensions)) 59053a27395SAdriana Kobylak { 5912b78eb0eSAdriana Kobylak try 5922b78eb0eSAdriana Kobylak { 593ae0998f1SAdriana Kobylak setBiosAttr(elementsJsonFilePath, extensions); 59453a27395SAdriana Kobylak } 5950dea1992SPatrick Williams catch (const sdbusplus::exception_t& e) 5962b78eb0eSAdriana Kobylak { 5972b78eb0eSAdriana Kobylak throw; 5982b78eb0eSAdriana Kobylak } 5992b78eb0eSAdriana Kobylak } 60053a27395SAdriana Kobylak } 60153a27395SAdriana Kobylak 60253a27395SAdriana Kobylak /** 603099543e4SBrad Bishop * @brief process host firmware 604099543e4SBrad Bishop * 605099543e4SBrad Bishop * Allocate a callback context and register for DBus.ObjectManager Interfaces 606099543e4SBrad Bishop * added signals from entity manager. 607099543e4SBrad Bishop * 608099543e4SBrad Bishop * Check the current entity manager object tree for a 609749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible instance (entity manager 610749bdcc9SAdriana Kobylak * will be dbus activated if it is not running). If one is found, determine if 611749bdcc9SAdriana Kobylak * symlinks need to be created and create them. Instruct the program event loop 612749bdcc9SAdriana Kobylak * to exit. 613099543e4SBrad Bishop * 614749bdcc9SAdriana Kobylak * If no instance of xyz.openbmc_project.Inventory.Decorator.Compatible is found 615749bdcc9SAdriana Kobylak * return the callback context to main, where the program will sleep until the 616749bdcc9SAdriana Kobylak * callback is invoked one or more times and instructs the program event loop to 617749bdcc9SAdriana Kobylak * exit when xyz.openbmc_project.Inventory.Decorator.Compatible is added. 618099543e4SBrad Bishop * 619099543e4SBrad Bishop * @param[in] bus a DBus client connection 620099543e4SBrad Bishop * @param[in] extensionMap a map of 621749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file 622749bdcc9SAdriana Kobylak * extensions. 623099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which processHostFirmware 624099543e4SBrad Bishop * should look for blob files. 625099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 626099543e4SBrad Bishop * @param[in] loop a program event loop 627099543e4SBrad Bishop * @return nullptr if an instance of 628749bdcc9SAdriana Kobylak * xyz.openbmc_project.Inventory.Decorator.Compatible is found, otherwise a 629099543e4SBrad Bishop * pointer to an sdbusplus match object. 630099543e4SBrad Bishop */ 631099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware( 6320dea1992SPatrick Williams sdbusplus::bus_t& bus, 633099543e4SBrad Bishop std::map<std::string, std::vector<std::string>> extensionMap, 634099543e4SBrad Bishop std::filesystem::path hostFirmwareDirectory, 635099543e4SBrad Bishop ErrorCallbackType errorCallback, sdeventplus::Event& loop) 636099543e4SBrad Bishop { 637099543e4SBrad Bishop // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't 63896442c88SManojkiran Eda // be transferred to the match callback because they are needed in the non 639099543e4SBrad Bishop // async part of this function below, so they need to be moved to the heap. 640099543e4SBrad Bishop auto pExtensionMap = 641099543e4SBrad Bishop std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 642099543e4SBrad Bishop auto pHostFirmwareDirectory = 643099543e4SBrad Bishop std::make_shared<decltype(hostFirmwareDirectory)>( 644099543e4SBrad Bishop std::move(hostFirmwareDirectory)); 645099543e4SBrad Bishop auto pErrorCallback = 646099543e4SBrad Bishop std::make_shared<decltype(errorCallback)>(std::move(errorCallback)); 647099543e4SBrad Bishop 648749bdcc9SAdriana Kobylak // register for a callback in case the Compatible interface has not yet been 649749bdcc9SAdriana Kobylak // published by entity manager. 6500dea1992SPatrick Williams auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match_t>( 651099543e4SBrad Bishop bus, 652099543e4SBrad Bishop sdbusplus::bus::match::rules::interfacesAdded() + 653099543e4SBrad Bishop sdbusplus::bus::match::rules::sender( 654099543e4SBrad Bishop "xyz.openbmc_project.EntityManager"), 655099543e4SBrad Bishop [pExtensionMap, pHostFirmwareDirectory, pErrorCallback, 656099543e4SBrad Bishop &loop](auto& message) { 657099543e4SBrad Bishop // bind the extension map, host firmware directory, and error 658099543e4SBrad Bishop // callback to the maybeMakeLinks function. 659099543e4SBrad Bishop auto maybeMakeLinksWithArgsBound = 660099543e4SBrad Bishop std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 661f8e02429SPatrick Williams std::cref(*pHostFirmwareDirectory), 662f8e02429SPatrick Williams std::placeholders::_1, std::cref(*pErrorCallback)); 663099543e4SBrad Bishop 664099543e4SBrad Bishop // if the InterfacesAdded message contains an an instance of 665f8e02429SPatrick Williams // xyz.openbmc_project.Inventory.Decorator.Compatible, check to see 666f8e02429SPatrick Williams // if links are necessary on this system and if so, create them. 667099543e4SBrad Bishop if (maybeCallMessage(message, maybeMakeLinksWithArgsBound)) 668099543e4SBrad Bishop { 669f8e02429SPatrick Williams // The Compatible interface was found and the links were created 670f8e02429SPatrick Williams // if applicable. Instruct the event loop / subcommand to exit. 671099543e4SBrad Bishop loop.exit(0); 672099543e4SBrad Bishop } 673099543e4SBrad Bishop }); 674099543e4SBrad Bishop 675099543e4SBrad Bishop // now that we'll get a callback in the event of an InterfacesAdded signal 676099543e4SBrad Bishop // (potentially containing 677749bdcc9SAdriana Kobylak // xyz.openbmc_project.Inventory.Decorator.Compatible), activate entity 678099543e4SBrad Bishop // manager if it isn't running and enumerate its objects 679099543e4SBrad Bishop auto getManagedObjects = bus.new_method_call( 68075352b42SNan Zhou "xyz.openbmc_project.EntityManager", "/xyz/openbmc_project/inventory", 681099543e4SBrad Bishop "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 682099543e4SBrad Bishop std::map<std::string, 683099543e4SBrad Bishop std::map<std::string, std::variant<std::vector<std::string>>>> 684099543e4SBrad Bishop interfacesAndProperties; 685099543e4SBrad Bishop std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 686099543e4SBrad Bishop objects; 687c79fa915SAdriana Kobylak try 688c79fa915SAdriana Kobylak { 689c79fa915SAdriana Kobylak auto reply = bus.call(getManagedObjects); 690099543e4SBrad Bishop reply.read(objects); 691c79fa915SAdriana Kobylak } 6920dea1992SPatrick Williams catch (const sdbusplus::exception_t& e) 693c79fa915SAdriana Kobylak { 694c79fa915SAdriana Kobylak // Error querying the EntityManager interface. Return the match to have 695c79fa915SAdriana Kobylak // the callback run if/when the interface appears in D-Bus. 696c79fa915SAdriana Kobylak return interfacesAddedMatch; 697c79fa915SAdriana Kobylak } 698099543e4SBrad Bishop 699099543e4SBrad Bishop // bind the extension map, host firmware directory, and error callback to 700099543e4SBrad Bishop // the maybeMakeLinks function. 701099543e4SBrad Bishop auto maybeMakeLinksWithArgsBound = 702099543e4SBrad Bishop std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 703099543e4SBrad Bishop std::cref(*pHostFirmwareDirectory), std::placeholders::_1, 704099543e4SBrad Bishop std::cref(*pErrorCallback)); 705099543e4SBrad Bishop 706099543e4SBrad Bishop for (const auto& pair : objects) 707099543e4SBrad Bishop { 708099543e4SBrad Bishop std::tie(std::ignore, interfacesAndProperties) = pair; 709099543e4SBrad Bishop // if interfacesAndProperties contains an an instance of 710749bdcc9SAdriana Kobylak // xyz.openbmc_project.Inventory.Decorator.Compatible, check to see if 711749bdcc9SAdriana Kobylak // links are necessary on this system and if so, create them 712099543e4SBrad Bishop if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound)) 713099543e4SBrad Bishop { 714749bdcc9SAdriana Kobylak // The Compatible interface is already on the bus and the links were 715749bdcc9SAdriana Kobylak // created if applicable. Instruct the event loop to exit. 716099543e4SBrad Bishop loop.exit(0); 717099543e4SBrad Bishop // The match object isn't needed anymore, so destroy it on return. 718099543e4SBrad Bishop return nullptr; 719099543e4SBrad Bishop } 720099543e4SBrad Bishop } 721099543e4SBrad Bishop 722749bdcc9SAdriana Kobylak // The Compatible interface has not yet been published. Move ownership of 723749bdcc9SAdriana Kobylak // the match callback to the caller. 724099543e4SBrad Bishop return interfacesAddedMatch; 725099543e4SBrad Bishop } 72653a27395SAdriana Kobylak 72753a27395SAdriana Kobylak /** 72853a27395SAdriana Kobylak * @brief Update the Bios Attribute Table 72953a27395SAdriana Kobylak * 730749bdcc9SAdriana Kobylak * If an instance of xyz.openbmc_project.Inventory.Decorator.Compatible is 73153a27395SAdriana Kobylak * found, update the Bios Attribute Table with the appropriate host firmware 73253a27395SAdriana Kobylak * data. 73353a27395SAdriana Kobylak * 73453a27395SAdriana Kobylak * @param[in] bus - D-Bus client connection. 735749bdcc9SAdriana Kobylak * @param[in] extensionMap - Map of Compatible names and host firmware file 736749bdcc9SAdriana Kobylak extensions. 737ae0998f1SAdriana Kobylak * @param[in] elementsJsonFilePath - The Path to the json file 73853a27395SAdriana Kobylak * @param[in] loop - Program event loop. 73953a27395SAdriana Kobylak * @return nullptr 74053a27395SAdriana Kobylak */ 741ebf67bf7SAdriana Kobylak std::vector<std::shared_ptr<void>> updateBiosAttrTable( 7420dea1992SPatrick Williams sdbusplus::bus_t& bus, 74353a27395SAdriana Kobylak std::map<std::string, std::vector<std::string>> extensionMap, 744ae0998f1SAdriana Kobylak std::filesystem::path elementsJsonFilePath, sdeventplus::Event& loop) 74553a27395SAdriana Kobylak { 746d0379ea5SAdriana Kobylak constexpr auto pldmPath = "/xyz/openbmc_project/pldm"; 747ebf67bf7SAdriana Kobylak constexpr auto entityManagerServiceName = 748ebf67bf7SAdriana Kobylak "xyz.openbmc_project.EntityManager"; 749d0379ea5SAdriana Kobylak 75053a27395SAdriana Kobylak auto pExtensionMap = 75153a27395SAdriana Kobylak std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 752ae0998f1SAdriana Kobylak auto pElementsJsonFilePath = 753ae0998f1SAdriana Kobylak std::make_shared<decltype(elementsJsonFilePath)>( 754ae0998f1SAdriana Kobylak std::move(elementsJsonFilePath)); 75553a27395SAdriana Kobylak 756d0379ea5SAdriana Kobylak auto maybeSetAttrWithArgsBound = 757d0379ea5SAdriana Kobylak std::bind(maybeSetBiosAttr, std::cref(*pExtensionMap), 758d0379ea5SAdriana Kobylak std::cref(*pElementsJsonFilePath), std::placeholders::_1); 759d0379ea5SAdriana Kobylak 760ebf67bf7SAdriana Kobylak std::vector<std::shared_ptr<void>> matches; 7612b78eb0eSAdriana Kobylak 7622b78eb0eSAdriana Kobylak // Entity Manager is needed to get the list of supported extensions. Add a 7632b78eb0eSAdriana Kobylak // match to monitor interfaces added in case it's not running yet. 7640dea1992SPatrick Williams matches.emplace_back(std::make_shared<sdbusplus::bus::match_t>( 765d0379ea5SAdriana Kobylak bus, 766d0379ea5SAdriana Kobylak sdbusplus::bus::match::rules::interfacesAdded() + 767d0379ea5SAdriana Kobylak sdbusplus::bus::match::rules::sender( 768d0379ea5SAdriana Kobylak "xyz.openbmc_project.EntityManager"), 769d0379ea5SAdriana Kobylak [pldmPath, pExtensionMap, pElementsJsonFilePath, 770d0379ea5SAdriana Kobylak maybeSetAttrWithArgsBound, &loop](auto& message) { 771d0379ea5SAdriana Kobylak if (maybeCallMessage(message, maybeSetAttrWithArgsBound)) 772d0379ea5SAdriana Kobylak { 773fd4a6088SAdriana Kobylak loop.exit(0); 774d0379ea5SAdriana Kobylak } 775ebf67bf7SAdriana Kobylak })); 7762b78eb0eSAdriana Kobylak 7772b78eb0eSAdriana Kobylak // The BIOS attribute table can only be updated if PLDM is running because 7782b78eb0eSAdriana Kobylak // PLDM is the one that exposes this property. Add a match to monitor when 7792b78eb0eSAdriana Kobylak // the PLDM service starts. 7800dea1992SPatrick Williams matches.emplace_back(std::make_shared<sdbusplus::bus::match_t>( 781ebf67bf7SAdriana Kobylak bus, 782ebf67bf7SAdriana Kobylak sdbusplus::bus::match::rules::nameOwnerChanged() + 783ebf67bf7SAdriana Kobylak sdbusplus::bus::match::rules::arg0namespace( 784ebf67bf7SAdriana Kobylak "xyz.openbmc_project.PLDM"), 785ebf67bf7SAdriana Kobylak [pExtensionMap, pElementsJsonFilePath, maybeSetAttrWithArgsBound, 786ebf67bf7SAdriana Kobylak &loop](auto& message) { 787ebf67bf7SAdriana Kobylak std::string name; 788ebf67bf7SAdriana Kobylak std::string oldOwner; 789ebf67bf7SAdriana Kobylak std::string newOwner; 790ebf67bf7SAdriana Kobylak message.read(name, oldOwner, newOwner); 791ebf67bf7SAdriana Kobylak 792ebf67bf7SAdriana Kobylak if (newOwner.empty()) 793ebf67bf7SAdriana Kobylak { 794ebf67bf7SAdriana Kobylak return; 795ebf67bf7SAdriana Kobylak } 796ebf67bf7SAdriana Kobylak 797ebf67bf7SAdriana Kobylak auto bus = sdbusplus::bus::new_default(); 798ebf67bf7SAdriana Kobylak InterfacesPropertiesMap interfacesAndProperties; 79975352b42SNan Zhou auto objects = getManagedObjects(bus, entityManagerServiceName, 80075352b42SNan Zhou "/xyz/openbmc_project/inventory"); 801ebf67bf7SAdriana Kobylak for (const auto& pair : objects) 802ebf67bf7SAdriana Kobylak { 803ebf67bf7SAdriana Kobylak std::tie(std::ignore, interfacesAndProperties) = pair; 804f8e02429SPatrick Williams if (maybeCall(interfacesAndProperties, 805f8e02429SPatrick Williams maybeSetAttrWithArgsBound)) 806ebf67bf7SAdriana Kobylak { 807ebf67bf7SAdriana Kobylak loop.exit(0); 808ebf67bf7SAdriana Kobylak } 809ebf67bf7SAdriana Kobylak } 810ebf67bf7SAdriana Kobylak })); 811d0379ea5SAdriana Kobylak 812ebf67bf7SAdriana Kobylak InterfacesPropertiesMap interfacesAndProperties; 81375352b42SNan Zhou auto objects = getManagedObjects(bus, entityManagerServiceName, 81475352b42SNan Zhou "/xyz/openbmc_project/inventory"); 81553a27395SAdriana Kobylak for (const auto& pair : objects) 81653a27395SAdriana Kobylak { 81753a27395SAdriana Kobylak std::tie(std::ignore, interfacesAndProperties) = pair; 81853a27395SAdriana Kobylak if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound)) 81953a27395SAdriana Kobylak { 820d0379ea5SAdriana Kobylak loop.exit(0); 821ebf67bf7SAdriana Kobylak return {}; 82253a27395SAdriana Kobylak } 82353a27395SAdriana Kobylak } 82453a27395SAdriana Kobylak 825ebf67bf7SAdriana Kobylak return matches; 82653a27395SAdriana Kobylak } 82753a27395SAdriana Kobylak 828099543e4SBrad Bishop } // namespace process_hostfirmware 829099543e4SBrad Bishop } // namespace functions 830