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