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