1099543e4SBrad Bishop // SPDX-License-Identifier: Apache-2.0
2099543e4SBrad Bishop 
3099543e4SBrad Bishop /**@file functions.cpp*/
4099543e4SBrad Bishop 
556f538caSAdriana Kobylak #include "config.h"
656f538caSAdriana Kobylak 
7099543e4SBrad Bishop #include "functions.hpp"
8099543e4SBrad Bishop 
9ae0998f1SAdriana Kobylak #include <nlohmann/json.hpp>
1056f538caSAdriana Kobylak #include <phosphor-logging/log.hpp>
11099543e4SBrad Bishop #include <sdbusplus/bus.hpp>
12099543e4SBrad Bishop #include <sdbusplus/bus/match.hpp>
13c79fa915SAdriana Kobylak #include <sdbusplus/exception.hpp>
14099543e4SBrad Bishop #include <sdbusplus/message.hpp>
15099543e4SBrad Bishop #include <sdeventplus/event.hpp>
162b78eb0eSAdriana Kobylak #include <xyz/openbmc_project/Common/error.hpp>
17099543e4SBrad Bishop 
18099543e4SBrad Bishop #include <filesystem>
19ae0998f1SAdriana Kobylak #include <fstream>
20099543e4SBrad Bishop #include <functional>
21099543e4SBrad Bishop #include <iostream>
22099543e4SBrad Bishop #include <map>
23099543e4SBrad Bishop #include <memory>
24099543e4SBrad Bishop #include <string>
25099543e4SBrad Bishop #include <variant>
26099543e4SBrad Bishop #include <vector>
27099543e4SBrad Bishop 
28099543e4SBrad Bishop namespace functions
29099543e4SBrad Bishop {
30099543e4SBrad Bishop namespace process_hostfirmware
31099543e4SBrad Bishop {
32099543e4SBrad Bishop 
3356f538caSAdriana Kobylak using namespace phosphor::logging;
34ebf67bf7SAdriana Kobylak using InterfacesPropertiesMap =
35ebf67bf7SAdriana Kobylak     std::map<std::string,
36ebf67bf7SAdriana Kobylak              std::map<std::string, std::variant<std::vector<std::string>>>>;
37ebf67bf7SAdriana Kobylak using ManagedObjectType =
38ebf67bf7SAdriana Kobylak     std::map<sdbusplus::message::object_path, InterfacesPropertiesMap>;
3956f538caSAdriana Kobylak 
40099543e4SBrad Bishop /**
41ebf67bf7SAdriana Kobylak  * @brief Returns the managed objects for a given service
42ebf67bf7SAdriana Kobylak  */
getManagedObjects(sdbusplus::bus_t & bus,const std::string & service,const std::string & managerPath)430dea1992SPatrick Williams ManagedObjectType getManagedObjects(sdbusplus::bus_t& bus,
4475352b42SNan Zhou                                     const std::string& service,
4575352b42SNan Zhou                                     const std::string& managerPath)
4675352b42SNan Zhou 
47ebf67bf7SAdriana Kobylak {
4875352b42SNan Zhou     auto method = bus.new_method_call(service.c_str(), managerPath.c_str(),
49ebf67bf7SAdriana Kobylak                                       "org.freedesktop.DBus.ObjectManager",
50ebf67bf7SAdriana Kobylak                                       "GetManagedObjects");
51ebf67bf7SAdriana Kobylak 
52ebf67bf7SAdriana Kobylak     ManagedObjectType objects;
53ebf67bf7SAdriana Kobylak 
54ebf67bf7SAdriana Kobylak     try
55ebf67bf7SAdriana Kobylak     {
56ebf67bf7SAdriana Kobylak         auto reply = bus.call(method);
57ebf67bf7SAdriana Kobylak         reply.read(objects);
58ebf67bf7SAdriana Kobylak     }
590dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
60ebf67bf7SAdriana Kobylak     {
61ebf67bf7SAdriana Kobylak         return ManagedObjectType{};
62ebf67bf7SAdriana Kobylak     }
63ebf67bf7SAdriana Kobylak     return objects;
64ebf67bf7SAdriana Kobylak }
65ebf67bf7SAdriana Kobylak 
66ebf67bf7SAdriana Kobylak /**
67099543e4SBrad Bishop  * @brief Issue callbacks safely
68099543e4SBrad Bishop  *
69099543e4SBrad Bishop  * std::function can be empty, so this wrapper method checks for that prior to
70099543e4SBrad Bishop  * calling it to avoid std::bad_function_call
71099543e4SBrad Bishop  *
72099543e4SBrad Bishop  * @tparam Sig the types of the std::function arguments
73099543e4SBrad Bishop  * @tparam Args the deduced argument types
74099543e4SBrad Bishop  * @param[in] callback the callback being wrapped
75099543e4SBrad Bishop  * @param[in] args the callback arguments
76099543e4SBrad Bishop  */
77099543e4SBrad Bishop template <typename... Sig, typename... Args>
makeCallback(const std::function<void (Sig...)> & callback,Args &&...args)78099543e4SBrad Bishop void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args)
79099543e4SBrad Bishop {
80099543e4SBrad Bishop     if (callback)
81099543e4SBrad Bishop     {
82099543e4SBrad Bishop         callback(std::forward<Args>(args)...);
83099543e4SBrad Bishop     }
84099543e4SBrad Bishop }
85099543e4SBrad Bishop 
86099543e4SBrad Bishop /**
87749bdcc9SAdriana Kobylak  * @brief Get file extensions for Compatible
88099543e4SBrad Bishop  *
89099543e4SBrad Bishop  * IBM host firmware can be deployed as blobs (files) in a filesystem. Host
90099543e4SBrad Bishop  * firmware blobs for different values of
91749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible are packaged with
92749bdcc9SAdriana Kobylak  * different filename extensions. getExtensionsForIbmCompatibleSystem maintains
93749bdcc9SAdriana Kobylak  * the mapping from a given value of
94749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible to an array of filename
95749bdcc9SAdriana Kobylak  * extensions.
96099543e4SBrad Bishop  *
97099543e4SBrad Bishop  * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and
98749bdcc9SAdriana Kobylak  * the extensions parameter is reset with the map entry. If no mapping is found
99749bdcc9SAdriana Kobylak  * getExtensionsForIbmCompatibleSystem returns false and extensions is
100099543e4SBrad Bishop  * unmodified.
101099543e4SBrad Bishop  *
102099543e4SBrad Bishop  * @param[in] extensionMap a map of
103749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file
104749bdcc9SAdriana Kobylak  * extensions.
105099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
106749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible
107*96442c88SManojkiran Eda  * @param[out] extensions the host firmware blob file extensions
108099543e4SBrad Bishop  * @return true if an entry was found, otherwise false
109099543e4SBrad Bishop  */
getExtensionsForIbmCompatibleSystem(const std::map<std::string,std::vector<std::string>> & extensionMap,const std::vector<std::string> & ibmCompatibleSystem,std::vector<std::string> & extensions)110099543e4SBrad Bishop bool getExtensionsForIbmCompatibleSystem(
111099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
112099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
113099543e4SBrad Bishop     std::vector<std::string>& extensions)
114099543e4SBrad Bishop {
115099543e4SBrad Bishop     for (const auto& system : ibmCompatibleSystem)
116099543e4SBrad Bishop     {
117099543e4SBrad Bishop         auto extensionMapIterator = extensionMap.find(system);
118099543e4SBrad Bishop         if (extensionMapIterator != extensionMap.end())
119099543e4SBrad Bishop         {
120099543e4SBrad Bishop             extensions = extensionMapIterator->second;
121099543e4SBrad Bishop             return true;
122099543e4SBrad Bishop         }
123099543e4SBrad Bishop     }
124099543e4SBrad Bishop 
125099543e4SBrad Bishop     return false;
126099543e4SBrad Bishop }
127099543e4SBrad Bishop 
128099543e4SBrad Bishop /**
129099543e4SBrad Bishop  * @brief Write host firmware well-known name
130099543e4SBrad Bishop  *
131099543e4SBrad Bishop  * A wrapper around std::filesystem::create_symlink that avoids EEXIST by
132099543e4SBrad Bishop  * deleting any pre-existing file.
133099543e4SBrad Bishop  *
134099543e4SBrad Bishop  * @param[in] linkTarget The link target argument to
135099543e4SBrad Bishop  * std::filesystem::create_symlink
136099543e4SBrad Bishop  * @param[in] linkPath The link path argument to std::filesystem::create_symlink
137099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
138099543e4SBrad Bishop  */
writeLink(const std::filesystem::path & linkTarget,const std::filesystem::path & linkPath,const ErrorCallbackType & errorCallback)139099543e4SBrad Bishop void writeLink(const std::filesystem::path& linkTarget,
140099543e4SBrad Bishop                const std::filesystem::path& linkPath,
141099543e4SBrad Bishop                const ErrorCallbackType& errorCallback)
142099543e4SBrad Bishop {
143099543e4SBrad Bishop     std::error_code ec;
144099543e4SBrad Bishop 
145099543e4SBrad Bishop     // remove files with the same name as the symlink to be created,
146099543e4SBrad Bishop     // otherwise symlink will fail with EEXIST.
147099543e4SBrad Bishop     if (!std::filesystem::remove(linkPath, ec))
148099543e4SBrad Bishop     {
149099543e4SBrad Bishop         if (ec)
150099543e4SBrad Bishop         {
151099543e4SBrad Bishop             makeCallback(errorCallback, linkPath, ec);
152099543e4SBrad Bishop             return;
153099543e4SBrad Bishop         }
154099543e4SBrad Bishop     }
155099543e4SBrad Bishop 
156099543e4SBrad Bishop     std::filesystem::create_symlink(linkTarget, linkPath, ec);
157099543e4SBrad Bishop     if (ec)
158099543e4SBrad Bishop     {
159099543e4SBrad Bishop         makeCallback(errorCallback, linkPath, ec);
160099543e4SBrad Bishop         return;
161099543e4SBrad Bishop     }
162099543e4SBrad Bishop }
163099543e4SBrad Bishop 
164099543e4SBrad Bishop /**
165099543e4SBrad Bishop  * @brief Find host firmware blob files that need well-known names
166099543e4SBrad Bishop  *
167099543e4SBrad Bishop  * The IBM host firmware runtime looks for data and/or additional code while
168*96442c88SManojkiran Eda  * bootstrapping in files with well-known names. findLinks uses the provided
169099543e4SBrad Bishop  * extensions argument to find host firmware blob files that require a
170099543e4SBrad Bishop  * well-known name. When a blob is found, issue the provided callback
171099543e4SBrad Bishop  * (typically a function that will write a symlink).
172099543e4SBrad Bishop  *
173099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which findLinks should
174099543e4SBrad Bishop  * look for host firmware blob files that need well-known names.
175*96442c88SManojkiran Eda  * @param[in] extensions The extensions of the firmware blob files denote a
176099543e4SBrad Bishop  * host firmware blob file requires a well-known name.
177099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
178099543e4SBrad Bishop  * @param[in] linkCallback A callback made when host firmware blob files
179099543e4SBrad Bishop  * needing a well known name are found.
180099543e4SBrad Bishop  */
findLinks(const std::filesystem::path & hostFirmwareDirectory,const std::vector<std::string> & extensions,const ErrorCallbackType & errorCallback,const LinkCallbackType & linkCallback)181099543e4SBrad Bishop void findLinks(const std::filesystem::path& hostFirmwareDirectory,
182099543e4SBrad Bishop                const std::vector<std::string>& extensions,
183099543e4SBrad Bishop                const ErrorCallbackType& errorCallback,
184099543e4SBrad Bishop                const LinkCallbackType& linkCallback)
185099543e4SBrad Bishop {
186099543e4SBrad Bishop     std::error_code ec;
187099543e4SBrad Bishop     std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory,
188099543e4SBrad Bishop                                                           ec);
189099543e4SBrad Bishop     if (ec)
190099543e4SBrad Bishop     {
191099543e4SBrad Bishop         makeCallback(errorCallback, hostFirmwareDirectory, ec);
192099543e4SBrad Bishop         return;
193099543e4SBrad Bishop     }
194099543e4SBrad Bishop 
1954e82bc84SAdriana Kobylak     // Create a symlink for pnor.toc
1964e82bc84SAdriana Kobylak     static const auto tocLid = "81e00994.lid";
1974e82bc84SAdriana Kobylak     auto tocLidPath = hostFirmwareDirectory / tocLid;
1984e82bc84SAdriana Kobylak     if (std::filesystem::exists(tocLidPath))
1994e82bc84SAdriana Kobylak     {
2004e82bc84SAdriana Kobylak         static const auto tocName = "pnor.toc";
2014e82bc84SAdriana Kobylak         auto tocLinkPath = hostFirmwareDirectory / tocName;
2024e82bc84SAdriana Kobylak         makeCallback(linkCallback, tocLid, tocLinkPath, errorCallback);
2034e82bc84SAdriana Kobylak     }
2044e82bc84SAdriana Kobylak 
205099543e4SBrad Bishop     for (; directoryIterator != std::filesystem::end(directoryIterator);
206099543e4SBrad Bishop          directoryIterator.increment(ec))
207099543e4SBrad Bishop     {
208099543e4SBrad Bishop         const auto& file = directoryIterator->path();
209099543e4SBrad Bishop         if (ec)
210099543e4SBrad Bishop         {
211099543e4SBrad Bishop             makeCallback(errorCallback, file, ec);
212099543e4SBrad Bishop             // quit here if the increment call failed otherwise the loop may
213099543e4SBrad Bishop             // never finish
214099543e4SBrad Bishop             break;
215099543e4SBrad Bishop         }
216099543e4SBrad Bishop 
217099543e4SBrad Bishop         if (std::find(extensions.begin(), extensions.end(), file.extension()) ==
218099543e4SBrad Bishop             extensions.end())
219099543e4SBrad Bishop         {
220099543e4SBrad Bishop             // this file doesn't have an extension or doesn't match any of the
221099543e4SBrad Bishop             // provided extensions.
222099543e4SBrad Bishop             continue;
223099543e4SBrad Bishop         }
224099543e4SBrad Bishop 
225099543e4SBrad Bishop         auto linkPath(file.parent_path().append(
226099543e4SBrad Bishop             static_cast<const std::string&>(file.stem())));
227099543e4SBrad Bishop 
228099543e4SBrad Bishop         makeCallback(linkCallback, file.filename(), linkPath, errorCallback);
229099543e4SBrad Bishop     }
230099543e4SBrad Bishop }
231099543e4SBrad Bishop 
232099543e4SBrad Bishop /**
233ae0998f1SAdriana Kobylak  * @brief Parse the elements json file and construct a string with the data to
234ae0998f1SAdriana Kobylak  *        be used to update the bios attribute table.
235ae0998f1SAdriana Kobylak  *
236ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath - The path to the host firmware json file.
237ae0998f1SAdriana Kobylak  * @param[in] extensions - The extensions of the firmware blob files.
23853a27395SAdriana Kobylak  */
getBiosAttrStr(const std::filesystem::path & elementsJsonFilePath,const std::vector<std::string> & extensions)239ae0998f1SAdriana Kobylak std::string getBiosAttrStr(const std::filesystem::path& elementsJsonFilePath,
240ae0998f1SAdriana Kobylak                            const std::vector<std::string>& extensions)
24156f538caSAdriana Kobylak {
24256f538caSAdriana Kobylak     std::string biosAttrStr{};
24356f538caSAdriana Kobylak 
244ae0998f1SAdriana Kobylak     std::ifstream jsonFile(elementsJsonFilePath.c_str());
245ae0998f1SAdriana Kobylak     if (!jsonFile)
246ae0998f1SAdriana Kobylak     {
247ae0998f1SAdriana Kobylak         return {};
248ae0998f1SAdriana Kobylak     }
249ae0998f1SAdriana Kobylak 
250ae0998f1SAdriana Kobylak     std::map<std::string, std::string> attr;
251ae0998f1SAdriana Kobylak     auto data = nlohmann::json::parse(jsonFile, nullptr, false);
252ae0998f1SAdriana Kobylak     if (data.is_discarded())
253ae0998f1SAdriana Kobylak     {
254ae0998f1SAdriana Kobylak         log<level::ERR>("Error parsing JSON file",
255ae0998f1SAdriana Kobylak                         entry("FILE=%s", elementsJsonFilePath.c_str()));
256ae0998f1SAdriana Kobylak         return {};
257ae0998f1SAdriana Kobylak     }
258ae0998f1SAdriana Kobylak 
259ae0998f1SAdriana Kobylak     // .get requires a non-const iterator
260ae0998f1SAdriana Kobylak     for (auto& iter : data["lids"])
261ae0998f1SAdriana Kobylak     {
262ae0998f1SAdriana Kobylak         std::string name{};
263ae0998f1SAdriana Kobylak         std::string lid{};
264ae0998f1SAdriana Kobylak 
265ae0998f1SAdriana Kobylak         try
266ae0998f1SAdriana Kobylak         {
267ae0998f1SAdriana Kobylak             name = iter["element_name"].get<std::string>();
268ae0998f1SAdriana Kobylak             lid = iter["short_lid_name"].get<std::string>();
269ae0998f1SAdriana Kobylak         }
27097a709b0SPatrick Williams         catch (const std::exception& e)
271ae0998f1SAdriana Kobylak         {
272ae0998f1SAdriana Kobylak             // Possibly the element or lid name field was not found
273ae0998f1SAdriana Kobylak             log<level::ERR>("Error reading JSON field",
274ae0998f1SAdriana Kobylak                             entry("FILE=%s", elementsJsonFilePath.c_str()),
275ae0998f1SAdriana Kobylak                             entry("ERROR=%s", e.what()));
276ae0998f1SAdriana Kobylak             continue;
277ae0998f1SAdriana Kobylak         }
278ae0998f1SAdriana Kobylak 
279ae0998f1SAdriana Kobylak         // The elements with the ipl extension have higher priority. Therefore
2809cbc06b1SAdriana Kobylak         // Use operator[] to overwrite value if an entry for it already exists,
2819cbc06b1SAdriana Kobylak         // and create a second entry with key name element_RT to specify it as
2829cbc06b1SAdriana Kobylak         // a runtime element.
2839cbc06b1SAdriana Kobylak         // Ex: if the JSON contains an entry A.P10 with lid name X, it'll create
2849cbc06b1SAdriana Kobylak         // and try A=X. If the JSON also contained an entry A.P10.iplTime with
2859cbc06b1SAdriana Kobylak         // lid name Y, the A entry would be overwritten to be A=Y and a second
2869cbc06b1SAdriana Kobylak         // entry A_RT=X would be created.
287ae0998f1SAdriana Kobylak         constexpr auto iplExtension = ".iplTime";
2889cbc06b1SAdriana Kobylak         constexpr auto runtimeSuffix = "_RT";
289ae0998f1SAdriana Kobylak         std::filesystem::path path(name);
290ae0998f1SAdriana Kobylak         if (path.extension() == iplExtension)
291ae0998f1SAdriana Kobylak         {
292ae0998f1SAdriana Kobylak             // Some elements have an additional extension, ex: .P10.iplTime
293ae0998f1SAdriana Kobylak             // Strip off the ipl extension with stem(), then check if there is
294ae0998f1SAdriana Kobylak             // an additional extension with extension().
295ae0998f1SAdriana Kobylak             if (!path.stem().extension().empty())
296ae0998f1SAdriana Kobylak             {
297ae0998f1SAdriana Kobylak                 // Check if the extension matches the extensions for this system
298ae0998f1SAdriana Kobylak                 if (std::find(extensions.begin(), extensions.end(),
299ae0998f1SAdriana Kobylak                               path.stem().extension()) == extensions.end())
300ae0998f1SAdriana Kobylak                 {
301ae0998f1SAdriana Kobylak                     continue;
302ae0998f1SAdriana Kobylak                 }
303ae0998f1SAdriana Kobylak             }
304ae0998f1SAdriana Kobylak             // Get the element name without extensions by calling stem() twice
305ae0998f1SAdriana Kobylak             // since stem() returns the base name if no periods are found.
306ae0998f1SAdriana Kobylak             // Therefore both "element.P10" and "element.P10.iplTime" would
307ae0998f1SAdriana Kobylak             // become "element".
3089cbc06b1SAdriana Kobylak             auto keyName = path.stem().stem();
3099cbc06b1SAdriana Kobylak             auto attrIt = attr.find(keyName);
3109cbc06b1SAdriana Kobylak             if (attrIt != attr.end())
3119cbc06b1SAdriana Kobylak             {
3129cbc06b1SAdriana Kobylak                 // Copy the existing entry to a runtime entry
3139cbc06b1SAdriana Kobylak                 auto runtimeKeyName = keyName.string() + runtimeSuffix;
3149cbc06b1SAdriana Kobylak                 attr.insert({runtimeKeyName, attrIt->second});
3159cbc06b1SAdriana Kobylak             }
316*96442c88SManojkiran Eda             // Overwrite the existing element with the ipl entry
3179cbc06b1SAdriana Kobylak             attr[keyName] = lid;
318ae0998f1SAdriana Kobylak             continue;
319ae0998f1SAdriana Kobylak         }
320ae0998f1SAdriana Kobylak 
321ae0998f1SAdriana Kobylak         // Process all other extensions. The extension should match the list of
322ae0998f1SAdriana Kobylak         // supported extensions for this system. Use .insert() to only add
323ae0998f1SAdriana Kobylak         // entries that do not exist, so to not overwrite the values that may
324ae0998f1SAdriana Kobylak         // had been added that had the ipl extension.
325ae0998f1SAdriana Kobylak         if (std::find(extensions.begin(), extensions.end(), path.extension()) !=
326ae0998f1SAdriana Kobylak             extensions.end())
327ae0998f1SAdriana Kobylak         {
3289cbc06b1SAdriana Kobylak             auto keyName = path.stem();
3299cbc06b1SAdriana Kobylak             auto attrIt = attr.find(keyName);
3309cbc06b1SAdriana Kobylak             if (attrIt != attr.end())
3319cbc06b1SAdriana Kobylak             {
3329cbc06b1SAdriana Kobylak                 // The existing entry is an ipl entry, therefore create this
3339cbc06b1SAdriana Kobylak                 // entry as a runtime one.
3349cbc06b1SAdriana Kobylak                 auto runtimeKeyName = keyName.string() + runtimeSuffix;
3359cbc06b1SAdriana Kobylak                 attr.insert({runtimeKeyName, lid});
3369cbc06b1SAdriana Kobylak             }
3379cbc06b1SAdriana Kobylak             else
3389cbc06b1SAdriana Kobylak             {
339ae0998f1SAdriana Kobylak                 attr.insert({path.stem(), lid});
340ae0998f1SAdriana Kobylak             }
341ae0998f1SAdriana Kobylak         }
3429cbc06b1SAdriana Kobylak     }
343ae0998f1SAdriana Kobylak     for (const auto& a : attr)
344ae0998f1SAdriana Kobylak     {
345ae0998f1SAdriana Kobylak         // Build the bios attribute string with format:
346ae0998f1SAdriana Kobylak         // "element1=lid1,element2=lid2,elementN=lidN,"
347ae0998f1SAdriana Kobylak         biosAttrStr += a.first + "=" + a.second + ",";
3485dc5d6ccSAdriana Kobylak 
3495dc5d6ccSAdriana Kobylak         // Create symlinks from the hostfw elements to their corresponding
3505dc5d6ccSAdriana Kobylak         // lid files if they don't exist
3517fb6c346SPatrick Williams         auto elementFilePath = std::filesystem::path("/media/hostfw/running") /
3527fb6c346SPatrick Williams                                a.first;
3535dc5d6ccSAdriana Kobylak         if (!std::filesystem::exists(elementFilePath))
3545dc5d6ccSAdriana Kobylak         {
3555dc5d6ccSAdriana Kobylak             std::error_code ec;
3565dc5d6ccSAdriana Kobylak             auto lidName = a.second + ".lid";
3575dc5d6ccSAdriana Kobylak             std::filesystem::create_symlink(lidName, elementFilePath, ec);
3585dc5d6ccSAdriana Kobylak             if (ec)
3595dc5d6ccSAdriana Kobylak             {
3605dc5d6ccSAdriana Kobylak                 log<level::ERR>("Error creating symlink",
3615dc5d6ccSAdriana Kobylak                                 entry("TARGET=%s", lidName.c_str()),
3625dc5d6ccSAdriana Kobylak                                 entry("LINK=%s", elementFilePath.c_str()));
3635dc5d6ccSAdriana Kobylak             }
3645dc5d6ccSAdriana Kobylak         }
365ae0998f1SAdriana Kobylak     }
366ae0998f1SAdriana Kobylak 
367a38f6e65SGeorge Liu     // Delete the last comma of the bios attribute string
368a38f6e65SGeorge Liu     if (biosAttrStr.back() == ',')
369a38f6e65SGeorge Liu     {
370a38f6e65SGeorge Liu         return biosAttrStr.substr(0, biosAttrStr.length() - 1);
371a38f6e65SGeorge Liu     }
372a38f6e65SGeorge Liu 
373ae0998f1SAdriana Kobylak     return biosAttrStr;
374ae0998f1SAdriana Kobylak }
375ae0998f1SAdriana Kobylak 
376ae0998f1SAdriana Kobylak /**
377ae0998f1SAdriana Kobylak  * @brief Set the bios attribute table with details of the host firmware data
378ae0998f1SAdriana Kobylak  * for this system.
379ae0998f1SAdriana Kobylak  *
380ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath - The path to the host firmware json file.
381*96442c88SManojkiran Eda  * @param[in] extensions - The extensions of the firmware blob files.
382ae0998f1SAdriana Kobylak  */
setBiosAttr(const std::filesystem::path & elementsJsonFilePath,const std::vector<std::string> & extensions)383ae0998f1SAdriana Kobylak void setBiosAttr(const std::filesystem::path& elementsJsonFilePath,
384ae0998f1SAdriana Kobylak                  const std::vector<std::string>& extensions)
385ae0998f1SAdriana Kobylak {
386ae0998f1SAdriana Kobylak     auto biosAttrStr = getBiosAttrStr(elementsJsonFilePath, extensions);
387ae0998f1SAdriana Kobylak 
38856f538caSAdriana Kobylak     constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager";
38956f538caSAdriana Kobylak     constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager";
39056f538caSAdriana Kobylak     constexpr auto dbusAttrName = "hb_lid_ids";
39156f538caSAdriana Kobylak     constexpr auto dbusAttrType =
39256f538caSAdriana Kobylak         "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
39356f538caSAdriana Kobylak 
39456f538caSAdriana Kobylak     using PendingAttributesType = std::vector<std::pair<
39556f538caSAdriana Kobylak         std::string, std::tuple<std::string, std::variant<std::string>>>>;
39656f538caSAdriana Kobylak     PendingAttributesType pendingAttributes;
39756f538caSAdriana Kobylak     pendingAttributes.emplace_back(std::make_pair(
39856f538caSAdriana Kobylak         dbusAttrName, std::make_tuple(dbusAttrType, biosAttrStr)));
39956f538caSAdriana Kobylak 
40056f538caSAdriana Kobylak     auto bus = sdbusplus::bus::new_default();
40156f538caSAdriana Kobylak     auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
40256f538caSAdriana Kobylak                                       MAPPER_INTERFACE, "GetObject");
40356f538caSAdriana Kobylak     method.append(biosConfigPath, std::vector<std::string>({biosConfigIntf}));
40456f538caSAdriana Kobylak     std::vector<std::pair<std::string, std::vector<std::string>>> response;
40556f538caSAdriana Kobylak     try
40656f538caSAdriana Kobylak     {
40756f538caSAdriana Kobylak         auto reply = bus.call(method);
40856f538caSAdriana Kobylak         reply.read(response);
40956f538caSAdriana Kobylak         if (response.empty())
41056f538caSAdriana Kobylak         {
4112b78eb0eSAdriana Kobylak             log<level::INFO>("Error reading mapper response",
41256f538caSAdriana Kobylak                              entry("PATH=%s", biosConfigPath),
41356f538caSAdriana Kobylak                              entry("INTERFACE=%s", biosConfigIntf));
4142b78eb0eSAdriana Kobylak             throw sdbusplus::xyz::openbmc_project::Common::Error::
4152b78eb0eSAdriana Kobylak                 InternalFailure();
41656f538caSAdriana Kobylak         }
41756f538caSAdriana Kobylak         auto method = bus.new_method_call((response.begin()->first).c_str(),
41856f538caSAdriana Kobylak                                           biosConfigPath,
41956f538caSAdriana Kobylak                                           SYSTEMD_PROPERTY_INTERFACE, "Set");
42056f538caSAdriana Kobylak         method.append(biosConfigIntf, "PendingAttributes",
42156f538caSAdriana Kobylak                       std::variant<PendingAttributesType>(pendingAttributes));
42256f538caSAdriana Kobylak         bus.call(method);
42356f538caSAdriana Kobylak     }
4240dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
42556f538caSAdriana Kobylak     {
4262b78eb0eSAdriana Kobylak         log<level::INFO>("Error setting the bios attribute",
42756f538caSAdriana Kobylak                          entry("ERROR=%s", e.what()),
42856f538caSAdriana Kobylak                          entry("ATTRIBUTE=%s", dbusAttrName));
4292b78eb0eSAdriana Kobylak         throw;
43056f538caSAdriana Kobylak     }
43156f538caSAdriana Kobylak }
43253a27395SAdriana Kobylak 
43353a27395SAdriana Kobylak /**
434099543e4SBrad Bishop  * @brief Make callbacks on
435749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible instances.
436099543e4SBrad Bishop  *
437749bdcc9SAdriana Kobylak  * Look for an instance of xyz.openbmc_project.Inventory.Decorator.Compatible in
438749bdcc9SAdriana Kobylak  * the provided argument and if found, issue the provided callback.
439099543e4SBrad Bishop  *
440099543e4SBrad Bishop  * @param[in] interfacesAndProperties the interfaces in which to look for an
441749bdcc9SAdriana Kobylak  * instance of xyz.openbmc_project.Inventory.Decorator.Compatible
442099543e4SBrad Bishop  * @param[in] callback the user callback to make if
443749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible is found in
444099543e4SBrad Bishop  * interfacesAndProperties
445099543e4SBrad Bishop  * @return true if interfacesAndProperties contained an instance of
446749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible, false otherwise
447099543e4SBrad Bishop  */
maybeCall(const std::map<std::string,std::map<std::string,std::variant<std::vector<std::string>>>> & interfacesAndProperties,const MaybeCallCallbackType & callback)448099543e4SBrad Bishop bool maybeCall(const std::map<std::string,
449099543e4SBrad Bishop                               std::map<std::string,
450099543e4SBrad Bishop                                        std::variant<std::vector<std::string>>>>&
451099543e4SBrad Bishop                    interfacesAndProperties,
452099543e4SBrad Bishop                const MaybeCallCallbackType& callback)
453099543e4SBrad Bishop {
454099543e4SBrad Bishop     using namespace std::string_literals;
455099543e4SBrad Bishop 
456099543e4SBrad Bishop     static const auto interfaceName =
457749bdcc9SAdriana Kobylak         "xyz.openbmc_project.Inventory.Decorator.Compatible"s;
458099543e4SBrad Bishop     auto interfaceIterator = interfacesAndProperties.find(interfaceName);
459099543e4SBrad Bishop     if (interfaceIterator == interfacesAndProperties.cend())
460099543e4SBrad Bishop     {
461749bdcc9SAdriana Kobylak         // Compatible interface not found, so instruct the caller to keep
462749bdcc9SAdriana Kobylak         // waiting or try again later.
463099543e4SBrad Bishop         return false;
464099543e4SBrad Bishop     }
465099543e4SBrad Bishop     auto propertyIterator = interfaceIterator->second.find("Names"s);
466099543e4SBrad Bishop     if (propertyIterator == interfaceIterator->second.cend())
467099543e4SBrad Bishop     {
468099543e4SBrad Bishop         // The interface exists but the property doesn't. This is a bug in the
469749bdcc9SAdriana Kobylak         // Compatible implementation. The caller should not try again.
470099543e4SBrad Bishop         std::cerr << "Names property not implemented on " << interfaceName
471099543e4SBrad Bishop                   << "\n";
472099543e4SBrad Bishop         return true;
473099543e4SBrad Bishop     }
474099543e4SBrad Bishop 
475099543e4SBrad Bishop     const auto& ibmCompatibleSystem =
476099543e4SBrad Bishop         std::get<std::vector<std::string>>(propertyIterator->second);
477099543e4SBrad Bishop     if (callback)
478099543e4SBrad Bishop     {
4792b78eb0eSAdriana Kobylak         try
4802b78eb0eSAdriana Kobylak         {
481099543e4SBrad Bishop             callback(ibmCompatibleSystem);
482099543e4SBrad Bishop         }
4830dea1992SPatrick Williams         catch (const sdbusplus::exception_t& e)
4842b78eb0eSAdriana Kobylak         {
4852b78eb0eSAdriana Kobylak             return false;
4862b78eb0eSAdriana Kobylak         }
4872b78eb0eSAdriana Kobylak     }
488099543e4SBrad Bishop 
489749bdcc9SAdriana Kobylak     // Compatible found and callback issued.
490099543e4SBrad Bishop     return true;
491099543e4SBrad Bishop }
492099543e4SBrad Bishop 
493099543e4SBrad Bishop /**
494099543e4SBrad Bishop  * @brief Make callbacks on
495749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible instances.
496099543e4SBrad Bishop  *
497749bdcc9SAdriana Kobylak  * Look for an instance ofxyz.openbmc_project.Inventory.Decorator.Compatible in
498749bdcc9SAdriana Kobylak  * the provided argument and if found, issue the provided callback.
499099543e4SBrad Bishop  *
500099543e4SBrad Bishop  * @param[in] message the DBus message in which to look for an instance of
501749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible
502099543e4SBrad Bishop  * @param[in] callback the user callback to make if
503749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible is found in message
504099543e4SBrad Bishop  * @return true if message contained an instance of
505749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible, false otherwise
506099543e4SBrad Bishop  */
maybeCallMessage(sdbusplus::message_t & message,const MaybeCallCallbackType & callback)5070dea1992SPatrick Williams bool maybeCallMessage(sdbusplus::message_t& message,
508099543e4SBrad Bishop                       const MaybeCallCallbackType& callback)
509099543e4SBrad Bishop {
510099543e4SBrad Bishop     std::map<std::string,
511099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
512099543e4SBrad Bishop         interfacesAndProperties;
513099543e4SBrad Bishop     sdbusplus::message::object_path _;
514099543e4SBrad Bishop     message.read(_, interfacesAndProperties);
515099543e4SBrad Bishop     return maybeCall(interfacesAndProperties, callback);
516099543e4SBrad Bishop }
517099543e4SBrad Bishop 
518099543e4SBrad Bishop /**
519099543e4SBrad Bishop  * @brief Determine system support for host firmware well-known names.
520099543e4SBrad Bishop  *
521099543e4SBrad Bishop  * Using the provided extensionMap and
522749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible, determine if well-known
523*96442c88SManojkiran Eda  * names for host firmware blob files are necessary and if so, create them.
524099543e4SBrad Bishop  *
525099543e4SBrad Bishop  * @param[in] extensionMap a map of
526749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file
527749bdcc9SAdriana Kobylak  * extensions.
528749bdcc9SAdriana Kobylak  * @param[in] hostFirmwareDirectory The directory in which findLinks should look
529749bdcc9SAdriana Kobylak  * for host firmware blob files that need well-known names.
530099543e4SBrad Bishop  * @param[in] ibmCompatibleSystem The names property of an instance of
531749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible
532099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
533099543e4SBrad Bishop  */
maybeMakeLinks(const std::map<std::string,std::vector<std::string>> & extensionMap,const std::filesystem::path & hostFirmwareDirectory,const std::vector<std::string> & ibmCompatibleSystem,const ErrorCallbackType & errorCallback)534099543e4SBrad Bishop void maybeMakeLinks(
535099543e4SBrad Bishop     const std::map<std::string, std::vector<std::string>>& extensionMap,
536099543e4SBrad Bishop     const std::filesystem::path& hostFirmwareDirectory,
537099543e4SBrad Bishop     const std::vector<std::string>& ibmCompatibleSystem,
538099543e4SBrad Bishop     const ErrorCallbackType& errorCallback)
539099543e4SBrad Bishop {
540099543e4SBrad Bishop     std::vector<std::string> extensions;
541099543e4SBrad Bishop     if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
542099543e4SBrad Bishop                                             extensions))
543099543e4SBrad Bishop     {
544099543e4SBrad Bishop         findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink);
545099543e4SBrad Bishop     }
546099543e4SBrad Bishop }
547099543e4SBrad Bishop 
548099543e4SBrad Bishop /**
54953a27395SAdriana Kobylak  * @brief Determine system support for updating the bios attribute table.
55053a27395SAdriana Kobylak  *
55153a27395SAdriana Kobylak  * Using the provided extensionMap and
552749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible, determine if the bios
55353a27395SAdriana Kobylak  * attribute table needs to be updated.
55453a27395SAdriana Kobylak  *
55553a27395SAdriana Kobylak  * @param[in] extensionMap a map of
556749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file
557749bdcc9SAdriana Kobylak  * extensions.
558ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath The file path to the json file
55953a27395SAdriana Kobylak  * @param[in] ibmCompatibleSystem The names property of an instance of
560749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible
56153a27395SAdriana Kobylak  */
maybeSetBiosAttr(const std::map<std::string,std::vector<std::string>> & extensionMap,const std::filesystem::path & elementsJsonFilePath,const std::vector<std::string> & ibmCompatibleSystem)56253a27395SAdriana Kobylak void maybeSetBiosAttr(
56353a27395SAdriana Kobylak     const std::map<std::string, std::vector<std::string>>& extensionMap,
564ae0998f1SAdriana Kobylak     const std::filesystem::path& elementsJsonFilePath,
56553a27395SAdriana Kobylak     const std::vector<std::string>& ibmCompatibleSystem)
56653a27395SAdriana Kobylak {
56753a27395SAdriana Kobylak     std::vector<std::string> extensions;
56853a27395SAdriana Kobylak     if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
56953a27395SAdriana Kobylak                                             extensions))
57053a27395SAdriana Kobylak     {
5712b78eb0eSAdriana Kobylak         try
5722b78eb0eSAdriana Kobylak         {
573ae0998f1SAdriana Kobylak             setBiosAttr(elementsJsonFilePath, extensions);
57453a27395SAdriana Kobylak         }
5750dea1992SPatrick Williams         catch (const sdbusplus::exception_t& e)
5762b78eb0eSAdriana Kobylak         {
5772b78eb0eSAdriana Kobylak             throw;
5782b78eb0eSAdriana Kobylak         }
5792b78eb0eSAdriana Kobylak     }
58053a27395SAdriana Kobylak }
58153a27395SAdriana Kobylak 
58253a27395SAdriana Kobylak /**
583099543e4SBrad Bishop  * @brief process host firmware
584099543e4SBrad Bishop  *
585099543e4SBrad Bishop  * Allocate a callback context and register for DBus.ObjectManager Interfaces
586099543e4SBrad Bishop  * added signals from entity manager.
587099543e4SBrad Bishop  *
588099543e4SBrad Bishop  * Check the current entity manager object tree for a
589749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible instance (entity manager
590749bdcc9SAdriana Kobylak  * will be dbus activated if it is not running). If one is found, determine if
591749bdcc9SAdriana Kobylak  * symlinks need to be created and create them. Instruct the program event loop
592749bdcc9SAdriana Kobylak  * to exit.
593099543e4SBrad Bishop  *
594749bdcc9SAdriana Kobylak  * If no instance of xyz.openbmc_project.Inventory.Decorator.Compatible is found
595749bdcc9SAdriana Kobylak  * return the callback context to main, where the program will sleep until the
596749bdcc9SAdriana Kobylak  * callback is invoked one or more times and instructs the program event loop to
597749bdcc9SAdriana Kobylak  * exit when xyz.openbmc_project.Inventory.Decorator.Compatible is added.
598099543e4SBrad Bishop  *
599099543e4SBrad Bishop  * @param[in] bus a DBus client connection
600099543e4SBrad Bishop  * @param[in] extensionMap a map of
601749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible to host firmware blob file
602749bdcc9SAdriana Kobylak  * extensions.
603099543e4SBrad Bishop  * @param[in] hostFirmwareDirectory The directory in which processHostFirmware
604099543e4SBrad Bishop  * should look for blob files.
605099543e4SBrad Bishop  * @param[in] errorCallback A callback made in the event of filesystem errors.
606099543e4SBrad Bishop  * @param[in] loop a program event loop
607099543e4SBrad Bishop  * @return nullptr if an instance of
608749bdcc9SAdriana Kobylak  * xyz.openbmc_project.Inventory.Decorator.Compatible is found, otherwise a
609099543e4SBrad Bishop  * pointer to an sdbusplus match object.
610099543e4SBrad Bishop  */
processHostFirmware(sdbusplus::bus_t & bus,std::map<std::string,std::vector<std::string>> extensionMap,std::filesystem::path hostFirmwareDirectory,ErrorCallbackType errorCallback,sdeventplus::Event & loop)611099543e4SBrad Bishop std::shared_ptr<void> processHostFirmware(
6120dea1992SPatrick Williams     sdbusplus::bus_t& bus,
613099543e4SBrad Bishop     std::map<std::string, std::vector<std::string>> extensionMap,
614099543e4SBrad Bishop     std::filesystem::path hostFirmwareDirectory,
615099543e4SBrad Bishop     ErrorCallbackType errorCallback, sdeventplus::Event& loop)
616099543e4SBrad Bishop {
617099543e4SBrad Bishop     // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't
618*96442c88SManojkiran Eda     // be transferred to the match callback because they are needed in the non
619099543e4SBrad Bishop     // async part of this function below, so they need to be moved to the heap.
620099543e4SBrad Bishop     auto pExtensionMap =
621099543e4SBrad Bishop         std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
622099543e4SBrad Bishop     auto pHostFirmwareDirectory =
623099543e4SBrad Bishop         std::make_shared<decltype(hostFirmwareDirectory)>(
624099543e4SBrad Bishop             std::move(hostFirmwareDirectory));
625099543e4SBrad Bishop     auto pErrorCallback =
626099543e4SBrad Bishop         std::make_shared<decltype(errorCallback)>(std::move(errorCallback));
627099543e4SBrad Bishop 
628749bdcc9SAdriana Kobylak     // register for a callback in case the Compatible interface has not yet been
629749bdcc9SAdriana Kobylak     // published by entity manager.
6300dea1992SPatrick Williams     auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match_t>(
631099543e4SBrad Bishop         bus,
632099543e4SBrad Bishop         sdbusplus::bus::match::rules::interfacesAdded() +
633099543e4SBrad Bishop             sdbusplus::bus::match::rules::sender(
634099543e4SBrad Bishop                 "xyz.openbmc_project.EntityManager"),
635099543e4SBrad Bishop         [pExtensionMap, pHostFirmwareDirectory, pErrorCallback,
636099543e4SBrad Bishop          &loop](auto& message) {
637099543e4SBrad Bishop         // bind the extension map, host firmware directory, and error
638099543e4SBrad Bishop         // callback to the maybeMakeLinks function.
639099543e4SBrad Bishop         auto maybeMakeLinksWithArgsBound =
640099543e4SBrad Bishop             std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
6417fb6c346SPatrick Williams                       std::cref(*pHostFirmwareDirectory), std::placeholders::_1,
6427fb6c346SPatrick Williams                       std::cref(*pErrorCallback));
643099543e4SBrad Bishop 
644099543e4SBrad Bishop         // if the InterfacesAdded message contains an an instance of
645749bdcc9SAdriana Kobylak         // xyz.openbmc_project.Inventory.Decorator.Compatible, check to see if
646749bdcc9SAdriana Kobylak         // links are necessary on this system and if so, create them.
647099543e4SBrad Bishop         if (maybeCallMessage(message, maybeMakeLinksWithArgsBound))
648099543e4SBrad Bishop         {
649749bdcc9SAdriana Kobylak             // The Compatible interface was found and the links were created if
650749bdcc9SAdriana Kobylak             // applicable. Instruct the event loop / subcommand to exit.
651099543e4SBrad Bishop             loop.exit(0);
652099543e4SBrad Bishop         }
653099543e4SBrad Bishop     });
654099543e4SBrad Bishop 
655099543e4SBrad Bishop     // now that we'll get a callback in the event of an InterfacesAdded signal
656099543e4SBrad Bishop     // (potentially containing
657749bdcc9SAdriana Kobylak     // xyz.openbmc_project.Inventory.Decorator.Compatible), activate entity
658099543e4SBrad Bishop     // manager if it isn't running and enumerate its objects
659099543e4SBrad Bishop     auto getManagedObjects = bus.new_method_call(
66075352b42SNan Zhou         "xyz.openbmc_project.EntityManager", "/xyz/openbmc_project/inventory",
661099543e4SBrad Bishop         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
662099543e4SBrad Bishop     std::map<std::string,
663099543e4SBrad Bishop              std::map<std::string, std::variant<std::vector<std::string>>>>
664099543e4SBrad Bishop         interfacesAndProperties;
665099543e4SBrad Bishop     std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
666099543e4SBrad Bishop         objects;
667c79fa915SAdriana Kobylak     try
668c79fa915SAdriana Kobylak     {
669c79fa915SAdriana Kobylak         auto reply = bus.call(getManagedObjects);
670099543e4SBrad Bishop         reply.read(objects);
671c79fa915SAdriana Kobylak     }
6720dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
673c79fa915SAdriana Kobylak     {
674c79fa915SAdriana Kobylak         // Error querying the EntityManager interface. Return the match to have
675c79fa915SAdriana Kobylak         // the callback run if/when the interface appears in D-Bus.
676c79fa915SAdriana Kobylak         return interfacesAddedMatch;
677c79fa915SAdriana Kobylak     }
678099543e4SBrad Bishop 
679099543e4SBrad Bishop     // bind the extension map, host firmware directory, and error callback to
680099543e4SBrad Bishop     // the maybeMakeLinks function.
681099543e4SBrad Bishop     auto maybeMakeLinksWithArgsBound =
682099543e4SBrad Bishop         std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
683099543e4SBrad Bishop                   std::cref(*pHostFirmwareDirectory), std::placeholders::_1,
684099543e4SBrad Bishop                   std::cref(*pErrorCallback));
685099543e4SBrad Bishop 
686099543e4SBrad Bishop     for (const auto& pair : objects)
687099543e4SBrad Bishop     {
688099543e4SBrad Bishop         std::tie(std::ignore, interfacesAndProperties) = pair;
689099543e4SBrad Bishop         // if interfacesAndProperties contains an an instance of
690749bdcc9SAdriana Kobylak         // xyz.openbmc_project.Inventory.Decorator.Compatible, check to see if
691749bdcc9SAdriana Kobylak         // links are necessary on this system and if so, create them
692099543e4SBrad Bishop         if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound))
693099543e4SBrad Bishop         {
694749bdcc9SAdriana Kobylak             // The Compatible interface is already on the bus and the links were
695749bdcc9SAdriana Kobylak             // created if applicable. Instruct the event loop to exit.
696099543e4SBrad Bishop             loop.exit(0);
697099543e4SBrad Bishop             // The match object isn't needed anymore, so destroy it on return.
698099543e4SBrad Bishop             return nullptr;
699099543e4SBrad Bishop         }
700099543e4SBrad Bishop     }
701099543e4SBrad Bishop 
702749bdcc9SAdriana Kobylak     // The Compatible interface has not yet been published. Move ownership of
703749bdcc9SAdriana Kobylak     // the match callback to the caller.
704099543e4SBrad Bishop     return interfacesAddedMatch;
705099543e4SBrad Bishop }
70653a27395SAdriana Kobylak 
70753a27395SAdriana Kobylak /**
70853a27395SAdriana Kobylak  * @brief Update the Bios Attribute Table
70953a27395SAdriana Kobylak  *
710749bdcc9SAdriana Kobylak  * If an instance of xyz.openbmc_project.Inventory.Decorator.Compatible is
71153a27395SAdriana Kobylak  * found, update the Bios Attribute Table with the appropriate host firmware
71253a27395SAdriana Kobylak  * data.
71353a27395SAdriana Kobylak  *
71453a27395SAdriana Kobylak  * @param[in] bus - D-Bus client connection.
715749bdcc9SAdriana Kobylak  * @param[in] extensionMap - Map of Compatible names and host firmware file
716749bdcc9SAdriana Kobylak                              extensions.
717ae0998f1SAdriana Kobylak  * @param[in] elementsJsonFilePath - The Path to the json file
71853a27395SAdriana Kobylak  * @param[in] loop - Program event loop.
71953a27395SAdriana Kobylak  * @return nullptr
72053a27395SAdriana Kobylak  */
updateBiosAttrTable(sdbusplus::bus_t & bus,std::map<std::string,std::vector<std::string>> extensionMap,std::filesystem::path elementsJsonFilePath,sdeventplus::Event & loop)721ebf67bf7SAdriana Kobylak std::vector<std::shared_ptr<void>> updateBiosAttrTable(
7220dea1992SPatrick Williams     sdbusplus::bus_t& bus,
72353a27395SAdriana Kobylak     std::map<std::string, std::vector<std::string>> extensionMap,
724ae0998f1SAdriana Kobylak     std::filesystem::path elementsJsonFilePath, sdeventplus::Event& loop)
72553a27395SAdriana Kobylak {
726d0379ea5SAdriana Kobylak     constexpr auto pldmPath = "/xyz/openbmc_project/pldm";
727ebf67bf7SAdriana Kobylak     constexpr auto entityManagerServiceName =
728ebf67bf7SAdriana Kobylak         "xyz.openbmc_project.EntityManager";
729d0379ea5SAdriana Kobylak 
73053a27395SAdriana Kobylak     auto pExtensionMap =
73153a27395SAdriana Kobylak         std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
732ae0998f1SAdriana Kobylak     auto pElementsJsonFilePath =
733ae0998f1SAdriana Kobylak         std::make_shared<decltype(elementsJsonFilePath)>(
734ae0998f1SAdriana Kobylak             std::move(elementsJsonFilePath));
73553a27395SAdriana Kobylak 
736d0379ea5SAdriana Kobylak     auto maybeSetAttrWithArgsBound =
737d0379ea5SAdriana Kobylak         std::bind(maybeSetBiosAttr, std::cref(*pExtensionMap),
738d0379ea5SAdriana Kobylak                   std::cref(*pElementsJsonFilePath), std::placeholders::_1);
739d0379ea5SAdriana Kobylak 
740ebf67bf7SAdriana Kobylak     std::vector<std::shared_ptr<void>> matches;
7412b78eb0eSAdriana Kobylak 
7422b78eb0eSAdriana Kobylak     // Entity Manager is needed to get the list of supported extensions. Add a
7432b78eb0eSAdriana Kobylak     // match to monitor interfaces added in case it's not running yet.
7440dea1992SPatrick Williams     matches.emplace_back(std::make_shared<sdbusplus::bus::match_t>(
745d0379ea5SAdriana Kobylak         bus,
746d0379ea5SAdriana Kobylak         sdbusplus::bus::match::rules::interfacesAdded() +
747d0379ea5SAdriana Kobylak             sdbusplus::bus::match::rules::sender(
748d0379ea5SAdriana Kobylak                 "xyz.openbmc_project.EntityManager"),
749d0379ea5SAdriana Kobylak         [pldmPath, pExtensionMap, pElementsJsonFilePath,
750d0379ea5SAdriana Kobylak          maybeSetAttrWithArgsBound, &loop](auto& message) {
751d0379ea5SAdriana Kobylak         if (maybeCallMessage(message, maybeSetAttrWithArgsBound))
752d0379ea5SAdriana Kobylak         {
753fd4a6088SAdriana Kobylak             loop.exit(0);
754d0379ea5SAdriana Kobylak         }
755ebf67bf7SAdriana Kobylak     }));
7562b78eb0eSAdriana Kobylak 
7572b78eb0eSAdriana Kobylak     // The BIOS attribute table can only be updated if PLDM is running because
7582b78eb0eSAdriana Kobylak     // PLDM is the one that exposes this property. Add a match to monitor when
7592b78eb0eSAdriana Kobylak     // the PLDM service starts.
7600dea1992SPatrick Williams     matches.emplace_back(std::make_shared<sdbusplus::bus::match_t>(
761ebf67bf7SAdriana Kobylak         bus,
762ebf67bf7SAdriana Kobylak         sdbusplus::bus::match::rules::nameOwnerChanged() +
763ebf67bf7SAdriana Kobylak             sdbusplus::bus::match::rules::arg0namespace(
764ebf67bf7SAdriana Kobylak                 "xyz.openbmc_project.PLDM"),
765ebf67bf7SAdriana Kobylak         [pExtensionMap, pElementsJsonFilePath, maybeSetAttrWithArgsBound,
766ebf67bf7SAdriana Kobylak          &loop](auto& message) {
767ebf67bf7SAdriana Kobylak         std::string name;
768ebf67bf7SAdriana Kobylak         std::string oldOwner;
769ebf67bf7SAdriana Kobylak         std::string newOwner;
770ebf67bf7SAdriana Kobylak         message.read(name, oldOwner, newOwner);
771ebf67bf7SAdriana Kobylak 
772ebf67bf7SAdriana Kobylak         if (newOwner.empty())
773ebf67bf7SAdriana Kobylak         {
774ebf67bf7SAdriana Kobylak             return;
775ebf67bf7SAdriana Kobylak         }
776ebf67bf7SAdriana Kobylak 
777ebf67bf7SAdriana Kobylak         auto bus = sdbusplus::bus::new_default();
778ebf67bf7SAdriana Kobylak         InterfacesPropertiesMap interfacesAndProperties;
77975352b42SNan Zhou         auto objects = getManagedObjects(bus, entityManagerServiceName,
78075352b42SNan Zhou                                          "/xyz/openbmc_project/inventory");
781ebf67bf7SAdriana Kobylak         for (const auto& pair : objects)
782ebf67bf7SAdriana Kobylak         {
783ebf67bf7SAdriana Kobylak             std::tie(std::ignore, interfacesAndProperties) = pair;
7847fb6c346SPatrick Williams             if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound))
785ebf67bf7SAdriana Kobylak             {
786ebf67bf7SAdriana Kobylak                 loop.exit(0);
787ebf67bf7SAdriana Kobylak             }
788ebf67bf7SAdriana Kobylak         }
789ebf67bf7SAdriana Kobylak     }));
790d0379ea5SAdriana Kobylak 
791ebf67bf7SAdriana Kobylak     InterfacesPropertiesMap interfacesAndProperties;
79275352b42SNan Zhou     auto objects = getManagedObjects(bus, entityManagerServiceName,
79375352b42SNan Zhou                                      "/xyz/openbmc_project/inventory");
79453a27395SAdriana Kobylak     for (const auto& pair : objects)
79553a27395SAdriana Kobylak     {
79653a27395SAdriana Kobylak         std::tie(std::ignore, interfacesAndProperties) = pair;
79753a27395SAdriana Kobylak         if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound))
79853a27395SAdriana Kobylak         {
799d0379ea5SAdriana Kobylak             loop.exit(0);
800ebf67bf7SAdriana Kobylak             return {};
80153a27395SAdriana Kobylak         }
80253a27395SAdriana Kobylak     }
80353a27395SAdriana Kobylak 
804ebf67bf7SAdriana Kobylak     return matches;
80553a27395SAdriana Kobylak }
80653a27395SAdriana Kobylak 
807099543e4SBrad Bishop } // namespace process_hostfirmware
808099543e4SBrad Bishop } // namespace functions
809