1099543e4SBrad Bishop // SPDX-License-Identifier: Apache-2.0 2099543e4SBrad Bishop 3099543e4SBrad Bishop /**@file functions.cpp*/ 4099543e4SBrad Bishop 5*56f538caSAdriana Kobylak #include "config.h" 6*56f538caSAdriana Kobylak 7099543e4SBrad Bishop #include "functions.hpp" 8099543e4SBrad Bishop 9*56f538caSAdriana Kobylak #include <phosphor-logging/log.hpp> 10099543e4SBrad Bishop #include <sdbusplus/bus.hpp> 11099543e4SBrad Bishop #include <sdbusplus/bus/match.hpp> 12c79fa915SAdriana Kobylak #include <sdbusplus/exception.hpp> 13099543e4SBrad Bishop #include <sdbusplus/message.hpp> 14099543e4SBrad Bishop #include <sdeventplus/event.hpp> 15099543e4SBrad Bishop 16099543e4SBrad Bishop #include <filesystem> 17099543e4SBrad Bishop #include <functional> 18099543e4SBrad Bishop #include <iostream> 19099543e4SBrad Bishop #include <map> 20099543e4SBrad Bishop #include <memory> 21099543e4SBrad Bishop #include <string> 22099543e4SBrad Bishop #include <variant> 23099543e4SBrad Bishop #include <vector> 24099543e4SBrad Bishop 25099543e4SBrad Bishop namespace functions 26099543e4SBrad Bishop { 27099543e4SBrad Bishop namespace process_hostfirmware 28099543e4SBrad Bishop { 29099543e4SBrad Bishop 30*56f538caSAdriana Kobylak using namespace phosphor::logging; 31*56f538caSAdriana Kobylak 32099543e4SBrad Bishop /** 33099543e4SBrad Bishop * @brief Issue callbacks safely 34099543e4SBrad Bishop * 35099543e4SBrad Bishop * std::function can be empty, so this wrapper method checks for that prior to 36099543e4SBrad Bishop * calling it to avoid std::bad_function_call 37099543e4SBrad Bishop * 38099543e4SBrad Bishop * @tparam Sig the types of the std::function arguments 39099543e4SBrad Bishop * @tparam Args the deduced argument types 40099543e4SBrad Bishop * @param[in] callback the callback being wrapped 41099543e4SBrad Bishop * @param[in] args the callback arguments 42099543e4SBrad Bishop */ 43099543e4SBrad Bishop template <typename... Sig, typename... Args> 44099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args) 45099543e4SBrad Bishop { 46099543e4SBrad Bishop if (callback) 47099543e4SBrad Bishop { 48099543e4SBrad Bishop callback(std::forward<Args>(args)...); 49099543e4SBrad Bishop } 50099543e4SBrad Bishop } 51099543e4SBrad Bishop 52099543e4SBrad Bishop /** 53099543e4SBrad Bishop * @brief Get file extensions for IBMCompatibleSystem 54099543e4SBrad Bishop * 55099543e4SBrad Bishop * IBM host firmware can be deployed as blobs (files) in a filesystem. Host 56099543e4SBrad Bishop * firmware blobs for different values of 57099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with 58099543e4SBrad Bishop * different filename extensions. getExtensionsForIbmCompatibleSystem 59099543e4SBrad Bishop * maintains the mapping from a given value of 60099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of 61099543e4SBrad Bishop * filename extensions. 62099543e4SBrad Bishop * 63099543e4SBrad Bishop * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and 64099543e4SBrad Bishop * the extensions parameter is reset with the map entry. If no mapping is 65099543e4SBrad Bishop * found getExtensionsForIbmCompatibleSystem returns false and extensions is 66099543e4SBrad Bishop * unmodified. 67099543e4SBrad Bishop * 68099543e4SBrad Bishop * @param[in] extensionMap a map of 69099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 70099543e4SBrad Bishop * file extensions. 71099543e4SBrad Bishop * @param[in] ibmCompatibleSystem The names property of an instance of 72099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem 73099543e4SBrad Bishop * @param[out] extentions the host firmware blob file extensions 74099543e4SBrad Bishop * @return true if an entry was found, otherwise false 75099543e4SBrad Bishop */ 76099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem( 77099543e4SBrad Bishop const std::map<std::string, std::vector<std::string>>& extensionMap, 78099543e4SBrad Bishop const std::vector<std::string>& ibmCompatibleSystem, 79099543e4SBrad Bishop std::vector<std::string>& extensions) 80099543e4SBrad Bishop { 81099543e4SBrad Bishop for (const auto& system : ibmCompatibleSystem) 82099543e4SBrad Bishop { 83099543e4SBrad Bishop auto extensionMapIterator = extensionMap.find(system); 84099543e4SBrad Bishop if (extensionMapIterator != extensionMap.end()) 85099543e4SBrad Bishop { 86099543e4SBrad Bishop extensions = extensionMapIterator->second; 87099543e4SBrad Bishop return true; 88099543e4SBrad Bishop } 89099543e4SBrad Bishop } 90099543e4SBrad Bishop 91099543e4SBrad Bishop return false; 92099543e4SBrad Bishop } 93099543e4SBrad Bishop 94099543e4SBrad Bishop /** 95099543e4SBrad Bishop * @brief Write host firmware well-known name 96099543e4SBrad Bishop * 97099543e4SBrad Bishop * A wrapper around std::filesystem::create_symlink that avoids EEXIST by 98099543e4SBrad Bishop * deleting any pre-existing file. 99099543e4SBrad Bishop * 100099543e4SBrad Bishop * @param[in] linkTarget The link target argument to 101099543e4SBrad Bishop * std::filesystem::create_symlink 102099543e4SBrad Bishop * @param[in] linkPath The link path argument to std::filesystem::create_symlink 103099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 104099543e4SBrad Bishop */ 105099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget, 106099543e4SBrad Bishop const std::filesystem::path& linkPath, 107099543e4SBrad Bishop const ErrorCallbackType& errorCallback) 108099543e4SBrad Bishop { 109099543e4SBrad Bishop std::error_code ec; 110099543e4SBrad Bishop 111099543e4SBrad Bishop // remove files with the same name as the symlink to be created, 112099543e4SBrad Bishop // otherwise symlink will fail with EEXIST. 113099543e4SBrad Bishop if (!std::filesystem::remove(linkPath, ec)) 114099543e4SBrad Bishop { 115099543e4SBrad Bishop if (ec) 116099543e4SBrad Bishop { 117099543e4SBrad Bishop makeCallback(errorCallback, linkPath, ec); 118099543e4SBrad Bishop return; 119099543e4SBrad Bishop } 120099543e4SBrad Bishop } 121099543e4SBrad Bishop 122099543e4SBrad Bishop std::filesystem::create_symlink(linkTarget, linkPath, ec); 123099543e4SBrad Bishop if (ec) 124099543e4SBrad Bishop { 125099543e4SBrad Bishop makeCallback(errorCallback, linkPath, ec); 126099543e4SBrad Bishop return; 127099543e4SBrad Bishop } 128099543e4SBrad Bishop } 129099543e4SBrad Bishop 130099543e4SBrad Bishop /** 131099543e4SBrad Bishop * @brief Find host firmware blob files that need well-known names 132099543e4SBrad Bishop * 133099543e4SBrad Bishop * The IBM host firmware runtime looks for data and/or additional code while 134099543e4SBrad Bishop * bootstraping in files with well-known names. findLinks uses the provided 135099543e4SBrad Bishop * extensions argument to find host firmware blob files that require a 136099543e4SBrad Bishop * well-known name. When a blob is found, issue the provided callback 137099543e4SBrad Bishop * (typically a function that will write a symlink). 138099543e4SBrad Bishop * 139099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which findLinks should 140099543e4SBrad Bishop * look for host firmware blob files that need well-known names. 141099543e4SBrad Bishop * @param[in] extentions The extensions of the firmware blob files denote a 142099543e4SBrad Bishop * host firmware blob file requires a well-known name. 143099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 144099543e4SBrad Bishop * @param[in] linkCallback A callback made when host firmware blob files 145099543e4SBrad Bishop * needing a well known name are found. 146099543e4SBrad Bishop */ 147099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory, 148099543e4SBrad Bishop const std::vector<std::string>& extensions, 149099543e4SBrad Bishop const ErrorCallbackType& errorCallback, 150099543e4SBrad Bishop const LinkCallbackType& linkCallback) 151099543e4SBrad Bishop { 152099543e4SBrad Bishop std::error_code ec; 153099543e4SBrad Bishop std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory, 154099543e4SBrad Bishop ec); 155099543e4SBrad Bishop if (ec) 156099543e4SBrad Bishop { 157099543e4SBrad Bishop makeCallback(errorCallback, hostFirmwareDirectory, ec); 158099543e4SBrad Bishop return; 159099543e4SBrad Bishop } 160099543e4SBrad Bishop 161fdc91fa0SAdriana Kobylak // Create a symlink from HBB to the corresponding LID file if it exists 162fdc91fa0SAdriana Kobylak static const auto hbbLid = "81e0065a.lid"; 163fdc91fa0SAdriana Kobylak auto hbbLidPath = hostFirmwareDirectory / hbbLid; 164fdc91fa0SAdriana Kobylak if (std::filesystem::exists(hbbLidPath)) 165fdc91fa0SAdriana Kobylak { 166fdc91fa0SAdriana Kobylak static const auto hbbName = "HBB"; 167fdc91fa0SAdriana Kobylak auto hbbLinkPath = hostFirmwareDirectory / hbbName; 168fdc91fa0SAdriana Kobylak makeCallback(linkCallback, hbbLid, hbbLinkPath, errorCallback); 169fdc91fa0SAdriana Kobylak } 170fdc91fa0SAdriana Kobylak 171099543e4SBrad Bishop for (; directoryIterator != std::filesystem::end(directoryIterator); 172099543e4SBrad Bishop directoryIterator.increment(ec)) 173099543e4SBrad Bishop { 174099543e4SBrad Bishop const auto& file = directoryIterator->path(); 175099543e4SBrad Bishop if (ec) 176099543e4SBrad Bishop { 177099543e4SBrad Bishop makeCallback(errorCallback, file, ec); 178099543e4SBrad Bishop // quit here if the increment call failed otherwise the loop may 179099543e4SBrad Bishop // never finish 180099543e4SBrad Bishop break; 181099543e4SBrad Bishop } 182099543e4SBrad Bishop 183099543e4SBrad Bishop if (std::find(extensions.begin(), extensions.end(), file.extension()) == 184099543e4SBrad Bishop extensions.end()) 185099543e4SBrad Bishop { 186099543e4SBrad Bishop // this file doesn't have an extension or doesn't match any of the 187099543e4SBrad Bishop // provided extensions. 188099543e4SBrad Bishop continue; 189099543e4SBrad Bishop } 190099543e4SBrad Bishop 191099543e4SBrad Bishop auto linkPath(file.parent_path().append( 192099543e4SBrad Bishop static_cast<const std::string&>(file.stem()))); 193099543e4SBrad Bishop 194099543e4SBrad Bishop makeCallback(linkCallback, file.filename(), linkPath, errorCallback); 195099543e4SBrad Bishop } 196099543e4SBrad Bishop } 197099543e4SBrad Bishop 198099543e4SBrad Bishop /** 19953a27395SAdriana Kobylak * @brief Set the bios attribute table with details of the host firmware data 20053a27395SAdriana Kobylak * for this system. 20153a27395SAdriana Kobylak */ 20253a27395SAdriana Kobylak void setBiosAttr() 203*56f538caSAdriana Kobylak { 204*56f538caSAdriana Kobylak std::string biosAttrStr{}; 205*56f538caSAdriana Kobylak 206*56f538caSAdriana Kobylak constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager"; 207*56f538caSAdriana Kobylak constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager"; 208*56f538caSAdriana Kobylak constexpr auto dbusAttrName = "hb_lid_ids"; 209*56f538caSAdriana Kobylak constexpr auto dbusAttrType = 210*56f538caSAdriana Kobylak "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String"; 211*56f538caSAdriana Kobylak 212*56f538caSAdriana Kobylak using PendingAttributesType = std::vector<std::pair< 213*56f538caSAdriana Kobylak std::string, std::tuple<std::string, std::variant<std::string>>>>; 214*56f538caSAdriana Kobylak PendingAttributesType pendingAttributes; 215*56f538caSAdriana Kobylak pendingAttributes.emplace_back(std::make_pair( 216*56f538caSAdriana Kobylak dbusAttrName, std::make_tuple(dbusAttrType, biosAttrStr))); 217*56f538caSAdriana Kobylak 218*56f538caSAdriana Kobylak auto bus = sdbusplus::bus::new_default(); 219*56f538caSAdriana Kobylak auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 220*56f538caSAdriana Kobylak MAPPER_INTERFACE, "GetObject"); 221*56f538caSAdriana Kobylak method.append(biosConfigPath, std::vector<std::string>({biosConfigIntf})); 222*56f538caSAdriana Kobylak std::vector<std::pair<std::string, std::vector<std::string>>> response; 223*56f538caSAdriana Kobylak try 224*56f538caSAdriana Kobylak { 225*56f538caSAdriana Kobylak auto reply = bus.call(method); 226*56f538caSAdriana Kobylak reply.read(response); 227*56f538caSAdriana Kobylak if (response.empty()) 228*56f538caSAdriana Kobylak { 229*56f538caSAdriana Kobylak log<level::ERR>("Error reading mapper response", 230*56f538caSAdriana Kobylak entry("PATH=%s", biosConfigPath), 231*56f538caSAdriana Kobylak entry("INTERFACE=%s", biosConfigIntf)); 232*56f538caSAdriana Kobylak return; 233*56f538caSAdriana Kobylak } 234*56f538caSAdriana Kobylak auto method = bus.new_method_call((response.begin()->first).c_str(), 235*56f538caSAdriana Kobylak biosConfigPath, 236*56f538caSAdriana Kobylak SYSTEMD_PROPERTY_INTERFACE, "Set"); 237*56f538caSAdriana Kobylak method.append(biosConfigIntf, "PendingAttributes", 238*56f538caSAdriana Kobylak std::variant<PendingAttributesType>(pendingAttributes)); 239*56f538caSAdriana Kobylak bus.call(method); 240*56f538caSAdriana Kobylak } 241*56f538caSAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 242*56f538caSAdriana Kobylak { 243*56f538caSAdriana Kobylak log<level::ERR>("Error setting the bios attribute", 244*56f538caSAdriana Kobylak entry("ERROR=%s", e.what()), 245*56f538caSAdriana Kobylak entry("ATTRIBUTE=%s", dbusAttrName)); 246*56f538caSAdriana Kobylak return; 247*56f538caSAdriana Kobylak } 248*56f538caSAdriana Kobylak } 24953a27395SAdriana Kobylak 25053a27395SAdriana Kobylak /** 251099543e4SBrad Bishop * @brief Make callbacks on 252099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances. 253099543e4SBrad Bishop * 254099543e4SBrad Bishop * Look for an instance of 255099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided 256099543e4SBrad Bishop * argument and if found, issue the provided callback. 257099543e4SBrad Bishop * 258099543e4SBrad Bishop * @param[in] interfacesAndProperties the interfaces in which to look for an 259099543e4SBrad Bishop * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem 260099543e4SBrad Bishop * @param[in] callback the user callback to make if 261099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in 262099543e4SBrad Bishop * interfacesAndProperties 263099543e4SBrad Bishop * @return true if interfacesAndProperties contained an instance of 264099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise 265099543e4SBrad Bishop */ 266099543e4SBrad Bishop bool maybeCall(const std::map<std::string, 267099543e4SBrad Bishop std::map<std::string, 268099543e4SBrad Bishop std::variant<std::vector<std::string>>>>& 269099543e4SBrad Bishop interfacesAndProperties, 270099543e4SBrad Bishop const MaybeCallCallbackType& callback) 271099543e4SBrad Bishop { 272099543e4SBrad Bishop using namespace std::string_literals; 273099543e4SBrad Bishop 274099543e4SBrad Bishop static const auto interfaceName = 275099543e4SBrad Bishop "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s; 276099543e4SBrad Bishop auto interfaceIterator = interfacesAndProperties.find(interfaceName); 277099543e4SBrad Bishop if (interfaceIterator == interfacesAndProperties.cend()) 278099543e4SBrad Bishop { 279099543e4SBrad Bishop // IBMCompatibleSystem interface not found, so instruct the caller to 280099543e4SBrad Bishop // keep waiting or try again later. 281099543e4SBrad Bishop return false; 282099543e4SBrad Bishop } 283099543e4SBrad Bishop auto propertyIterator = interfaceIterator->second.find("Names"s); 284099543e4SBrad Bishop if (propertyIterator == interfaceIterator->second.cend()) 285099543e4SBrad Bishop { 286099543e4SBrad Bishop // The interface exists but the property doesn't. This is a bug in the 287099543e4SBrad Bishop // IBMCompatibleSystem implementation. The caller should not try 288099543e4SBrad Bishop // again. 289099543e4SBrad Bishop std::cerr << "Names property not implemented on " << interfaceName 290099543e4SBrad Bishop << "\n"; 291099543e4SBrad Bishop return true; 292099543e4SBrad Bishop } 293099543e4SBrad Bishop 294099543e4SBrad Bishop const auto& ibmCompatibleSystem = 295099543e4SBrad Bishop std::get<std::vector<std::string>>(propertyIterator->second); 296099543e4SBrad Bishop if (callback) 297099543e4SBrad Bishop { 298099543e4SBrad Bishop callback(ibmCompatibleSystem); 299099543e4SBrad Bishop } 300099543e4SBrad Bishop 301099543e4SBrad Bishop // IBMCompatibleSystem found and callback issued. 302099543e4SBrad Bishop return true; 303099543e4SBrad Bishop } 304099543e4SBrad Bishop 305099543e4SBrad Bishop /** 306099543e4SBrad Bishop * @brief Make callbacks on 307099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances. 308099543e4SBrad Bishop * 309099543e4SBrad Bishop * Look for an instance of 310099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided 311099543e4SBrad Bishop * argument and if found, issue the provided callback. 312099543e4SBrad Bishop * 313099543e4SBrad Bishop * @param[in] message the DBus message in which to look for an instance of 314099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem 315099543e4SBrad Bishop * @param[in] callback the user callback to make if 316099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in 317099543e4SBrad Bishop * message 318099543e4SBrad Bishop * @return true if message contained an instance of 319099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise 320099543e4SBrad Bishop */ 321099543e4SBrad Bishop bool maybeCallMessage(sdbusplus::message::message& message, 322099543e4SBrad Bishop const MaybeCallCallbackType& callback) 323099543e4SBrad Bishop { 324099543e4SBrad Bishop std::map<std::string, 325099543e4SBrad Bishop std::map<std::string, std::variant<std::vector<std::string>>>> 326099543e4SBrad Bishop interfacesAndProperties; 327099543e4SBrad Bishop sdbusplus::message::object_path _; 328099543e4SBrad Bishop message.read(_, interfacesAndProperties); 329099543e4SBrad Bishop return maybeCall(interfacesAndProperties, callback); 330099543e4SBrad Bishop } 331099543e4SBrad Bishop 332099543e4SBrad Bishop /** 333099543e4SBrad Bishop * @brief Determine system support for host firmware well-known names. 334099543e4SBrad Bishop * 335099543e4SBrad Bishop * Using the provided extensionMap and 336099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if 337099543e4SBrad Bishop * well-known names for host firmare blob files are necessary and if so, create 338099543e4SBrad Bishop * them. 339099543e4SBrad Bishop * 340099543e4SBrad Bishop * @param[in] extensionMap a map of 341099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 342099543e4SBrad Bishop * file extensions. 343099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which findLinks should 344099543e4SBrad Bishop * look for host firmware blob files that need well-known names. 345099543e4SBrad Bishop * @param[in] ibmCompatibleSystem The names property of an instance of 346099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem 347099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 348099543e4SBrad Bishop */ 349099543e4SBrad Bishop void maybeMakeLinks( 350099543e4SBrad Bishop const std::map<std::string, std::vector<std::string>>& extensionMap, 351099543e4SBrad Bishop const std::filesystem::path& hostFirmwareDirectory, 352099543e4SBrad Bishop const std::vector<std::string>& ibmCompatibleSystem, 353099543e4SBrad Bishop const ErrorCallbackType& errorCallback) 354099543e4SBrad Bishop { 355099543e4SBrad Bishop std::vector<std::string> extensions; 356099543e4SBrad Bishop if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 357099543e4SBrad Bishop extensions)) 358099543e4SBrad Bishop { 359099543e4SBrad Bishop findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink); 360099543e4SBrad Bishop } 361099543e4SBrad Bishop } 362099543e4SBrad Bishop 363099543e4SBrad Bishop /** 36453a27395SAdriana Kobylak * @brief Determine system support for updating the bios attribute table. 36553a27395SAdriana Kobylak * 36653a27395SAdriana Kobylak * Using the provided extensionMap and 36753a27395SAdriana Kobylak * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if the bios 36853a27395SAdriana Kobylak * attribute table needs to be updated. 36953a27395SAdriana Kobylak * 37053a27395SAdriana Kobylak * @param[in] extensionMap a map of 37153a27395SAdriana Kobylak * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 37253a27395SAdriana Kobylak * file extensions. 37353a27395SAdriana Kobylak * @param[in] ibmCompatibleSystem The names property of an instance of 37453a27395SAdriana Kobylak * xyz.openbmc_project.Configuration.IBMCompatibleSystem 37553a27395SAdriana Kobylak */ 37653a27395SAdriana Kobylak void maybeSetBiosAttr( 37753a27395SAdriana Kobylak const std::map<std::string, std::vector<std::string>>& extensionMap, 37853a27395SAdriana Kobylak const std::vector<std::string>& ibmCompatibleSystem) 37953a27395SAdriana Kobylak { 38053a27395SAdriana Kobylak std::vector<std::string> extensions; 38153a27395SAdriana Kobylak if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem, 38253a27395SAdriana Kobylak extensions)) 38353a27395SAdriana Kobylak { 38453a27395SAdriana Kobylak setBiosAttr(); 38553a27395SAdriana Kobylak } 38653a27395SAdriana Kobylak } 38753a27395SAdriana Kobylak 38853a27395SAdriana Kobylak /** 389099543e4SBrad Bishop * @brief process host firmware 390099543e4SBrad Bishop * 391099543e4SBrad Bishop * Allocate a callback context and register for DBus.ObjectManager Interfaces 392099543e4SBrad Bishop * added signals from entity manager. 393099543e4SBrad Bishop * 394099543e4SBrad Bishop * Check the current entity manager object tree for a 395099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity 396099543e4SBrad Bishop * manager will be dbus activated if it is not running). If one is found, 397099543e4SBrad Bishop * determine if symlinks need to be created and create them. Instruct the 398099543e4SBrad Bishop * program event loop to exit. 399099543e4SBrad Bishop * 400099543e4SBrad Bishop * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is 401099543e4SBrad Bishop * found return the callback context to main, where the program will sleep 402099543e4SBrad Bishop * until the callback is invoked one or more times and instructs the program 403099543e4SBrad Bishop * event loop to exit when 404099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added. 405099543e4SBrad Bishop * 406099543e4SBrad Bishop * @param[in] bus a DBus client connection 407099543e4SBrad Bishop * @param[in] extensionMap a map of 408099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob 409099543e4SBrad Bishop * file extensions. 410099543e4SBrad Bishop * @param[in] hostFirmwareDirectory The directory in which processHostFirmware 411099543e4SBrad Bishop * should look for blob files. 412099543e4SBrad Bishop * @param[in] errorCallback A callback made in the event of filesystem errors. 413099543e4SBrad Bishop * @param[in] loop a program event loop 414099543e4SBrad Bishop * @return nullptr if an instance of 415099543e4SBrad Bishop * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a 416099543e4SBrad Bishop * pointer to an sdbusplus match object. 417099543e4SBrad Bishop */ 418099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware( 419099543e4SBrad Bishop sdbusplus::bus::bus& bus, 420099543e4SBrad Bishop std::map<std::string, std::vector<std::string>> extensionMap, 421099543e4SBrad Bishop std::filesystem::path hostFirmwareDirectory, 422099543e4SBrad Bishop ErrorCallbackType errorCallback, sdeventplus::Event& loop) 423099543e4SBrad Bishop { 424099543e4SBrad Bishop // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't 425099543e4SBrad Bishop // be transfered to the match callback because they are needed in the non 426099543e4SBrad Bishop // async part of this function below, so they need to be moved to the heap. 427099543e4SBrad Bishop auto pExtensionMap = 428099543e4SBrad Bishop std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 429099543e4SBrad Bishop auto pHostFirmwareDirectory = 430099543e4SBrad Bishop std::make_shared<decltype(hostFirmwareDirectory)>( 431099543e4SBrad Bishop std::move(hostFirmwareDirectory)); 432099543e4SBrad Bishop auto pErrorCallback = 433099543e4SBrad Bishop std::make_shared<decltype(errorCallback)>(std::move(errorCallback)); 434099543e4SBrad Bishop 435099543e4SBrad Bishop // register for a callback in case the IBMCompatibleSystem interface has 436099543e4SBrad Bishop // not yet been published by entity manager. 437099543e4SBrad Bishop auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>( 438099543e4SBrad Bishop bus, 439099543e4SBrad Bishop sdbusplus::bus::match::rules::interfacesAdded() + 440099543e4SBrad Bishop sdbusplus::bus::match::rules::sender( 441099543e4SBrad Bishop "xyz.openbmc_project.EntityManager"), 442099543e4SBrad Bishop [pExtensionMap, pHostFirmwareDirectory, pErrorCallback, 443099543e4SBrad Bishop &loop](auto& message) { 444099543e4SBrad Bishop // bind the extension map, host firmware directory, and error 445099543e4SBrad Bishop // callback to the maybeMakeLinks function. 446099543e4SBrad Bishop auto maybeMakeLinksWithArgsBound = 447099543e4SBrad Bishop std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 448099543e4SBrad Bishop std::cref(*pHostFirmwareDirectory), 449099543e4SBrad Bishop std::placeholders::_1, std::cref(*pErrorCallback)); 450099543e4SBrad Bishop 451099543e4SBrad Bishop // if the InterfacesAdded message contains an an instance of 452099543e4SBrad Bishop // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to 453099543e4SBrad Bishop // see if links are necessary on this system and if so, create 454099543e4SBrad Bishop // them. 455099543e4SBrad Bishop if (maybeCallMessage(message, maybeMakeLinksWithArgsBound)) 456099543e4SBrad Bishop { 457099543e4SBrad Bishop // The IBMCompatibleSystem interface was found and the links 458099543e4SBrad Bishop // were created if applicable. Instruct the event loop / 459099543e4SBrad Bishop // subcommand to exit. 460099543e4SBrad Bishop loop.exit(0); 461099543e4SBrad Bishop } 462099543e4SBrad Bishop }); 463099543e4SBrad Bishop 464099543e4SBrad Bishop // now that we'll get a callback in the event of an InterfacesAdded signal 465099543e4SBrad Bishop // (potentially containing 466099543e4SBrad Bishop // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity 467099543e4SBrad Bishop // manager if it isn't running and enumerate its objects 468099543e4SBrad Bishop auto getManagedObjects = bus.new_method_call( 469099543e4SBrad Bishop "xyz.openbmc_project.EntityManager", "/", 470099543e4SBrad Bishop "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 471099543e4SBrad Bishop std::map<std::string, 472099543e4SBrad Bishop std::map<std::string, std::variant<std::vector<std::string>>>> 473099543e4SBrad Bishop interfacesAndProperties; 474099543e4SBrad Bishop std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 475099543e4SBrad Bishop objects; 476c79fa915SAdriana Kobylak try 477c79fa915SAdriana Kobylak { 478c79fa915SAdriana Kobylak auto reply = bus.call(getManagedObjects); 479099543e4SBrad Bishop reply.read(objects); 480c79fa915SAdriana Kobylak } 481c79fa915SAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 482c79fa915SAdriana Kobylak { 483c79fa915SAdriana Kobylak // Error querying the EntityManager interface. Return the match to have 484c79fa915SAdriana Kobylak // the callback run if/when the interface appears in D-Bus. 485c79fa915SAdriana Kobylak return interfacesAddedMatch; 486c79fa915SAdriana Kobylak } 487099543e4SBrad Bishop 488099543e4SBrad Bishop // bind the extension map, host firmware directory, and error callback to 489099543e4SBrad Bishop // the maybeMakeLinks function. 490099543e4SBrad Bishop auto maybeMakeLinksWithArgsBound = 491099543e4SBrad Bishop std::bind(maybeMakeLinks, std::cref(*pExtensionMap), 492099543e4SBrad Bishop std::cref(*pHostFirmwareDirectory), std::placeholders::_1, 493099543e4SBrad Bishop std::cref(*pErrorCallback)); 494099543e4SBrad Bishop 495099543e4SBrad Bishop for (const auto& pair : objects) 496099543e4SBrad Bishop { 497099543e4SBrad Bishop std::tie(std::ignore, interfacesAndProperties) = pair; 498099543e4SBrad Bishop // if interfacesAndProperties contains an an instance of 499099543e4SBrad Bishop // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see 500099543e4SBrad Bishop // if links are necessary on this system and if so, create them 501099543e4SBrad Bishop if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound)) 502099543e4SBrad Bishop { 503099543e4SBrad Bishop // The IBMCompatibleSystem interface is already on the bus and the 504099543e4SBrad Bishop // links were created if applicable. Instruct the event loop to 505099543e4SBrad Bishop // exit. 506099543e4SBrad Bishop loop.exit(0); 507099543e4SBrad Bishop // The match object isn't needed anymore, so destroy it on return. 508099543e4SBrad Bishop return nullptr; 509099543e4SBrad Bishop } 510099543e4SBrad Bishop } 511099543e4SBrad Bishop 512099543e4SBrad Bishop // The IBMCompatibleSystem interface has not yet been published. Move 513099543e4SBrad Bishop // ownership of the match callback to the caller. 514099543e4SBrad Bishop return interfacesAddedMatch; 515099543e4SBrad Bishop } 51653a27395SAdriana Kobylak 51753a27395SAdriana Kobylak /** 51853a27395SAdriana Kobylak * @brief Update the Bios Attribute Table 51953a27395SAdriana Kobylak * 52053a27395SAdriana Kobylak * If an instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is 52153a27395SAdriana Kobylak * found, update the Bios Attribute Table with the appropriate host firmware 52253a27395SAdriana Kobylak * data. 52353a27395SAdriana Kobylak * 52453a27395SAdriana Kobylak * @param[in] bus - D-Bus client connection. 52553a27395SAdriana Kobylak * @param[in] extensionMap - Map of IBMCompatibleSystem names and host firmware 52653a27395SAdriana Kobylak * file extensions. 52753a27395SAdriana Kobylak * @param[in] loop - Program event loop. 52853a27395SAdriana Kobylak * @return nullptr 52953a27395SAdriana Kobylak */ 53053a27395SAdriana Kobylak std::shared_ptr<void> updateBiosAttrTable( 53153a27395SAdriana Kobylak sdbusplus::bus::bus& bus, 53253a27395SAdriana Kobylak std::map<std::string, std::vector<std::string>> extensionMap, 53353a27395SAdriana Kobylak sdeventplus::Event& loop) 53453a27395SAdriana Kobylak { 53553a27395SAdriana Kobylak auto pExtensionMap = 53653a27395SAdriana Kobylak std::make_shared<decltype(extensionMap)>(std::move(extensionMap)); 53753a27395SAdriana Kobylak 53853a27395SAdriana Kobylak auto getManagedObjects = bus.new_method_call( 53953a27395SAdriana Kobylak "xyz.openbmc_project.EntityManager", "/", 54053a27395SAdriana Kobylak "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 54153a27395SAdriana Kobylak std::map<std::string, 54253a27395SAdriana Kobylak std::map<std::string, std::variant<std::vector<std::string>>>> 54353a27395SAdriana Kobylak interfacesAndProperties; 54453a27395SAdriana Kobylak std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)> 54553a27395SAdriana Kobylak objects; 54653a27395SAdriana Kobylak try 54753a27395SAdriana Kobylak { 54853a27395SAdriana Kobylak auto reply = bus.call(getManagedObjects); 54953a27395SAdriana Kobylak reply.read(objects); 55053a27395SAdriana Kobylak } 55153a27395SAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 55253a27395SAdriana Kobylak {} 55353a27395SAdriana Kobylak 55453a27395SAdriana Kobylak auto maybeSetAttrWithArgsBound = std::bind( 55553a27395SAdriana Kobylak maybeSetBiosAttr, std::cref(*pExtensionMap), std::placeholders::_1); 55653a27395SAdriana Kobylak 55753a27395SAdriana Kobylak for (const auto& pair : objects) 55853a27395SAdriana Kobylak { 55953a27395SAdriana Kobylak std::tie(std::ignore, interfacesAndProperties) = pair; 56053a27395SAdriana Kobylak if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound)) 56153a27395SAdriana Kobylak { 56253a27395SAdriana Kobylak break; 56353a27395SAdriana Kobylak } 56453a27395SAdriana Kobylak } 56553a27395SAdriana Kobylak 56653a27395SAdriana Kobylak loop.exit(0); 56753a27395SAdriana Kobylak return nullptr; 56853a27395SAdriana Kobylak } 56953a27395SAdriana Kobylak 570099543e4SBrad Bishop } // namespace process_hostfirmware 571099543e4SBrad Bishop } // namespace functions 572