1099543e4SBrad Bishop // SPDX-License-Identifier: Apache-2.0 2099543e4SBrad Bishop 3099543e4SBrad Bishop /**@file functions.cpp*/ 4099543e4SBrad Bishop 5099543e4SBrad Bishop #include "functions.hpp" 6099543e4SBrad Bishop 7099543e4SBrad Bishop #include <sdbusplus/bus.hpp> 8099543e4SBrad Bishop #include <sdbusplus/bus/match.hpp> 9c79fa915SAdriana Kobylak #include <sdbusplus/exception.hpp> 10099543e4SBrad Bishop #include <sdbusplus/message.hpp> 11099543e4SBrad Bishop #include <sdeventplus/event.hpp> 12099543e4SBrad Bishop 13099543e4SBrad Bishop #include <filesystem> 14099543e4SBrad Bishop #include <functional> 15099543e4SBrad Bishop #include <iostream> 16099543e4SBrad Bishop #include <map> 17099543e4SBrad Bishop #include <memory> 18099543e4SBrad Bishop #include <string> 19099543e4SBrad Bishop #include <variant> 20099543e4SBrad Bishop #include <vector> 21099543e4SBrad Bishop 22099543e4SBrad Bishop namespace functions 23099543e4SBrad Bishop { 24099543e4SBrad Bishop namespace process_hostfirmware 25099543e4SBrad Bishop { 26099543e4SBrad Bishop 27099543e4SBrad Bishop /** 28099543e4SBrad Bishop * @brief Issue callbacks safely 29099543e4SBrad Bishop * 30099543e4SBrad Bishop * std::function can be empty, so this wrapper method checks for that prior to 31099543e4SBrad Bishop * calling it to avoid std::bad_function_call 32099543e4SBrad Bishop * 33099543e4SBrad Bishop * @tparam Sig the types of the std::function arguments 34099543e4SBrad Bishop * @tparam Args the deduced argument types 35099543e4SBrad Bishop * @param[in] callback the callback being wrapped 36099543e4SBrad Bishop * @param[in] args the callback arguments 37099543e4SBrad Bishop */ 38099543e4SBrad Bishop template <typename... Sig, typename... Args> 39099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args) 40099543e4SBrad Bishop { 41099543e4SBrad Bishop if (callback) 42099543e4SBrad Bishop { 43099543e4SBrad Bishop callback(std::forward<Args>(args)...); 44099543e4SBrad Bishop } 45099543e4SBrad Bishop } 46099543e4SBrad Bishop 47099543e4SBrad Bishop /** 48099543e4SBrad Bishop * @brief Get file extensions for IBMCompatibleSystem 49099543e4SBrad Bishop * 50099543e4SBrad Bishop * IBM host firmware can be deployed as blobs (files) in a filesystem. Host 51099543e4SBrad Bishop * firmware blobs for different values of 52099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with 53099543e4SBrad Bishop * different filename extensions. getExtensionsForIbmCompatibleSystem 54099543e4SBrad Bishop * maintains the mapping from a given value of 55099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of 56099543e4SBrad Bishop * filename extensions. 57099543e4SBrad Bishop * 58099543e4SBrad Bishop * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and 59099543e4SBrad Bishop * the extensions parameter is reset with the map entry. If no mapping is 60099543e4SBrad Bishop * found getExtensionsForIbmCompatibleSystem returns false and extensions is 61099543e4SBrad Bishop * unmodified. 62099543e4SBrad Bishop * 63099543e4SBrad Bishop * @param[in] extensionMap a map of 64099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 65099543e4SBrad Bishop * file extensions. 66099543e4SBrad Bishop * @param[in] ibmCompatibleSystem The names property of an instance of 67099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem 68099543e4SBrad Bishop * @param[out] extentions the host firmware blob file extensions 69099543e4SBrad Bishop * @return true if an entry was found, otherwise false 70099543e4SBrad Bishop */ 71099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem( 72099543e4SBrad Bishop const std::map<std::string, std::vector<std::string>>& extensionMap, 73099543e4SBrad Bishop const std::vector<std::string>& ibmCompatibleSystem, 74099543e4SBrad Bishop std::vector<std::string>& extensions) 75099543e4SBrad Bishop { 76099543e4SBrad Bishop for (const auto& system : ibmCompatibleSystem) 77099543e4SBrad Bishop { 78099543e4SBrad Bishop auto extensionMapIterator = extensionMap.find(system); 79099543e4SBrad Bishop if (extensionMapIterator != extensionMap.end()) 80099543e4SBrad Bishop { 81099543e4SBrad Bishop extensions = extensionMapIterator->second; 82099543e4SBrad Bishop return true; 83099543e4SBrad Bishop } 84099543e4SBrad Bishop } 85099543e4SBrad Bishop 86099543e4SBrad Bishop return false; 87099543e4SBrad Bishop } 88099543e4SBrad Bishop 89099543e4SBrad Bishop /** 90099543e4SBrad Bishop * @brief Write host firmware well-known name 91099543e4SBrad Bishop * 92099543e4SBrad Bishop * A wrapper around std::filesystem::create_symlink that avoids EEXIST by 93099543e4SBrad Bishop * deleting any pre-existing file. 94099543e4SBrad Bishop * 95099543e4SBrad Bishop * @param[in] linkTarget The link target argument to 96099543e4SBrad Bishop * std::filesystem::create_symlink 97099543e4SBrad Bishop * @param[in] linkPath The link path argument to std::filesystem::create_symlink 98099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 99099543e4SBrad Bishop */ 100099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget, 101099543e4SBrad Bishop const std::filesystem::path& linkPath, 102099543e4SBrad Bishop const ErrorCallbackType& errorCallback) 103099543e4SBrad Bishop { 104099543e4SBrad Bishop std::error_code ec; 105099543e4SBrad Bishop 106099543e4SBrad Bishop // remove files with the same name as the symlink to be created, 107099543e4SBrad Bishop // otherwise symlink will fail with EEXIST. 108099543e4SBrad Bishop if (!std::filesystem::remove(linkPath, ec)) 109099543e4SBrad Bishop { 110099543e4SBrad Bishop if (ec) 111099543e4SBrad Bishop { 112099543e4SBrad Bishop makeCallback(errorCallback, linkPath, ec); 113099543e4SBrad Bishop return; 114099543e4SBrad Bishop } 115099543e4SBrad Bishop } 116099543e4SBrad Bishop 117099543e4SBrad Bishop std::filesystem::create_symlink(linkTarget, linkPath, ec); 118099543e4SBrad Bishop if (ec) 119099543e4SBrad Bishop { 120099543e4SBrad Bishop makeCallback(errorCallback, linkPath, ec); 121099543e4SBrad Bishop return; 122099543e4SBrad Bishop } 123099543e4SBrad Bishop } 124099543e4SBrad Bishop 125099543e4SBrad Bishop /** 126099543e4SBrad Bishop * @brief Find host firmware blob files that need well-known names 127099543e4SBrad Bishop * 128099543e4SBrad Bishop * The IBM host firmware runtime looks for data and/or additional code while 129099543e4SBrad Bishop * bootstraping in files with well-known names. findLinks uses the provided 130099543e4SBrad Bishop * extensions argument to find host firmware blob files that require a 131099543e4SBrad Bishop * well-known name. When a blob is found, issue the provided callback 132099543e4SBrad Bishop * (typically a function that will write a symlink). 133099543e4SBrad Bishop * 134099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which findLinks should 135099543e4SBrad Bishop * look for host firmware blob files that need well-known names. 136099543e4SBrad Bishop * @param[in] extentions The extensions of the firmware blob files denote a 137099543e4SBrad Bishop * host firmware blob file requires a well-known name. 138099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 139099543e4SBrad Bishop * @param[in] linkCallback A callback made when host firmware blob files 140099543e4SBrad Bishop * needing a well known name are found. 141099543e4SBrad Bishop */ 142099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory, 143099543e4SBrad Bishop const std::vector<std::string>& extensions, 144099543e4SBrad Bishop const ErrorCallbackType& errorCallback, 145099543e4SBrad Bishop const LinkCallbackType& linkCallback) 146099543e4SBrad Bishop { 147099543e4SBrad Bishop std::error_code ec; 148099543e4SBrad Bishop std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory, 149099543e4SBrad Bishop ec); 150099543e4SBrad Bishop if (ec) 151099543e4SBrad Bishop { 152099543e4SBrad Bishop makeCallback(errorCallback, hostFirmwareDirectory, ec); 153099543e4SBrad Bishop return; 154099543e4SBrad Bishop } 155099543e4SBrad Bishop 156fdc91fa0SAdriana Kobylak // Create a symlink from HBB to the corresponding LID file if it exists 157fdc91fa0SAdriana Kobylak static const auto hbbLid = "81e0065a.lid"; 158fdc91fa0SAdriana Kobylak auto hbbLidPath = hostFirmwareDirectory / hbbLid; 159fdc91fa0SAdriana Kobylak if (std::filesystem::exists(hbbLidPath)) 160fdc91fa0SAdriana Kobylak { 161fdc91fa0SAdriana Kobylak static const auto hbbName = "HBB"; 162fdc91fa0SAdriana Kobylak auto hbbLinkPath = hostFirmwareDirectory / hbbName; 163fdc91fa0SAdriana Kobylak makeCallback(linkCallback, hbbLid, hbbLinkPath, errorCallback); 164fdc91fa0SAdriana Kobylak } 165fdc91fa0SAdriana Kobylak 166099543e4SBrad Bishop for (; directoryIterator != std::filesystem::end(directoryIterator); 167099543e4SBrad Bishop directoryIterator.increment(ec)) 168099543e4SBrad Bishop { 169099543e4SBrad Bishop const auto& file = directoryIterator->path(); 170099543e4SBrad Bishop if (ec) 171099543e4SBrad Bishop { 172099543e4SBrad Bishop makeCallback(errorCallback, file, ec); 173099543e4SBrad Bishop // quit here if the increment call failed otherwise the loop may 174099543e4SBrad Bishop // never finish 175099543e4SBrad Bishop break; 176099543e4SBrad Bishop } 177099543e4SBrad Bishop 178099543e4SBrad Bishop if (std::find(extensions.begin(), extensions.end(), file.extension()) == 179099543e4SBrad Bishop extensions.end()) 180099543e4SBrad Bishop { 181099543e4SBrad Bishop // this file doesn't have an extension or doesn't match any of the 182099543e4SBrad Bishop // provided extensions. 183099543e4SBrad Bishop continue; 184099543e4SBrad Bishop } 185099543e4SBrad Bishop 186099543e4SBrad Bishop auto linkPath(file.parent_path().append( 187099543e4SBrad Bishop static_cast<const std::string&>(file.stem()))); 188099543e4SBrad Bishop 189099543e4SBrad Bishop makeCallback(linkCallback, file.filename(), linkPath, errorCallback); 190099543e4SBrad Bishop } 191099543e4SBrad Bishop } 192099543e4SBrad Bishop 193099543e4SBrad Bishop /** 194*53a27395SAdriana Kobylak * @brief Set the bios attribute table with details of the host firmware data 195*53a27395SAdriana Kobylak * for this system. 196*53a27395SAdriana Kobylak */ 197*53a27395SAdriana Kobylak void setBiosAttr() 198*53a27395SAdriana Kobylak {} 199*53a27395SAdriana Kobylak 200*53a27395SAdriana Kobylak /** 201099543e4SBrad Bishop * @brief Make callbacks on 202099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances. 203099543e4SBrad Bishop * 204099543e4SBrad Bishop * Look for an instance of 205099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided 206099543e4SBrad Bishop * argument and if found, issue the provided callback. 207099543e4SBrad Bishop * 208099543e4SBrad Bishop * @param[in] interfacesAndProperties the interfaces in which to look for an 209099543e4SBrad Bishop * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem 210099543e4SBrad Bishop * @param[in] callback the user callback to make if 211099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in 212099543e4SBrad Bishop * interfacesAndProperties 213099543e4SBrad Bishop * @return true if interfacesAndProperties contained an instance of 214099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise 215099543e4SBrad Bishop */ 216099543e4SBrad Bishop bool maybeCall(const std::map<std::string, 217099543e4SBrad Bishop std::map<std::string, 218099543e4SBrad Bishop std::variant<std::vector<std::string>>>>& 219099543e4SBrad Bishop interfacesAndProperties, 220099543e4SBrad Bishop const MaybeCallCallbackType& callback) 221099543e4SBrad Bishop { 222099543e4SBrad Bishop using namespace std::string_literals; 223099543e4SBrad Bishop 224099543e4SBrad Bishop static const auto interfaceName = 225099543e4SBrad Bishop "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s; 226099543e4SBrad Bishop auto interfaceIterator = interfacesAndProperties.find(interfaceName); 227099543e4SBrad Bishop if (interfaceIterator == interfacesAndProperties.cend()) 228099543e4SBrad Bishop { 229099543e4SBrad Bishop // IBMCompatibleSystem interface not found, so instruct the caller to 230099543e4SBrad Bishop // keep waiting or try again later. 231099543e4SBrad Bishop return false; 232099543e4SBrad Bishop } 233099543e4SBrad Bishop auto propertyIterator = interfaceIterator->second.find("Names"s); 234099543e4SBrad Bishop if (propertyIterator == interfaceIterator->second.cend()) 235099543e4SBrad Bishop { 236099543e4SBrad Bishop // The interface exists but the property doesn't. This is a bug in the 237099543e4SBrad Bishop // IBMCompatibleSystem implementation. The caller should not try 238099543e4SBrad Bishop // again. 239099543e4SBrad Bishop std::cerr << "Names property not implemented on " << interfaceName 240099543e4SBrad Bishop << "\n"; 241099543e4SBrad Bishop return true; 242099543e4SBrad Bishop } 243099543e4SBrad Bishop 244099543e4SBrad Bishop const auto& ibmCompatibleSystem = 245099543e4SBrad Bishop std::get<std::vector<std::string>>(propertyIterator->second); 246099543e4SBrad Bishop if (callback) 247099543e4SBrad Bishop { 248099543e4SBrad Bishop callback(ibmCompatibleSystem); 249099543e4SBrad Bishop } 250099543e4SBrad Bishop 251099543e4SBrad Bishop // IBMCompatibleSystem found and callback issued. 252099543e4SBrad Bishop return true; 253099543e4SBrad Bishop } 254099543e4SBrad Bishop 255099543e4SBrad Bishop /** 256099543e4SBrad Bishop * @brief Make callbacks on 257099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances. 258099543e4SBrad Bishop * 259099543e4SBrad Bishop * Look for an instance of 260099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided 261099543e4SBrad Bishop * argument and if found, issue the provided callback. 262099543e4SBrad Bishop * 263099543e4SBrad Bishop * @param[in] message the DBus message in which to look for an instance of 264099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem 265099543e4SBrad Bishop * @param[in] callback the user callback to make if 266099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in 267099543e4SBrad Bishop * message 268099543e4SBrad Bishop * @return true if message contained an instance of 269099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise 270099543e4SBrad Bishop */ 271099543e4SBrad Bishop bool maybeCallMessage(sdbusplus::message::message& message, 272099543e4SBrad Bishop const MaybeCallCallbackType& callback) 273099543e4SBrad Bishop { 274099543e4SBrad Bishop std::map<std::string, 275099543e4SBrad Bishop std::map<std::string, std::variant<std::vector<std::string>>>> 276099543e4SBrad Bishop interfacesAndProperties; 277099543e4SBrad Bishop sdbusplus::message::object_path _; 278099543e4SBrad Bishop message.read(_, interfacesAndProperties); 279099543e4SBrad Bishop return maybeCall(interfacesAndProperties, callback); 280099543e4SBrad Bishop } 281099543e4SBrad Bishop 282099543e4SBrad Bishop /** 283099543e4SBrad Bishop * @brief Determine system support for host firmware well-known names. 284099543e4SBrad Bishop * 285099543e4SBrad Bishop * Using the provided extensionMap and 286099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if 287099543e4SBrad Bishop * well-known names for host firmare blob files are necessary and if so, create 288099543e4SBrad Bishop * them. 289099543e4SBrad Bishop * 290099543e4SBrad Bishop * @param[in] extensionMap a map of 291099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 292099543e4SBrad Bishop * file extensions. 293099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which findLinks should 294099543e4SBrad Bishop * look for host firmware blob files that need well-known names. 295099543e4SBrad Bishop * @param[in] ibmCompatibleSystem The names property of an instance of 296099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem 297099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 298099543e4SBrad Bishop */ 299099543e4SBrad Bishop void maybeMakeLinks( 300099543e4SBrad Bishop const std::map<std::string, std::vector<std::string>>& extensionMap, 301099543e4SBrad Bishop const std::filesystem::path& hostFirmwareDirectory, 302099543e4SBrad Bishop const std::vector<std::string>& ibmCompatibleSystem, 303099543e4SBrad Bishop const ErrorCallbackType& errorCallback) 304099543e4SBrad Bishop { 305099543e4SBrad Bishop std::vector<std::string> extensions; 306099543e4SBrad Bishop if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 307099543e4SBrad Bishop extensions)) 308099543e4SBrad Bishop { 309099543e4SBrad Bishop findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink); 310099543e4SBrad Bishop } 311099543e4SBrad Bishop } 312099543e4SBrad Bishop 313099543e4SBrad Bishop /** 314*53a27395SAdriana Kobylak * @brief Determine system support for updating the bios attribute table. 315*53a27395SAdriana Kobylak * 316*53a27395SAdriana Kobylak * Using the provided extensionMap and 317*53a27395SAdriana Kobylak * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if the bios 318*53a27395SAdriana Kobylak * attribute table needs to be updated. 319*53a27395SAdriana Kobylak * 320*53a27395SAdriana Kobylak * @param[in] extensionMap a map of 321*53a27395SAdriana Kobylak * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 322*53a27395SAdriana Kobylak * file extensions. 323*53a27395SAdriana Kobylak * @param[in] ibmCompatibleSystem The names property of an instance of 324*53a27395SAdriana Kobylak * xyz.openbmc_project.Configuration.IBMCompatibleSystem 325*53a27395SAdriana Kobylak */ 326*53a27395SAdriana Kobylak void maybeSetBiosAttr( 327*53a27395SAdriana Kobylak const std::map<std::string, std::vector<std::string>>& extensionMap, 328*53a27395SAdriana Kobylak const std::vector<std::string>& ibmCompatibleSystem) 329*53a27395SAdriana Kobylak { 330*53a27395SAdriana Kobylak std::vector<std::string> extensions; 331*53a27395SAdriana Kobylak if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 332*53a27395SAdriana Kobylak extensions)) 333*53a27395SAdriana Kobylak { 334*53a27395SAdriana Kobylak setBiosAttr(); 335*53a27395SAdriana Kobylak } 336*53a27395SAdriana Kobylak } 337*53a27395SAdriana Kobylak 338*53a27395SAdriana Kobylak /** 339099543e4SBrad Bishop * @brief process host firmware 340099543e4SBrad Bishop * 341099543e4SBrad Bishop * Allocate a callback context and register for DBus.ObjectManager Interfaces 342099543e4SBrad Bishop * added signals from entity manager. 343099543e4SBrad Bishop * 344099543e4SBrad Bishop * Check the current entity manager object tree for a 345099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity 346099543e4SBrad Bishop * manager will be dbus activated if it is not running). If one is found, 347099543e4SBrad Bishop * determine if symlinks need to be created and create them. Instruct the 348099543e4SBrad Bishop * program event loop to exit. 349099543e4SBrad Bishop * 350099543e4SBrad Bishop * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is 351099543e4SBrad Bishop * found return the callback context to main, where the program will sleep 352099543e4SBrad Bishop * until the callback is invoked one or more times and instructs the program 353099543e4SBrad Bishop * event loop to exit when 354099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added. 355099543e4SBrad Bishop * 356099543e4SBrad Bishop * @param[in] bus a DBus client connection 357099543e4SBrad Bishop * @param[in] extensionMap a map of 358099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 359099543e4SBrad Bishop * file extensions. 360099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which processHostFirmware 361099543e4SBrad Bishop * should look for blob files. 362099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 363099543e4SBrad Bishop * @param[in] loop a program event loop 364099543e4SBrad Bishop * @return nullptr if an instance of 365099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a 366099543e4SBrad Bishop * pointer to an sdbusplus match object. 367099543e4SBrad Bishop */ 368099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware( 369099543e4SBrad Bishop sdbusplus::bus::bus& bus, 370099543e4SBrad Bishop std::map<std::string, std::vector<std::string>> extensionMap, 371099543e4SBrad Bishop std::filesystem::path hostFirmwareDirectory, 372099543e4SBrad Bishop ErrorCallbackType errorCallback, sdeventplus::Event& loop) 373099543e4SBrad Bishop { 374099543e4SBrad Bishop // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't 375099543e4SBrad Bishop // be transfered to the match callback because they are needed in the non 376099543e4SBrad Bishop // async part of this function below, so they need to be moved to the heap. 377099543e4SBrad Bishop auto pExtensionMap = 378099543e4SBrad Bishop std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 379099543e4SBrad Bishop auto pHostFirmwareDirectory = 380099543e4SBrad Bishop std::make_shared<decltype(hostFirmwareDirectory)>( 381099543e4SBrad Bishop std::move(hostFirmwareDirectory)); 382099543e4SBrad Bishop auto pErrorCallback = 383099543e4SBrad Bishop std::make_shared<decltype(errorCallback)>(std::move(errorCallback)); 384099543e4SBrad Bishop 385099543e4SBrad Bishop // register for a callback in case the IBMCompatibleSystem interface has 386099543e4SBrad Bishop // not yet been published by entity manager. 387099543e4SBrad Bishop auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>( 388099543e4SBrad Bishop bus, 389099543e4SBrad Bishop sdbusplus::bus::match::rules::interfacesAdded() + 390099543e4SBrad Bishop sdbusplus::bus::match::rules::sender( 391099543e4SBrad Bishop "xyz.openbmc_project.EntityManager"), 392099543e4SBrad Bishop [pExtensionMap, pHostFirmwareDirectory, pErrorCallback, 393099543e4SBrad Bishop &loop](auto& message) { 394099543e4SBrad Bishop // bind the extension map, host firmware directory, and error 395099543e4SBrad Bishop // callback to the maybeMakeLinks function. 396099543e4SBrad Bishop auto maybeMakeLinksWithArgsBound = 397099543e4SBrad Bishop std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 398099543e4SBrad Bishop std::cref(*pHostFirmwareDirectory), 399099543e4SBrad Bishop std::placeholders::_1, std::cref(*pErrorCallback)); 400099543e4SBrad Bishop 401099543e4SBrad Bishop // if the InterfacesAdded message contains an an instance of 402099543e4SBrad Bishop // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to 403099543e4SBrad Bishop // see if links are necessary on this system and if so, create 404099543e4SBrad Bishop // them. 405099543e4SBrad Bishop if (maybeCallMessage(message, maybeMakeLinksWithArgsBound)) 406099543e4SBrad Bishop { 407099543e4SBrad Bishop // The IBMCompatibleSystem interface was found and the links 408099543e4SBrad Bishop // were created if applicable. Instruct the event loop / 409099543e4SBrad Bishop // subcommand to exit. 410099543e4SBrad Bishop loop.exit(0); 411099543e4SBrad Bishop } 412099543e4SBrad Bishop }); 413099543e4SBrad Bishop 414099543e4SBrad Bishop // now that we'll get a callback in the event of an InterfacesAdded signal 415099543e4SBrad Bishop // (potentially containing 416099543e4SBrad Bishop // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity 417099543e4SBrad Bishop // manager if it isn't running and enumerate its objects 418099543e4SBrad Bishop auto getManagedObjects = bus.new_method_call( 419099543e4SBrad Bishop "xyz.openbmc_project.EntityManager", "/", 420099543e4SBrad Bishop "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 421099543e4SBrad Bishop std::map<std::string, 422099543e4SBrad Bishop std::map<std::string, std::variant<std::vector<std::string>>>> 423099543e4SBrad Bishop interfacesAndProperties; 424099543e4SBrad Bishop std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 425099543e4SBrad Bishop objects; 426c79fa915SAdriana Kobylak try 427c79fa915SAdriana Kobylak { 428c79fa915SAdriana Kobylak auto reply = bus.call(getManagedObjects); 429099543e4SBrad Bishop reply.read(objects); 430c79fa915SAdriana Kobylak } 431c79fa915SAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 432c79fa915SAdriana Kobylak { 433c79fa915SAdriana Kobylak // Error querying the EntityManager interface. Return the match to have 434c79fa915SAdriana Kobylak // the callback run if/when the interface appears in D-Bus. 435c79fa915SAdriana Kobylak return interfacesAddedMatch; 436c79fa915SAdriana Kobylak } 437099543e4SBrad Bishop 438099543e4SBrad Bishop // bind the extension map, host firmware directory, and error callback to 439099543e4SBrad Bishop // the maybeMakeLinks function. 440099543e4SBrad Bishop auto maybeMakeLinksWithArgsBound = 441099543e4SBrad Bishop std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 442099543e4SBrad Bishop std::cref(*pHostFirmwareDirectory), std::placeholders::_1, 443099543e4SBrad Bishop std::cref(*pErrorCallback)); 444099543e4SBrad Bishop 445099543e4SBrad Bishop for (const auto& pair : objects) 446099543e4SBrad Bishop { 447099543e4SBrad Bishop std::tie(std::ignore, interfacesAndProperties) = pair; 448099543e4SBrad Bishop // if interfacesAndProperties contains an an instance of 449099543e4SBrad Bishop // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see 450099543e4SBrad Bishop // if links are necessary on this system and if so, create them 451099543e4SBrad Bishop if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound)) 452099543e4SBrad Bishop { 453099543e4SBrad Bishop // The IBMCompatibleSystem interface is already on the bus and the 454099543e4SBrad Bishop // links were created if applicable. Instruct the event loop to 455099543e4SBrad Bishop // exit. 456099543e4SBrad Bishop loop.exit(0); 457099543e4SBrad Bishop // The match object isn't needed anymore, so destroy it on return. 458099543e4SBrad Bishop return nullptr; 459099543e4SBrad Bishop } 460099543e4SBrad Bishop } 461099543e4SBrad Bishop 462099543e4SBrad Bishop // The IBMCompatibleSystem interface has not yet been published. Move 463099543e4SBrad Bishop // ownership of the match callback to the caller. 464099543e4SBrad Bishop return interfacesAddedMatch; 465099543e4SBrad Bishop } 466*53a27395SAdriana Kobylak 467*53a27395SAdriana Kobylak /** 468*53a27395SAdriana Kobylak * @brief Update the Bios Attribute Table 469*53a27395SAdriana Kobylak * 470*53a27395SAdriana Kobylak * If an instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is 471*53a27395SAdriana Kobylak * found, update the Bios Attribute Table with the appropriate host firmware 472*53a27395SAdriana Kobylak * data. 473*53a27395SAdriana Kobylak * 474*53a27395SAdriana Kobylak * @param[in] bus - D-Bus client connection. 475*53a27395SAdriana Kobylak * @param[in] extensionMap - Map of IBMCompatibleSystem names and host firmware 476*53a27395SAdriana Kobylak * file extensions. 477*53a27395SAdriana Kobylak * @param[in] loop - Program event loop. 478*53a27395SAdriana Kobylak * @return nullptr 479*53a27395SAdriana Kobylak */ 480*53a27395SAdriana Kobylak std::shared_ptr<void> updateBiosAttrTable( 481*53a27395SAdriana Kobylak sdbusplus::bus::bus& bus, 482*53a27395SAdriana Kobylak std::map<std::string, std::vector<std::string>> extensionMap, 483*53a27395SAdriana Kobylak sdeventplus::Event& loop) 484*53a27395SAdriana Kobylak { 485*53a27395SAdriana Kobylak auto pExtensionMap = 486*53a27395SAdriana Kobylak std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 487*53a27395SAdriana Kobylak 488*53a27395SAdriana Kobylak auto getManagedObjects = bus.new_method_call( 489*53a27395SAdriana Kobylak "xyz.openbmc_project.EntityManager", "/", 490*53a27395SAdriana Kobylak "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 491*53a27395SAdriana Kobylak std::map<std::string, 492*53a27395SAdriana Kobylak std::map<std::string, std::variant<std::vector<std::string>>>> 493*53a27395SAdriana Kobylak interfacesAndProperties; 494*53a27395SAdriana Kobylak std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 495*53a27395SAdriana Kobylak objects; 496*53a27395SAdriana Kobylak try 497*53a27395SAdriana Kobylak { 498*53a27395SAdriana Kobylak auto reply = bus.call(getManagedObjects); 499*53a27395SAdriana Kobylak reply.read(objects); 500*53a27395SAdriana Kobylak } 501*53a27395SAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 502*53a27395SAdriana Kobylak {} 503*53a27395SAdriana Kobylak 504*53a27395SAdriana Kobylak auto maybeSetAttrWithArgsBound = std::bind( 505*53a27395SAdriana Kobylak maybeSetBiosAttr, std::cref(*pExtensionMap), std::placeholders::_1); 506*53a27395SAdriana Kobylak 507*53a27395SAdriana Kobylak for (const auto& pair : objects) 508*53a27395SAdriana Kobylak { 509*53a27395SAdriana Kobylak std::tie(std::ignore, interfacesAndProperties) = pair; 510*53a27395SAdriana Kobylak if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound)) 511*53a27395SAdriana Kobylak { 512*53a27395SAdriana Kobylak break; 513*53a27395SAdriana Kobylak } 514*53a27395SAdriana Kobylak } 515*53a27395SAdriana Kobylak 516*53a27395SAdriana Kobylak loop.exit(0); 517*53a27395SAdriana Kobylak return nullptr; 518*53a27395SAdriana Kobylak } 519*53a27395SAdriana Kobylak 520099543e4SBrad Bishop } // namespace process_hostfirmware 521099543e4SBrad Bishop } // namespace functions 522