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>
16099543e4SBrad Bishop 
17099543e4SBrad Bishop #include <filesystem>
18ae0998f1SAdriana Kobylak #include <fstream>
19099543e4SBrad Bishop #include <functional>
20099543e4SBrad Bishop #include <iostream>
21099543e4SBrad Bishop #include <map>
22099543e4SBrad Bishop #include <memory>
23099543e4SBrad Bishop #include <string>
24099543e4SBrad Bishop #include <variant>
25099543e4SBrad Bishop #include <vector>
26099543e4SBrad Bishop 
27099543e4SBrad Bishop namespace functions
28099543e4SBrad Bishop {
29099543e4SBrad Bishop namespace process_hostfirmware
30099543e4SBrad Bishop {
31099543e4SBrad Bishop 
3256f538caSAdriana Kobylak using namespace phosphor::logging;
3356f538caSAdriana Kobylak 
34099543e4SBrad Bishop /**
35fd4a6088SAdriana Kobylak  * @brief GetObject function to find the service given an object path.
36fd4a6088SAdriana Kobylak  *        It is used to determine if a service is running, so there is no need
37fd4a6088SAdriana Kobylak  *        to specify interfaces as a parameter to constrain the search.
38fd4a6088SAdriana Kobylak  */
39fd4a6088SAdriana Kobylak std::string getObject(sdbusplus::bus::bus& bus, const std::string& path)
40fd4a6088SAdriana Kobylak {
41fd4a6088SAdriana Kobylak     auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
42fd4a6088SAdriana Kobylak                                       MAPPER_BUSNAME, "GetObject");
43fd4a6088SAdriana Kobylak     method.append(path);
44fd4a6088SAdriana Kobylak     std::vector<std::string> interfaces;
45fd4a6088SAdriana Kobylak     method.append(interfaces);
46fd4a6088SAdriana Kobylak 
47fd4a6088SAdriana Kobylak     std::vector<std::pair<std::string, std::vector<std::string>>> response;
48fd4a6088SAdriana Kobylak 
49fd4a6088SAdriana Kobylak     try
50fd4a6088SAdriana Kobylak     {
51fd4a6088SAdriana Kobylak         auto reply = bus.call(method);
52fd4a6088SAdriana Kobylak         reply.read(response);
53fd4a6088SAdriana Kobylak         if (response.empty())
54fd4a6088SAdriana Kobylak         {
55fd4a6088SAdriana Kobylak             return std::string{};
56fd4a6088SAdriana Kobylak         }
57fd4a6088SAdriana Kobylak     }
58fd4a6088SAdriana Kobylak     catch (const sdbusplus::exception::SdBusError& e)
59fd4a6088SAdriana Kobylak     {
60fd4a6088SAdriana Kobylak         return std::string{};
61fd4a6088SAdriana Kobylak     }
62fd4a6088SAdriana Kobylak     return response[0].first;
63fd4a6088SAdriana Kobylak }
64fd4a6088SAdriana Kobylak 
65fd4a6088SAdriana Kobylak /**
66099543e4SBrad Bishop  * @brief Issue callbacks safely
67099543e4SBrad Bishop  *
68099543e4SBrad Bishop  * std::function can be empty, so this wrapper method checks for that prior to
69099543e4SBrad Bishop  * calling it to avoid std::bad_function_call
70099543e4SBrad Bishop  *
71099543e4SBrad Bishop  * @tparam Sig the types of the std::function arguments
72099543e4SBrad Bishop  * @tparam Args the deduced argument types
73099543e4SBrad Bishop  * @param[in] callback the callback being wrapped
74099543e4SBrad Bishop  * @param[in] args the callback arguments
75099543e4SBrad Bishop  */
76099543e4SBrad Bishop template <typename... Sig, typename... Args>
77099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args)
78099543e4SBrad Bishop {
79099543e4SBrad Bishop     if (callback)
80099543e4SBrad Bishop     {
81099543e4SBrad Bishop         callback(std::forward<Args>(args)...);
82099543e4SBrad Bishop     }
83099543e4SBrad Bishop }
84099543e4SBrad Bishop 
85099543e4SBrad Bishop /**
86099543e4SBrad Bishop  * @brief Get file extensions for IBMCompatibleSystem
87099543e4SBrad Bishop  *
88099543e4SBrad Bishop  * IBM host firmware can be deployed as blobs (files) in a filesystem.  Host
89099543e4SBrad Bishop  * firmware blobs for different values of
90099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with
91099543e4SBrad Bishop  * different filename extensions.  getExtensionsForIbmCompatibleSystem
92099543e4SBrad Bishop  * maintains the mapping from a given value of
93099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of
94099543e4SBrad Bishop  * filename extensions.
95099543e4SBrad Bishop  *
96099543e4SBrad Bishop  * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and
97099543e4SBrad Bishop  * the extensions parameter is reset with the map entry.  If no mapping is
98099543e4SBrad Bishop  * found getExtensionsForIbmCompatibleSystem returns false and extensions is
99099543e4SBrad Bishop  * unmodified.
100099543e4SBrad Bishop  *
101099543e4SBrad Bishop  * @param[in] extensionMap a map of
102099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
103099543e4SBrad Bishop  * file extensions.
104099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
105099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
106099543e4SBrad Bishop  * @param[out] extentions the host firmware blob file extensions
107099543e4SBrad Bishop  * @return true if an entry was found, otherwise false
108099543e4SBrad Bishop  */
109099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem(
110099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
111099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
112099543e4SBrad Bishop     std::vector<std::string>& extensions)
113099543e4SBrad Bishop {
114099543e4SBrad Bishop     for (const auto& system : ibmCompatibleSystem)
115099543e4SBrad Bishop     {
116099543e4SBrad Bishop         auto extensionMapIterator = extensionMap.find(system);
117099543e4SBrad Bishop         if (extensionMapIterator != extensionMap.end())
118099543e4SBrad Bishop         {
119099543e4SBrad Bishop             extensions = extensionMapIterator->second;
120099543e4SBrad Bishop             return true;
121099543e4SBrad Bishop         }
122099543e4SBrad Bishop     }
123099543e4SBrad Bishop 
124099543e4SBrad Bishop     return false;
125099543e4SBrad Bishop }
126099543e4SBrad Bishop 
127099543e4SBrad Bishop /**
128099543e4SBrad Bishop  * @brief Write host firmware well-known name
129099543e4SBrad Bishop  *
130099543e4SBrad Bishop  * A wrapper around std::filesystem::create_symlink that avoids EEXIST by
131099543e4SBrad Bishop  * deleting any pre-existing file.
132099543e4SBrad Bishop  *
133099543e4SBrad Bishop  * @param[in] linkTarget The link target argument to
134099543e4SBrad Bishop  * std::filesystem::create_symlink
135099543e4SBrad Bishop  * @param[in] linkPath The link path argument to std::filesystem::create_symlink
136099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
137099543e4SBrad Bishop  */
138099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget,
139099543e4SBrad Bishop                const std::filesystem::path& linkPath,
140099543e4SBrad Bishop                const ErrorCallbackType& errorCallback)
141099543e4SBrad Bishop {
142099543e4SBrad Bishop     std::error_code ec;
143099543e4SBrad Bishop 
144099543e4SBrad Bishop     // remove files with the same name as the symlink to be created,
145099543e4SBrad Bishop     // otherwise symlink will fail with EEXIST.
146099543e4SBrad Bishop     if (!std::filesystem::remove(linkPath, ec))
147099543e4SBrad Bishop     {
148099543e4SBrad Bishop         if (ec)
149099543e4SBrad Bishop         {
150099543e4SBrad Bishop             makeCallback(errorCallback, linkPath, ec);
151099543e4SBrad Bishop             return;
152099543e4SBrad Bishop         }
153099543e4SBrad Bishop     }
154099543e4SBrad Bishop 
155099543e4SBrad Bishop     std::filesystem::create_symlink(linkTarget, linkPath, ec);
156099543e4SBrad Bishop     if (ec)
157099543e4SBrad Bishop     {
158099543e4SBrad Bishop         makeCallback(errorCallback, linkPath, ec);
159099543e4SBrad Bishop         return;
160099543e4SBrad Bishop     }
161099543e4SBrad Bishop }
162099543e4SBrad Bishop 
163099543e4SBrad Bishop /**
164099543e4SBrad Bishop  * @brief Find host firmware blob files that need well-known names
165099543e4SBrad Bishop  *
166099543e4SBrad Bishop  * The IBM host firmware runtime looks for data and/or additional code while
167099543e4SBrad Bishop  * bootstraping in files with well-known names.  findLinks uses the provided
168099543e4SBrad Bishop  * extensions argument to find host firmware blob files that require a
169099543e4SBrad Bishop  * well-known name.  When a blob is found, issue the provided callback
170099543e4SBrad Bishop  * (typically a function that will write a symlink).
171099543e4SBrad Bishop  *
172099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
173099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
174099543e4SBrad Bishop  * @param[in] extentions The extensions of the firmware blob files denote a
175099543e4SBrad Bishop  * host firmware blob file requires a well-known name.
176099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
177099543e4SBrad Bishop  * @param[in] linkCallback A callback made when host firmware blob files
178099543e4SBrad Bishop  * needing a well known name are found.
179099543e4SBrad Bishop  */
180099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory,
181099543e4SBrad Bishop                const std::vector<std::string>& extensions,
182099543e4SBrad Bishop                const ErrorCallbackType& errorCallback,
183099543e4SBrad Bishop                const LinkCallbackType& linkCallback)
184099543e4SBrad Bishop {
185099543e4SBrad Bishop     std::error_code ec;
186099543e4SBrad Bishop     std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory,
187099543e4SBrad Bishop                                                           ec);
188099543e4SBrad Bishop     if (ec)
189099543e4SBrad Bishop     {
190099543e4SBrad Bishop         makeCallback(errorCallback, hostFirmwareDirectory, ec);
191099543e4SBrad Bishop         return;
192099543e4SBrad Bishop     }
193099543e4SBrad Bishop 
194fdc91fa0SAdriana Kobylak     // Create a symlink from HBB to the corresponding LID file if it exists
195fdc91fa0SAdriana Kobylak     static const auto hbbLid = "81e0065a.lid";
196fdc91fa0SAdriana Kobylak     auto hbbLidPath = hostFirmwareDirectory / hbbLid;
197fdc91fa0SAdriana Kobylak     if (std::filesystem::exists(hbbLidPath))
198fdc91fa0SAdriana Kobylak     {
199fdc91fa0SAdriana Kobylak         static const auto hbbName = "HBB";
200fdc91fa0SAdriana Kobylak         auto hbbLinkPath = hostFirmwareDirectory / hbbName;
201fdc91fa0SAdriana Kobylak         makeCallback(linkCallback, hbbLid, hbbLinkPath, errorCallback);
202fdc91fa0SAdriana Kobylak     }
203fdc91fa0SAdriana Kobylak 
204099543e4SBrad Bishop     for (; directoryIterator != std::filesystem::end(directoryIterator);
205099543e4SBrad Bishop          directoryIterator.increment(ec))
206099543e4SBrad Bishop     {
207099543e4SBrad Bishop         const auto& file = directoryIterator->path();
208099543e4SBrad Bishop         if (ec)
209099543e4SBrad Bishop         {
210099543e4SBrad Bishop             makeCallback(errorCallback, file, ec);
211099543e4SBrad Bishop             // quit here if the increment call failed otherwise the loop may
212099543e4SBrad Bishop             // never finish
213099543e4SBrad Bishop             break;
214099543e4SBrad Bishop         }
215099543e4SBrad Bishop 
216099543e4SBrad Bishop         if (std::find(extensions.begin(), extensions.end(), file.extension()) ==
217099543e4SBrad Bishop             extensions.end())
218099543e4SBrad Bishop         {
219099543e4SBrad Bishop             // this file doesn't have an extension or doesn't match any of the
220099543e4SBrad Bishop             // provided extensions.
221099543e4SBrad Bishop             continue;
222099543e4SBrad Bishop         }
223099543e4SBrad Bishop 
224099543e4SBrad Bishop         auto linkPath(file.parent_path().append(
225099543e4SBrad Bishop             static_cast<const std::string&>(file.stem())));
226099543e4SBrad Bishop 
227099543e4SBrad Bishop         makeCallback(linkCallback, file.filename(), linkPath, errorCallback);
228099543e4SBrad Bishop     }
229099543e4SBrad Bishop }
230099543e4SBrad Bishop 
231099543e4SBrad Bishop /**
232ae0998f1SAdriana Kobylak  * @brief Parse the elements json file and construct a string with the data to
233ae0998f1SAdriana Kobylak  *        be used to update the bios attribute table.
234ae0998f1SAdriana Kobylak  *
235ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath - The path to the host firmware json file.
236ae0998f1SAdriana Kobylak  * @param[in] extensions - The extensions of the firmware blob files.
23753a27395SAdriana Kobylak  */
238ae0998f1SAdriana Kobylak std::string getBiosAttrStr(const std::filesystem::path& elementsJsonFilePath,
239ae0998f1SAdriana Kobylak                            const std::vector<std::string>& extensions)
24056f538caSAdriana Kobylak {
24156f538caSAdriana Kobylak     std::string biosAttrStr{};
24256f538caSAdriana Kobylak 
243ae0998f1SAdriana Kobylak     std::ifstream jsonFile(elementsJsonFilePath.c_str());
244ae0998f1SAdriana Kobylak     if (!jsonFile)
245ae0998f1SAdriana Kobylak     {
246ae0998f1SAdriana Kobylak         return {};
247ae0998f1SAdriana Kobylak     }
248ae0998f1SAdriana Kobylak 
249ae0998f1SAdriana Kobylak     std::map<std::string, std::string> attr;
250ae0998f1SAdriana Kobylak     auto data = nlohmann::json::parse(jsonFile, nullptr, false);
251ae0998f1SAdriana Kobylak     if (data.is_discarded())
252ae0998f1SAdriana Kobylak     {
253ae0998f1SAdriana Kobylak         log<level::ERR>("Error parsing JSON file",
254ae0998f1SAdriana Kobylak                         entry("FILE=%s", elementsJsonFilePath.c_str()));
255ae0998f1SAdriana Kobylak         return {};
256ae0998f1SAdriana Kobylak     }
257ae0998f1SAdriana Kobylak 
258ae0998f1SAdriana Kobylak     // .get requires a non-const iterator
259ae0998f1SAdriana Kobylak     for (auto& iter : data["lids"])
260ae0998f1SAdriana Kobylak     {
261ae0998f1SAdriana Kobylak         std::string name{};
262ae0998f1SAdriana Kobylak         std::string lid{};
263ae0998f1SAdriana Kobylak 
264ae0998f1SAdriana Kobylak         try
265ae0998f1SAdriana Kobylak         {
266ae0998f1SAdriana Kobylak             name = iter["element_name"].get<std::string>();
267ae0998f1SAdriana Kobylak             lid = iter["short_lid_name"].get<std::string>();
268ae0998f1SAdriana Kobylak         }
269ae0998f1SAdriana Kobylak         catch (std::exception& e)
270ae0998f1SAdriana Kobylak         {
271ae0998f1SAdriana Kobylak             // Possibly the element or lid name field was not found
272ae0998f1SAdriana Kobylak             log<level::ERR>("Error reading JSON field",
273ae0998f1SAdriana Kobylak                             entry("FILE=%s", elementsJsonFilePath.c_str()),
274ae0998f1SAdriana Kobylak                             entry("ERROR=%s", e.what()));
275ae0998f1SAdriana Kobylak             continue;
276ae0998f1SAdriana Kobylak         }
277ae0998f1SAdriana Kobylak 
278ae0998f1SAdriana Kobylak         // The elements with the ipl extension have higher priority. Therefore
279ae0998f1SAdriana Kobylak         // Use operator[] to overwrite value if an entry for it already exists.
280ae0998f1SAdriana Kobylak         // Ex: if the JSON contains an entry A.P10 followed by A.P10.iplTime,
281ae0998f1SAdriana Kobylak         // the lid value for the latter one will be overwrite the value of the
282ae0998f1SAdriana Kobylak         // first one.
283ae0998f1SAdriana Kobylak         constexpr auto iplExtension = ".iplTime";
284ae0998f1SAdriana Kobylak         std::filesystem::path path(name);
285ae0998f1SAdriana Kobylak         if (path.extension() == iplExtension)
286ae0998f1SAdriana Kobylak         {
287ae0998f1SAdriana Kobylak             // Some elements have an additional extension, ex: .P10.iplTime
288ae0998f1SAdriana Kobylak             // Strip off the ipl extension with stem(), then check if there is
289ae0998f1SAdriana Kobylak             // an additional extension with extension().
290ae0998f1SAdriana Kobylak             if (!path.stem().extension().empty())
291ae0998f1SAdriana Kobylak             {
292ae0998f1SAdriana Kobylak                 // Check if the extension matches the extensions for this system
293ae0998f1SAdriana Kobylak                 if (std::find(extensions.begin(), extensions.end(),
294ae0998f1SAdriana Kobylak                               path.stem().extension()) == extensions.end())
295ae0998f1SAdriana Kobylak                 {
296ae0998f1SAdriana Kobylak                     continue;
297ae0998f1SAdriana Kobylak                 }
298ae0998f1SAdriana Kobylak             }
299ae0998f1SAdriana Kobylak             // Get the element name without extensions by calling stem() twice
300ae0998f1SAdriana Kobylak             // since stem() returns the base name if no periods are found.
301ae0998f1SAdriana Kobylak             // Therefore both "element.P10" and "element.P10.iplTime" would
302ae0998f1SAdriana Kobylak             // become "element".
303ae0998f1SAdriana Kobylak             attr[path.stem().stem()] = lid;
304ae0998f1SAdriana Kobylak             continue;
305ae0998f1SAdriana Kobylak         }
306ae0998f1SAdriana Kobylak 
307ae0998f1SAdriana Kobylak         // Process all other extensions. The extension should match the list of
308ae0998f1SAdriana Kobylak         // supported extensions for this system. Use .insert() to only add
309ae0998f1SAdriana Kobylak         // entries that do not exist, so to not overwrite the values that may
310ae0998f1SAdriana Kobylak         // had been added that had the ipl extension.
311ae0998f1SAdriana Kobylak         if (std::find(extensions.begin(), extensions.end(), path.extension()) !=
312ae0998f1SAdriana Kobylak             extensions.end())
313ae0998f1SAdriana Kobylak         {
314ae0998f1SAdriana Kobylak             attr.insert({path.stem(), lid});
315ae0998f1SAdriana Kobylak         }
316ae0998f1SAdriana Kobylak     }
317ae0998f1SAdriana Kobylak     for (const auto& a : attr)
318ae0998f1SAdriana Kobylak     {
319ae0998f1SAdriana Kobylak         // Build the bios attribute string with format:
320ae0998f1SAdriana Kobylak         // "element1=lid1,element2=lid2,elementN=lidN,"
321ae0998f1SAdriana Kobylak         biosAttrStr += a.first + "=" + a.second + ",";
322ae0998f1SAdriana Kobylak     }
323ae0998f1SAdriana Kobylak 
324ae0998f1SAdriana Kobylak     return biosAttrStr;
325ae0998f1SAdriana Kobylak }
326ae0998f1SAdriana Kobylak 
327ae0998f1SAdriana Kobylak /**
328ae0998f1SAdriana Kobylak  * @brief Set the bios attribute table with details of the host firmware data
329ae0998f1SAdriana Kobylak  * for this system.
330ae0998f1SAdriana Kobylak  *
331ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath - The path to the host firmware json file.
332ae0998f1SAdriana Kobylak  * @param[in] extentions - The extensions of the firmware blob files.
333ae0998f1SAdriana Kobylak  */
334ae0998f1SAdriana Kobylak void setBiosAttr(const std::filesystem::path& elementsJsonFilePath,
335ae0998f1SAdriana Kobylak                  const std::vector<std::string>& extensions)
336ae0998f1SAdriana Kobylak {
337ae0998f1SAdriana Kobylak     auto biosAttrStr = getBiosAttrStr(elementsJsonFilePath, extensions);
338ae0998f1SAdriana Kobylak 
33956f538caSAdriana Kobylak     constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager";
34056f538caSAdriana Kobylak     constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager";
34156f538caSAdriana Kobylak     constexpr auto dbusAttrName = "hb_lid_ids";
34256f538caSAdriana Kobylak     constexpr auto dbusAttrType =
34356f538caSAdriana Kobylak         "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
34456f538caSAdriana Kobylak 
34556f538caSAdriana Kobylak     using PendingAttributesType = std::vector<std::pair<
34656f538caSAdriana Kobylak         std::string, std::tuple<std::string, std::variant<std::string>>>>;
34756f538caSAdriana Kobylak     PendingAttributesType pendingAttributes;
34856f538caSAdriana Kobylak     pendingAttributes.emplace_back(std::make_pair(
34956f538caSAdriana Kobylak         dbusAttrName, std::make_tuple(dbusAttrType, biosAttrStr)));
35056f538caSAdriana Kobylak 
35156f538caSAdriana Kobylak     auto bus = sdbusplus::bus::new_default();
35256f538caSAdriana Kobylak     auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
35356f538caSAdriana Kobylak                                       MAPPER_INTERFACE, "GetObject");
35456f538caSAdriana Kobylak     method.append(biosConfigPath, std::vector<std::string>({biosConfigIntf}));
35556f538caSAdriana Kobylak     std::vector<std::pair<std::string, std::vector<std::string>>> response;
35656f538caSAdriana Kobylak     try
35756f538caSAdriana Kobylak     {
35856f538caSAdriana Kobylak         auto reply = bus.call(method);
35956f538caSAdriana Kobylak         reply.read(response);
36056f538caSAdriana Kobylak         if (response.empty())
36156f538caSAdriana Kobylak         {
36256f538caSAdriana Kobylak             log<level::ERR>("Error reading mapper response",
36356f538caSAdriana Kobylak                             entry("PATH=%s", biosConfigPath),
36456f538caSAdriana Kobylak                             entry("INTERFACE=%s", biosConfigIntf));
36556f538caSAdriana Kobylak             return;
36656f538caSAdriana Kobylak         }
36756f538caSAdriana Kobylak         auto method = bus.new_method_call((response.begin()->first).c_str(),
36856f538caSAdriana Kobylak                                           biosConfigPath,
36956f538caSAdriana Kobylak                                           SYSTEMD_PROPERTY_INTERFACE, "Set");
37056f538caSAdriana Kobylak         method.append(biosConfigIntf, "PendingAttributes",
37156f538caSAdriana Kobylak                       std::variant<PendingAttributesType>(pendingAttributes));
37256f538caSAdriana Kobylak         bus.call(method);
37356f538caSAdriana Kobylak     }
37456f538caSAdriana Kobylak     catch (const sdbusplus::exception::SdBusError& e)
37556f538caSAdriana Kobylak     {
37656f538caSAdriana Kobylak         log<level::ERR>("Error setting the bios attribute",
37756f538caSAdriana Kobylak                         entry("ERROR=%s", e.what()),
37856f538caSAdriana Kobylak                         entry("ATTRIBUTE=%s", dbusAttrName));
37956f538caSAdriana Kobylak         return;
38056f538caSAdriana Kobylak     }
38156f538caSAdriana Kobylak }
38253a27395SAdriana Kobylak 
38353a27395SAdriana Kobylak /**
384099543e4SBrad Bishop  * @brief Make callbacks on
385099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
386099543e4SBrad Bishop  *
387099543e4SBrad Bishop  * Look for an instance of
388099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
389099543e4SBrad Bishop  * argument and if found, issue the provided callback.
390099543e4SBrad Bishop  *
391099543e4SBrad Bishop  * @param[in] interfacesAndProperties the interfaces in which to look for an
392099543e4SBrad Bishop  * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem
393099543e4SBrad Bishop  * @param[in] callback the user callback to make if
394099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
395099543e4SBrad Bishop  * interfacesAndProperties
396099543e4SBrad Bishop  * @return true if interfacesAndProperties contained an instance of
397099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
398099543e4SBrad Bishop  */
399099543e4SBrad Bishop bool maybeCall(const std::map<std::string,
400099543e4SBrad Bishop                               std::map<std::string,
401099543e4SBrad Bishop                                        std::variant<std::vector<std::string>>>>&
402099543e4SBrad Bishop                    interfacesAndProperties,
403099543e4SBrad Bishop                const MaybeCallCallbackType& callback)
404099543e4SBrad Bishop {
405099543e4SBrad Bishop     using namespace std::string_literals;
406099543e4SBrad Bishop 
407099543e4SBrad Bishop     static const auto interfaceName =
408099543e4SBrad Bishop         "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s;
409099543e4SBrad Bishop     auto interfaceIterator = interfacesAndProperties.find(interfaceName);
410099543e4SBrad Bishop     if (interfaceIterator == interfacesAndProperties.cend())
411099543e4SBrad Bishop     {
412099543e4SBrad Bishop         // IBMCompatibleSystem interface not found, so instruct the caller to
413099543e4SBrad Bishop         // keep waiting or try again later.
414099543e4SBrad Bishop         return false;
415099543e4SBrad Bishop     }
416099543e4SBrad Bishop     auto propertyIterator = interfaceIterator->second.find("Names"s);
417099543e4SBrad Bishop     if (propertyIterator == interfaceIterator->second.cend())
418099543e4SBrad Bishop     {
419099543e4SBrad Bishop         // The interface exists but the property doesn't.  This is a bug in the
420099543e4SBrad Bishop         // IBMCompatibleSystem implementation.  The caller should not try
421099543e4SBrad Bishop         // again.
422099543e4SBrad Bishop         std::cerr << "Names property not implemented on " << interfaceName
423099543e4SBrad Bishop                   << "\n";
424099543e4SBrad Bishop         return true;
425099543e4SBrad Bishop     }
426099543e4SBrad Bishop 
427099543e4SBrad Bishop     const auto& ibmCompatibleSystem =
428099543e4SBrad Bishop         std::get<std::vector<std::string>>(propertyIterator->second);
429099543e4SBrad Bishop     if (callback)
430099543e4SBrad Bishop     {
431099543e4SBrad Bishop         callback(ibmCompatibleSystem);
432099543e4SBrad Bishop     }
433099543e4SBrad Bishop 
434099543e4SBrad Bishop     // IBMCompatibleSystem found and callback issued.
435099543e4SBrad Bishop     return true;
436099543e4SBrad Bishop }
437099543e4SBrad Bishop 
438099543e4SBrad Bishop /**
439099543e4SBrad Bishop  * @brief Make callbacks on
440099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
441099543e4SBrad Bishop  *
442099543e4SBrad Bishop  * Look for an instance of
443099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
444099543e4SBrad Bishop  * argument and if found, issue the provided callback.
445099543e4SBrad Bishop  *
446099543e4SBrad Bishop  * @param[in] message the DBus message in which to look for an instance of
447099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
448099543e4SBrad Bishop  * @param[in] callback the user callback to make if
449099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
450099543e4SBrad Bishop  * message
451099543e4SBrad Bishop  * @return true if message contained an instance of
452099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
453099543e4SBrad Bishop  */
454099543e4SBrad Bishop bool maybeCallMessage(sdbusplus::message::message& message,
455099543e4SBrad Bishop                       const MaybeCallCallbackType& callback)
456099543e4SBrad Bishop {
457099543e4SBrad Bishop     std::map<std::string,
458099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
459099543e4SBrad Bishop         interfacesAndProperties;
460099543e4SBrad Bishop     sdbusplus::message::object_path _;
461099543e4SBrad Bishop     message.read(_, interfacesAndProperties);
462099543e4SBrad Bishop     return maybeCall(interfacesAndProperties, callback);
463099543e4SBrad Bishop }
464099543e4SBrad Bishop 
465099543e4SBrad Bishop /**
466099543e4SBrad Bishop  * @brief Determine system support for host firmware well-known names.
467099543e4SBrad Bishop  *
468099543e4SBrad Bishop  * Using the provided extensionMap and
469099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if
470099543e4SBrad Bishop  * well-known names for host firmare blob files are necessary and if so, create
471099543e4SBrad Bishop  * them.
472099543e4SBrad Bishop  *
473099543e4SBrad Bishop  * @param[in] extensionMap a map of
474099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
475099543e4SBrad Bishop  * file extensions.
476099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
477099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
478099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
479099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
480099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
481099543e4SBrad Bishop  */
482099543e4SBrad Bishop void maybeMakeLinks(
483099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
484099543e4SBrad Bishop     const std::filesystem::path& hostFirmwareDirectory,
485099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
486099543e4SBrad Bishop     const ErrorCallbackType& errorCallback)
487099543e4SBrad Bishop {
488099543e4SBrad Bishop     std::vector<std::string> extensions;
489099543e4SBrad Bishop     if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
490099543e4SBrad Bishop                                             extensions))
491099543e4SBrad Bishop     {
492099543e4SBrad Bishop         findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink);
493099543e4SBrad Bishop     }
494099543e4SBrad Bishop }
495099543e4SBrad Bishop 
496099543e4SBrad Bishop /**
49753a27395SAdriana Kobylak  * @brief Determine system support for updating the bios attribute table.
49853a27395SAdriana Kobylak  *
49953a27395SAdriana Kobylak  * Using the provided extensionMap and
50053a27395SAdriana Kobylak  * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if the bios
50153a27395SAdriana Kobylak  * attribute table needs to be updated.
50253a27395SAdriana Kobylak  *
50353a27395SAdriana Kobylak  * @param[in] extensionMap a map of
50453a27395SAdriana Kobylak  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
50553a27395SAdriana Kobylak  * file extensions.
506ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath The file path to the json file
50753a27395SAdriana Kobylak  * @param[in] ibmCompatibleSystem The names property of an instance of
50853a27395SAdriana Kobylak  * xyz.openbmc_project.Configuration.IBMCompatibleSystem
50953a27395SAdriana Kobylak  */
51053a27395SAdriana Kobylak void maybeSetBiosAttr(
51153a27395SAdriana Kobylak     const std::map<std::string, std::vector<std::string>>& extensionMap,
512ae0998f1SAdriana Kobylak     const std::filesystem::path& elementsJsonFilePath,
51353a27395SAdriana Kobylak     const std::vector<std::string>& ibmCompatibleSystem)
51453a27395SAdriana Kobylak {
51553a27395SAdriana Kobylak     std::vector<std::string> extensions;
51653a27395SAdriana Kobylak     if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
51753a27395SAdriana Kobylak                                             extensions))
51853a27395SAdriana Kobylak     {
519ae0998f1SAdriana Kobylak         setBiosAttr(elementsJsonFilePath, extensions);
52053a27395SAdriana Kobylak     }
52153a27395SAdriana Kobylak }
52253a27395SAdriana Kobylak 
52353a27395SAdriana Kobylak /**
524099543e4SBrad Bishop  * @brief process host firmware
525099543e4SBrad Bishop  *
526099543e4SBrad Bishop  * Allocate a callback context and register for DBus.ObjectManager Interfaces
527099543e4SBrad Bishop  * added signals from entity manager.
528099543e4SBrad Bishop  *
529099543e4SBrad Bishop  * Check the current entity manager object tree for a
530099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity
531099543e4SBrad Bishop  * manager will be dbus activated if it is not running).  If one is found,
532099543e4SBrad Bishop  * determine if symlinks need to be created and create them.  Instruct the
533099543e4SBrad Bishop  * program event loop to exit.
534099543e4SBrad Bishop  *
535099543e4SBrad Bishop  * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
536099543e4SBrad Bishop  * found return the callback context to main, where the program will sleep
537099543e4SBrad Bishop  * until the callback is invoked one or more times and instructs the program
538099543e4SBrad Bishop  * event loop to exit when
539099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added.
540099543e4SBrad Bishop  *
541099543e4SBrad Bishop  * @param[in] bus a DBus client connection
542099543e4SBrad Bishop  * @param[in] extensionMap a map of
543099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
544099543e4SBrad Bishop  * file extensions.
545099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which processHostFirmware
546099543e4SBrad Bishop  * should look for blob files.
547099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
548099543e4SBrad Bishop  * @param[in] loop a program event loop
549099543e4SBrad Bishop  * @return nullptr if an instance of
550099543e4SBrad Bishop  * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a
551099543e4SBrad Bishop  * pointer to an sdbusplus match object.
552099543e4SBrad Bishop  */
553099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware(
554099543e4SBrad Bishop     sdbusplus::bus::bus& bus,
555099543e4SBrad Bishop     std::map<std::string, std::vector<std::string>> extensionMap,
556099543e4SBrad Bishop     std::filesystem::path hostFirmwareDirectory,
557099543e4SBrad Bishop     ErrorCallbackType errorCallback, sdeventplus::Event& loop)
558099543e4SBrad Bishop {
559099543e4SBrad Bishop     // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't
560099543e4SBrad Bishop     // be transfered to the match callback because they are needed in the non
561099543e4SBrad Bishop     // async part of this function below, so they need to be moved to the heap.
562099543e4SBrad Bishop     auto pExtensionMap =
563099543e4SBrad Bishop         std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
564099543e4SBrad Bishop     auto pHostFirmwareDirectory =
565099543e4SBrad Bishop         std::make_shared<decltype(hostFirmwareDirectory)>(
566099543e4SBrad Bishop             std::move(hostFirmwareDirectory));
567099543e4SBrad Bishop     auto pErrorCallback =
568099543e4SBrad Bishop         std::make_shared<decltype(errorCallback)>(std::move(errorCallback));
569099543e4SBrad Bishop 
570099543e4SBrad Bishop     // register for a callback in case the IBMCompatibleSystem interface has
571099543e4SBrad Bishop     // not yet been published by entity manager.
572099543e4SBrad Bishop     auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>(
573099543e4SBrad Bishop         bus,
574099543e4SBrad Bishop         sdbusplus::bus::match::rules::interfacesAdded() +
575099543e4SBrad Bishop             sdbusplus::bus::match::rules::sender(
576099543e4SBrad Bishop                 "xyz.openbmc_project.EntityManager"),
577099543e4SBrad Bishop         [pExtensionMap, pHostFirmwareDirectory, pErrorCallback,
578099543e4SBrad Bishop          &loop](auto& message) {
579099543e4SBrad Bishop             // bind the extension map, host firmware directory, and error
580099543e4SBrad Bishop             // callback to the maybeMakeLinks function.
581099543e4SBrad Bishop             auto maybeMakeLinksWithArgsBound =
582099543e4SBrad Bishop                 std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
583099543e4SBrad Bishop                           std::cref(*pHostFirmwareDirectory),
584099543e4SBrad Bishop                           std::placeholders::_1, std::cref(*pErrorCallback));
585099543e4SBrad Bishop 
586099543e4SBrad Bishop             // if the InterfacesAdded message contains an an instance of
587099543e4SBrad Bishop             // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to
588099543e4SBrad Bishop             // see if links are necessary on this system and if so, create
589099543e4SBrad Bishop             // them.
590099543e4SBrad Bishop             if (maybeCallMessage(message, maybeMakeLinksWithArgsBound))
591099543e4SBrad Bishop             {
592099543e4SBrad Bishop                 // The IBMCompatibleSystem interface was found and the links
593099543e4SBrad Bishop                 // were created if applicable.  Instruct the event loop /
594099543e4SBrad Bishop                 // subcommand to exit.
595099543e4SBrad Bishop                 loop.exit(0);
596099543e4SBrad Bishop             }
597099543e4SBrad Bishop         });
598099543e4SBrad Bishop 
599099543e4SBrad Bishop     // now that we'll get a callback in the event of an InterfacesAdded signal
600099543e4SBrad Bishop     // (potentially containing
601099543e4SBrad Bishop     // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity
602099543e4SBrad Bishop     // manager if it isn't running and enumerate its objects
603099543e4SBrad Bishop     auto getManagedObjects = bus.new_method_call(
604099543e4SBrad Bishop         "xyz.openbmc_project.EntityManager", "/",
605099543e4SBrad Bishop         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
606099543e4SBrad Bishop     std::map<std::string,
607099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
608099543e4SBrad Bishop         interfacesAndProperties;
609099543e4SBrad Bishop     std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
610099543e4SBrad Bishop         objects;
611c79fa915SAdriana Kobylak     try
612c79fa915SAdriana Kobylak     {
613c79fa915SAdriana Kobylak         auto reply = bus.call(getManagedObjects);
614099543e4SBrad Bishop         reply.read(objects);
615c79fa915SAdriana Kobylak     }
616c79fa915SAdriana Kobylak     catch (const sdbusplus::exception::SdBusError& e)
617c79fa915SAdriana Kobylak     {
618c79fa915SAdriana Kobylak         // Error querying the EntityManager interface. Return the match to have
619c79fa915SAdriana Kobylak         // the callback run if/when the interface appears in D-Bus.
620c79fa915SAdriana Kobylak         return interfacesAddedMatch;
621c79fa915SAdriana Kobylak     }
622099543e4SBrad Bishop 
623099543e4SBrad Bishop     // bind the extension map, host firmware directory, and error callback to
624099543e4SBrad Bishop     // the maybeMakeLinks function.
625099543e4SBrad Bishop     auto maybeMakeLinksWithArgsBound =
626099543e4SBrad Bishop         std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
627099543e4SBrad Bishop                   std::cref(*pHostFirmwareDirectory), std::placeholders::_1,
628099543e4SBrad Bishop                   std::cref(*pErrorCallback));
629099543e4SBrad Bishop 
630099543e4SBrad Bishop     for (const auto& pair : objects)
631099543e4SBrad Bishop     {
632099543e4SBrad Bishop         std::tie(std::ignore, interfacesAndProperties) = pair;
633099543e4SBrad Bishop         // if interfacesAndProperties contains an an instance of
634099543e4SBrad Bishop         // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see
635099543e4SBrad Bishop         // if links are necessary on this system and if so, create them
636099543e4SBrad Bishop         if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound))
637099543e4SBrad Bishop         {
638099543e4SBrad Bishop             // The IBMCompatibleSystem interface is already on the bus and the
639099543e4SBrad Bishop             // links were created if applicable.  Instruct the event loop to
640099543e4SBrad Bishop             // exit.
641099543e4SBrad Bishop             loop.exit(0);
642099543e4SBrad Bishop             // The match object isn't needed anymore, so destroy it on return.
643099543e4SBrad Bishop             return nullptr;
644099543e4SBrad Bishop         }
645099543e4SBrad Bishop     }
646099543e4SBrad Bishop 
647099543e4SBrad Bishop     // The IBMCompatibleSystem interface has not yet been published.  Move
648099543e4SBrad Bishop     // ownership of the match callback to the caller.
649099543e4SBrad Bishop     return interfacesAddedMatch;
650099543e4SBrad Bishop }
65153a27395SAdriana Kobylak 
65253a27395SAdriana Kobylak /**
65353a27395SAdriana Kobylak  * @brief Update the Bios Attribute Table
65453a27395SAdriana Kobylak  *
65553a27395SAdriana Kobylak  * If an instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
65653a27395SAdriana Kobylak  * found, update the Bios Attribute Table with the appropriate host firmware
65753a27395SAdriana Kobylak  * data.
65853a27395SAdriana Kobylak  *
65953a27395SAdriana Kobylak  * @param[in] bus - D-Bus client connection.
66053a27395SAdriana Kobylak  * @param[in] extensionMap - Map of IBMCompatibleSystem names and host firmware
66153a27395SAdriana Kobylak  *                           file extensions.
662ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath - The Path to the json file
66353a27395SAdriana Kobylak  * @param[in] loop - Program event loop.
66453a27395SAdriana Kobylak  * @return nullptr
66553a27395SAdriana Kobylak  */
66653a27395SAdriana Kobylak std::shared_ptr<void> updateBiosAttrTable(
66753a27395SAdriana Kobylak     sdbusplus::bus::bus& bus,
66853a27395SAdriana Kobylak     std::map<std::string, std::vector<std::string>> extensionMap,
669ae0998f1SAdriana Kobylak     std::filesystem::path elementsJsonFilePath, sdeventplus::Event& loop)
67053a27395SAdriana Kobylak {
671*d0379ea5SAdriana Kobylak     constexpr auto pldmPath = "/xyz/openbmc_project/pldm";
672*d0379ea5SAdriana Kobylak 
67353a27395SAdriana Kobylak     auto pExtensionMap =
67453a27395SAdriana Kobylak         std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
675ae0998f1SAdriana Kobylak     auto pElementsJsonFilePath =
676ae0998f1SAdriana Kobylak         std::make_shared<decltype(elementsJsonFilePath)>(
677ae0998f1SAdriana Kobylak             std::move(elementsJsonFilePath));
67853a27395SAdriana Kobylak 
679*d0379ea5SAdriana Kobylak     // Entity Manager is needed to get the list of supported extensions. Add a
680*d0379ea5SAdriana Kobylak     // match to monitor interfaces added in case it's not running yet.
681*d0379ea5SAdriana Kobylak     auto maybeSetAttrWithArgsBound =
682*d0379ea5SAdriana Kobylak         std::bind(maybeSetBiosAttr, std::cref(*pExtensionMap),
683*d0379ea5SAdriana Kobylak                   std::cref(*pElementsJsonFilePath), std::placeholders::_1);
684*d0379ea5SAdriana Kobylak 
685*d0379ea5SAdriana Kobylak     auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>(
686*d0379ea5SAdriana Kobylak         bus,
687*d0379ea5SAdriana Kobylak         sdbusplus::bus::match::rules::interfacesAdded() +
688*d0379ea5SAdriana Kobylak             sdbusplus::bus::match::rules::sender(
689*d0379ea5SAdriana Kobylak                 "xyz.openbmc_project.EntityManager"),
690*d0379ea5SAdriana Kobylak         [pldmPath, pExtensionMap, pElementsJsonFilePath,
691*d0379ea5SAdriana Kobylak          maybeSetAttrWithArgsBound, &loop](auto& message) {
692*d0379ea5SAdriana Kobylak             auto bus = sdbusplus::bus::new_default();
693fd4a6088SAdriana Kobylak             auto pldmObject = getObject(bus, pldmPath);
694fd4a6088SAdriana Kobylak             if (pldmObject.empty())
695fd4a6088SAdriana Kobylak             {
696*d0379ea5SAdriana Kobylak                 return;
697*d0379ea5SAdriana Kobylak             }
698*d0379ea5SAdriana Kobylak             if (maybeCallMessage(message, maybeSetAttrWithArgsBound))
699*d0379ea5SAdriana Kobylak             {
700fd4a6088SAdriana Kobylak                 loop.exit(0);
701*d0379ea5SAdriana Kobylak             }
702*d0379ea5SAdriana Kobylak         });
703*d0379ea5SAdriana Kobylak 
704*d0379ea5SAdriana Kobylak     // The BIOS attribute table can only be updated if PLDM is running because
705*d0379ea5SAdriana Kobylak     // PLDM is the one that exposes this property. Return if it's not running.
706*d0379ea5SAdriana Kobylak     auto pldmObject = getObject(bus, pldmPath);
707*d0379ea5SAdriana Kobylak     if (pldmObject.empty())
708*d0379ea5SAdriana Kobylak     {
709*d0379ea5SAdriana Kobylak         return interfacesAddedMatch;
710fd4a6088SAdriana Kobylak     }
711fd4a6088SAdriana Kobylak 
71253a27395SAdriana Kobylak     auto getManagedObjects = bus.new_method_call(
71353a27395SAdriana Kobylak         "xyz.openbmc_project.EntityManager", "/",
71453a27395SAdriana Kobylak         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
71553a27395SAdriana Kobylak     std::map<std::string,
71653a27395SAdriana Kobylak              std::map<std::string, std::variant<std::vector<std::string>>>>
71753a27395SAdriana Kobylak         interfacesAndProperties;
71853a27395SAdriana Kobylak     std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
71953a27395SAdriana Kobylak         objects;
72053a27395SAdriana Kobylak     try
72153a27395SAdriana Kobylak     {
72253a27395SAdriana Kobylak         auto reply = bus.call(getManagedObjects);
72353a27395SAdriana Kobylak         reply.read(objects);
72453a27395SAdriana Kobylak     }
72553a27395SAdriana Kobylak     catch (const sdbusplus::exception::SdBusError& e)
72653a27395SAdriana Kobylak     {}
72753a27395SAdriana Kobylak 
72853a27395SAdriana Kobylak     for (const auto& pair : objects)
72953a27395SAdriana Kobylak     {
73053a27395SAdriana Kobylak         std::tie(std::ignore, interfacesAndProperties) = pair;
73153a27395SAdriana Kobylak         if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound))
73253a27395SAdriana Kobylak         {
733*d0379ea5SAdriana Kobylak             loop.exit(0);
734*d0379ea5SAdriana Kobylak             return nullptr;
73553a27395SAdriana Kobylak         }
73653a27395SAdriana Kobylak     }
73753a27395SAdriana Kobylak 
738*d0379ea5SAdriana Kobylak     return interfacesAddedMatch;
73953a27395SAdriana Kobylak }
74053a27395SAdriana Kobylak 
741099543e4SBrad Bishop } // namespace process_hostfirmware
742099543e4SBrad Bishop } // namespace functions
743