blob: 40bfc83c002d63437c07894406fd202c6048eea2 [file] [log] [blame]
Brad Bishop099543e2020-11-09 15:37:58 -05001// SPDX-License-Identifier: Apache-2.0
2
3/**@file functions.cpp*/
4
Adriana Kobylak56f538c2021-06-16 20:37:21 +00005#include "config.h"
6
Brad Bishop099543e2020-11-09 15:37:58 -05007#include "functions.hpp"
8
Adriana Kobylakae0998f2021-06-16 19:52:24 +00009#include <nlohmann/json.hpp>
Adriana Kobylak56f538c2021-06-16 20:37:21 +000010#include <phosphor-logging/log.hpp>
Brad Bishop099543e2020-11-09 15:37:58 -050011#include <sdbusplus/bus.hpp>
12#include <sdbusplus/bus/match.hpp>
Adriana Kobylakc79fa912021-06-22 15:37:50 +000013#include <sdbusplus/exception.hpp>
Brad Bishop099543e2020-11-09 15:37:58 -050014#include <sdbusplus/message.hpp>
15#include <sdeventplus/event.hpp>
16
17#include <filesystem>
Adriana Kobylakae0998f2021-06-16 19:52:24 +000018#include <fstream>
Brad Bishop099543e2020-11-09 15:37:58 -050019#include <functional>
20#include <iostream>
21#include <map>
22#include <memory>
23#include <string>
24#include <variant>
25#include <vector>
26
27namespace functions
28{
29namespace process_hostfirmware
30{
31
Adriana Kobylak56f538c2021-06-16 20:37:21 +000032using namespace phosphor::logging;
33
Brad Bishop099543e2020-11-09 15:37:58 -050034/**
35 * @brief Issue callbacks safely
36 *
37 * std::function can be empty, so this wrapper method checks for that prior to
38 * calling it to avoid std::bad_function_call
39 *
40 * @tparam Sig the types of the std::function arguments
41 * @tparam Args the deduced argument types
42 * @param[in] callback the callback being wrapped
43 * @param[in] args the callback arguments
44 */
45template <typename... Sig, typename... Args>
46void makeCallback(const std::function<void(Sig...)>& callback, Args&&... args)
47{
48 if (callback)
49 {
50 callback(std::forward<Args>(args)...);
51 }
52}
53
54/**
55 * @brief Get file extensions for IBMCompatibleSystem
56 *
57 * IBM host firmware can be deployed as blobs (files) in a filesystem. Host
58 * firmware blobs for different values of
59 * xyz.openbmc_project.Configuration.IBMCompatibleSystem are packaged with
60 * different filename extensions. getExtensionsForIbmCompatibleSystem
61 * maintains the mapping from a given value of
62 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to an array of
63 * filename extensions.
64 *
65 * If a mapping is found getExtensionsForIbmCompatibleSystem returns true and
66 * the extensions parameter is reset with the map entry. If no mapping is
67 * found getExtensionsForIbmCompatibleSystem returns false and extensions is
68 * unmodified.
69 *
70 * @param[in] extensionMap a map of
71 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
72 * file extensions.
73 * @param[in] ibmCompatibleSystem The names property of an instance of
74 * xyz.openbmc_project.Configuration.IBMCompatibleSystem
75 * @param[out] extentions the host firmware blob file extensions
76 * @return true if an entry was found, otherwise false
77 */
78bool getExtensionsForIbmCompatibleSystem(
79 const std::map<std::string, std::vector<std::string>>& extensionMap,
80 const std::vector<std::string>& ibmCompatibleSystem,
81 std::vector<std::string>& extensions)
82{
83 for (const auto& system : ibmCompatibleSystem)
84 {
85 auto extensionMapIterator = extensionMap.find(system);
86 if (extensionMapIterator != extensionMap.end())
87 {
88 extensions = extensionMapIterator->second;
89 return true;
90 }
91 }
92
93 return false;
94}
95
96/**
97 * @brief Write host firmware well-known name
98 *
99 * A wrapper around std::filesystem::create_symlink that avoids EEXIST by
100 * deleting any pre-existing file.
101 *
102 * @param[in] linkTarget The link target argument to
103 * std::filesystem::create_symlink
104 * @param[in] linkPath The link path argument to std::filesystem::create_symlink
105 * @param[in] errorCallback A callback made in the event of filesystem errors.
106 */
107void writeLink(const std::filesystem::path& linkTarget,
108 const std::filesystem::path& linkPath,
109 const ErrorCallbackType& errorCallback)
110{
111 std::error_code ec;
112
113 // remove files with the same name as the symlink to be created,
114 // otherwise symlink will fail with EEXIST.
115 if (!std::filesystem::remove(linkPath, ec))
116 {
117 if (ec)
118 {
119 makeCallback(errorCallback, linkPath, ec);
120 return;
121 }
122 }
123
124 std::filesystem::create_symlink(linkTarget, linkPath, ec);
125 if (ec)
126 {
127 makeCallback(errorCallback, linkPath, ec);
128 return;
129 }
130}
131
132/**
133 * @brief Find host firmware blob files that need well-known names
134 *
135 * The IBM host firmware runtime looks for data and/or additional code while
136 * bootstraping in files with well-known names. findLinks uses the provided
137 * extensions argument to find host firmware blob files that require a
138 * well-known name. When a blob is found, issue the provided callback
139 * (typically a function that will write a symlink).
140 *
141 * @param[in] hostFirmwareDirectory The directory in which findLinks should
142 * look for host firmware blob files that need well-known names.
143 * @param[in] extentions The extensions of the firmware blob files denote a
144 * host firmware blob file requires a well-known name.
145 * @param[in] errorCallback A callback made in the event of filesystem errors.
146 * @param[in] linkCallback A callback made when host firmware blob files
147 * needing a well known name are found.
148 */
149void findLinks(const std::filesystem::path& hostFirmwareDirectory,
150 const std::vector<std::string>& extensions,
151 const ErrorCallbackType& errorCallback,
152 const LinkCallbackType& linkCallback)
153{
154 std::error_code ec;
155 std::filesystem::directory_iterator directoryIterator(hostFirmwareDirectory,
156 ec);
157 if (ec)
158 {
159 makeCallback(errorCallback, hostFirmwareDirectory, ec);
160 return;
161 }
162
Adriana Kobylakfdc91fa2021-05-20 16:00:45 +0000163 // Create a symlink from HBB to the corresponding LID file if it exists
164 static const auto hbbLid = "81e0065a.lid";
165 auto hbbLidPath = hostFirmwareDirectory / hbbLid;
166 if (std::filesystem::exists(hbbLidPath))
167 {
168 static const auto hbbName = "HBB";
169 auto hbbLinkPath = hostFirmwareDirectory / hbbName;
170 makeCallback(linkCallback, hbbLid, hbbLinkPath, errorCallback);
171 }
172
Brad Bishop099543e2020-11-09 15:37:58 -0500173 for (; directoryIterator != std::filesystem::end(directoryIterator);
174 directoryIterator.increment(ec))
175 {
176 const auto& file = directoryIterator->path();
177 if (ec)
178 {
179 makeCallback(errorCallback, file, ec);
180 // quit here if the increment call failed otherwise the loop may
181 // never finish
182 break;
183 }
184
185 if (std::find(extensions.begin(), extensions.end(), file.extension()) ==
186 extensions.end())
187 {
188 // this file doesn't have an extension or doesn't match any of the
189 // provided extensions.
190 continue;
191 }
192
193 auto linkPath(file.parent_path().append(
194 static_cast<const std::string&>(file.stem())));
195
196 makeCallback(linkCallback, file.filename(), linkPath, errorCallback);
197 }
198}
199
200/**
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000201 * @brief Parse the elements json file and construct a string with the data to
202 * be used to update the bios attribute table.
203 *
204 * @param[in] elementsJsonFilePath - The path to the host firmware json file.
205 * @param[in] extensions - The extensions of the firmware blob files.
Adriana Kobylak53a27392021-06-14 17:42:40 +0000206 */
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000207std::string getBiosAttrStr(const std::filesystem::path& elementsJsonFilePath,
208 const std::vector<std::string>& extensions)
Adriana Kobylak56f538c2021-06-16 20:37:21 +0000209{
210 std::string biosAttrStr{};
211
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000212 std::ifstream jsonFile(elementsJsonFilePath.c_str());
213 if (!jsonFile)
214 {
215 return {};
216 }
217
218 std::map<std::string, std::string> attr;
219 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
220 if (data.is_discarded())
221 {
222 log<level::ERR>("Error parsing JSON file",
223 entry("FILE=%s", elementsJsonFilePath.c_str()));
224 return {};
225 }
226
227 // .get requires a non-const iterator
228 for (auto& iter : data["lids"])
229 {
230 std::string name{};
231 std::string lid{};
232
233 try
234 {
235 name = iter["element_name"].get<std::string>();
236 lid = iter["short_lid_name"].get<std::string>();
237 }
238 catch (std::exception& e)
239 {
240 // Possibly the element or lid name field was not found
241 log<level::ERR>("Error reading JSON field",
242 entry("FILE=%s", elementsJsonFilePath.c_str()),
243 entry("ERROR=%s", e.what()));
244 continue;
245 }
246
247 // The elements with the ipl extension have higher priority. Therefore
248 // Use operator[] to overwrite value if an entry for it already exists.
249 // Ex: if the JSON contains an entry A.P10 followed by A.P10.iplTime,
250 // the lid value for the latter one will be overwrite the value of the
251 // first one.
252 constexpr auto iplExtension = ".iplTime";
253 std::filesystem::path path(name);
254 if (path.extension() == iplExtension)
255 {
256 // Some elements have an additional extension, ex: .P10.iplTime
257 // Strip off the ipl extension with stem(), then check if there is
258 // an additional extension with extension().
259 if (!path.stem().extension().empty())
260 {
261 // Check if the extension matches the extensions for this system
262 if (std::find(extensions.begin(), extensions.end(),
263 path.stem().extension()) == extensions.end())
264 {
265 continue;
266 }
267 }
268 // Get the element name without extensions by calling stem() twice
269 // since stem() returns the base name if no periods are found.
270 // Therefore both "element.P10" and "element.P10.iplTime" would
271 // become "element".
272 attr[path.stem().stem()] = lid;
273 continue;
274 }
275
276 // Process all other extensions. The extension should match the list of
277 // supported extensions for this system. Use .insert() to only add
278 // entries that do not exist, so to not overwrite the values that may
279 // had been added that had the ipl extension.
280 if (std::find(extensions.begin(), extensions.end(), path.extension()) !=
281 extensions.end())
282 {
283 attr.insert({path.stem(), lid});
284 }
285 }
286 for (const auto& a : attr)
287 {
288 // Build the bios attribute string with format:
289 // "element1=lid1,element2=lid2,elementN=lidN,"
290 biosAttrStr += a.first + "=" + a.second + ",";
291 }
292
293 return biosAttrStr;
294}
295
296/**
297 * @brief Set the bios attribute table with details of the host firmware data
298 * for this system.
299 *
300 * @param[in] elementsJsonFilePath - The path to the host firmware json file.
301 * @param[in] extentions - The extensions of the firmware blob files.
302 */
303void setBiosAttr(const std::filesystem::path& elementsJsonFilePath,
304 const std::vector<std::string>& extensions)
305{
306 auto biosAttrStr = getBiosAttrStr(elementsJsonFilePath, extensions);
307
Adriana Kobylak56f538c2021-06-16 20:37:21 +0000308 constexpr auto biosConfigPath = "/xyz/openbmc_project/bios_config/manager";
309 constexpr auto biosConfigIntf = "xyz.openbmc_project.BIOSConfig.Manager";
310 constexpr auto dbusAttrName = "hb_lid_ids";
311 constexpr auto dbusAttrType =
312 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
313
314 using PendingAttributesType = std::vector<std::pair<
315 std::string, std::tuple<std::string, std::variant<std::string>>>>;
316 PendingAttributesType pendingAttributes;
317 pendingAttributes.emplace_back(std::make_pair(
318 dbusAttrName, std::make_tuple(dbusAttrType, biosAttrStr)));
319
320 auto bus = sdbusplus::bus::new_default();
321 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
322 MAPPER_INTERFACE, "GetObject");
323 method.append(biosConfigPath, std::vector<std::string>({biosConfigIntf}));
324 std::vector<std::pair<std::string, std::vector<std::string>>> response;
325 try
326 {
327 auto reply = bus.call(method);
328 reply.read(response);
329 if (response.empty())
330 {
331 log<level::ERR>("Error reading mapper response",
332 entry("PATH=%s", biosConfigPath),
333 entry("INTERFACE=%s", biosConfigIntf));
334 return;
335 }
336 auto method = bus.new_method_call((response.begin()->first).c_str(),
337 biosConfigPath,
338 SYSTEMD_PROPERTY_INTERFACE, "Set");
339 method.append(biosConfigIntf, "PendingAttributes",
340 std::variant<PendingAttributesType>(pendingAttributes));
341 bus.call(method);
342 }
343 catch (const sdbusplus::exception::SdBusError& e)
344 {
345 log<level::ERR>("Error setting the bios attribute",
346 entry("ERROR=%s", e.what()),
347 entry("ATTRIBUTE=%s", dbusAttrName));
348 return;
349 }
350}
Adriana Kobylak53a27392021-06-14 17:42:40 +0000351
352/**
Brad Bishop099543e2020-11-09 15:37:58 -0500353 * @brief Make callbacks on
354 * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
355 *
356 * Look for an instance of
357 * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
358 * argument and if found, issue the provided callback.
359 *
360 * @param[in] interfacesAndProperties the interfaces in which to look for an
361 * instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem
362 * @param[in] callback the user callback to make if
363 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
364 * interfacesAndProperties
365 * @return true if interfacesAndProperties contained an instance of
366 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
367 */
368bool maybeCall(const std::map<std::string,
369 std::map<std::string,
370 std::variant<std::vector<std::string>>>>&
371 interfacesAndProperties,
372 const MaybeCallCallbackType& callback)
373{
374 using namespace std::string_literals;
375
376 static const auto interfaceName =
377 "xyz.openbmc_project.Configuration.IBMCompatibleSystem"s;
378 auto interfaceIterator = interfacesAndProperties.find(interfaceName);
379 if (interfaceIterator == interfacesAndProperties.cend())
380 {
381 // IBMCompatibleSystem interface not found, so instruct the caller to
382 // keep waiting or try again later.
383 return false;
384 }
385 auto propertyIterator = interfaceIterator->second.find("Names"s);
386 if (propertyIterator == interfaceIterator->second.cend())
387 {
388 // The interface exists but the property doesn't. This is a bug in the
389 // IBMCompatibleSystem implementation. The caller should not try
390 // again.
391 std::cerr << "Names property not implemented on " << interfaceName
392 << "\n";
393 return true;
394 }
395
396 const auto& ibmCompatibleSystem =
397 std::get<std::vector<std::string>>(propertyIterator->second);
398 if (callback)
399 {
400 callback(ibmCompatibleSystem);
401 }
402
403 // IBMCompatibleSystem found and callback issued.
404 return true;
405}
406
407/**
408 * @brief Make callbacks on
409 * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
410 *
411 * Look for an instance of
412 * xyz.openbmc_project.Configuration.IBMCompatibleSystem in the provided
413 * argument and if found, issue the provided callback.
414 *
415 * @param[in] message the DBus message in which to look for an instance of
416 * xyz.openbmc_project.Configuration.IBMCompatibleSystem
417 * @param[in] callback the user callback to make if
418 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found in
419 * message
420 * @return true if message contained an instance of
421 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, false otherwise
422 */
423bool maybeCallMessage(sdbusplus::message::message& message,
424 const MaybeCallCallbackType& callback)
425{
426 std::map<std::string,
427 std::map<std::string, std::variant<std::vector<std::string>>>>
428 interfacesAndProperties;
429 sdbusplus::message::object_path _;
430 message.read(_, interfacesAndProperties);
431 return maybeCall(interfacesAndProperties, callback);
432}
433
434/**
435 * @brief Determine system support for host firmware well-known names.
436 *
437 * Using the provided extensionMap and
438 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if
439 * well-known names for host firmare blob files are necessary and if so, create
440 * them.
441 *
442 * @param[in] extensionMap a map of
443 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
444 * file extensions.
445 * @param[in] hostFirmwareDirectory The directory in which findLinks should
446 * look for host firmware blob files that need well-known names.
447 * @param[in] ibmCompatibleSystem The names property of an instance of
448 * xyz.openbmc_project.Configuration.IBMCompatibleSystem
449 * @param[in] errorCallback A callback made in the event of filesystem errors.
450 */
451void maybeMakeLinks(
452 const std::map<std::string, std::vector<std::string>>& extensionMap,
453 const std::filesystem::path& hostFirmwareDirectory,
454 const std::vector<std::string>& ibmCompatibleSystem,
455 const ErrorCallbackType& errorCallback)
456{
457 std::vector<std::string> extensions;
458 if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
459 extensions))
460 {
461 findLinks(hostFirmwareDirectory, extensions, errorCallback, writeLink);
462 }
463}
464
465/**
Adriana Kobylak53a27392021-06-14 17:42:40 +0000466 * @brief Determine system support for updating the bios attribute table.
467 *
468 * Using the provided extensionMap and
469 * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if the bios
470 * attribute table needs to be updated.
471 *
472 * @param[in] extensionMap a map of
473 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
474 * file extensions.
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000475 * @param[in] elementsJsonFilePath The file path to the json file
Adriana Kobylak53a27392021-06-14 17:42:40 +0000476 * @param[in] ibmCompatibleSystem The names property of an instance of
477 * xyz.openbmc_project.Configuration.IBMCompatibleSystem
478 */
479void maybeSetBiosAttr(
480 const std::map<std::string, std::vector<std::string>>& extensionMap,
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000481 const std::filesystem::path& elementsJsonFilePath,
Adriana Kobylak53a27392021-06-14 17:42:40 +0000482 const std::vector<std::string>& ibmCompatibleSystem)
483{
484 std::vector<std::string> extensions;
485 if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
486 extensions))
487 {
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000488 setBiosAttr(elementsJsonFilePath, extensions);
Adriana Kobylak53a27392021-06-14 17:42:40 +0000489 }
490}
491
492/**
Brad Bishop099543e2020-11-09 15:37:58 -0500493 * @brief process host firmware
494 *
495 * Allocate a callback context and register for DBus.ObjectManager Interfaces
496 * added signals from entity manager.
497 *
498 * Check the current entity manager object tree for a
499 * xyz.openbmc_project.Configuration.IBMCompatibleSystem instance (entity
500 * manager will be dbus activated if it is not running). If one is found,
501 * determine if symlinks need to be created and create them. Instruct the
502 * program event loop to exit.
503 *
504 * If no instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
505 * found return the callback context to main, where the program will sleep
506 * until the callback is invoked one or more times and instructs the program
507 * event loop to exit when
508 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is added.
509 *
510 * @param[in] bus a DBus client connection
511 * @param[in] extensionMap a map of
512 * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
513 * file extensions.
514 * @param[in] hostFirmwareDirectory The directory in which processHostFirmware
515 * should look for blob files.
516 * @param[in] errorCallback A callback made in the event of filesystem errors.
517 * @param[in] loop a program event loop
518 * @return nullptr if an instance of
519 * xyz.openbmc_project.Configuration.IBMCompatibleSystem is found, otherwise a
520 * pointer to an sdbusplus match object.
521 */
522std::shared_ptr<void> processHostFirmware(
523 sdbusplus::bus::bus& bus,
524 std::map<std::string, std::vector<std::string>> extensionMap,
525 std::filesystem::path hostFirmwareDirectory,
526 ErrorCallbackType errorCallback, sdeventplus::Event& loop)
527{
528 // ownership of extensionMap, hostFirmwareDirectory and errorCallback can't
529 // be transfered to the match callback because they are needed in the non
530 // async part of this function below, so they need to be moved to the heap.
531 auto pExtensionMap =
532 std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
533 auto pHostFirmwareDirectory =
534 std::make_shared<decltype(hostFirmwareDirectory)>(
535 std::move(hostFirmwareDirectory));
536 auto pErrorCallback =
537 std::make_shared<decltype(errorCallback)>(std::move(errorCallback));
538
539 // register for a callback in case the IBMCompatibleSystem interface has
540 // not yet been published by entity manager.
541 auto interfacesAddedMatch = std::make_shared<sdbusplus::bus::match::match>(
542 bus,
543 sdbusplus::bus::match::rules::interfacesAdded() +
544 sdbusplus::bus::match::rules::sender(
545 "xyz.openbmc_project.EntityManager"),
546 [pExtensionMap, pHostFirmwareDirectory, pErrorCallback,
547 &loop](auto& message) {
548 // bind the extension map, host firmware directory, and error
549 // callback to the maybeMakeLinks function.
550 auto maybeMakeLinksWithArgsBound =
551 std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
552 std::cref(*pHostFirmwareDirectory),
553 std::placeholders::_1, std::cref(*pErrorCallback));
554
555 // if the InterfacesAdded message contains an an instance of
556 // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to
557 // see if links are necessary on this system and if so, create
558 // them.
559 if (maybeCallMessage(message, maybeMakeLinksWithArgsBound))
560 {
561 // The IBMCompatibleSystem interface was found and the links
562 // were created if applicable. Instruct the event loop /
563 // subcommand to exit.
564 loop.exit(0);
565 }
566 });
567
568 // now that we'll get a callback in the event of an InterfacesAdded signal
569 // (potentially containing
570 // xyz.openbmc_project.Configuration.IBMCompatibleSystem), activate entity
571 // manager if it isn't running and enumerate its objects
572 auto getManagedObjects = bus.new_method_call(
573 "xyz.openbmc_project.EntityManager", "/",
574 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Brad Bishop099543e2020-11-09 15:37:58 -0500575 std::map<std::string,
576 std::map<std::string, std::variant<std::vector<std::string>>>>
577 interfacesAndProperties;
578 std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
579 objects;
Adriana Kobylakc79fa912021-06-22 15:37:50 +0000580 try
581 {
582 auto reply = bus.call(getManagedObjects);
583 reply.read(objects);
584 }
585 catch (const sdbusplus::exception::SdBusError& e)
586 {
587 // Error querying the EntityManager interface. Return the match to have
588 // the callback run if/when the interface appears in D-Bus.
589 return interfacesAddedMatch;
590 }
Brad Bishop099543e2020-11-09 15:37:58 -0500591
592 // bind the extension map, host firmware directory, and error callback to
593 // the maybeMakeLinks function.
594 auto maybeMakeLinksWithArgsBound =
595 std::bind(maybeMakeLinks, std::cref(*pExtensionMap),
596 std::cref(*pHostFirmwareDirectory), std::placeholders::_1,
597 std::cref(*pErrorCallback));
598
599 for (const auto& pair : objects)
600 {
601 std::tie(std::ignore, interfacesAndProperties) = pair;
602 // if interfacesAndProperties contains an an instance of
603 // xyz.openbmc_project.Configuration.IBMCompatibleSystem, check to see
604 // if links are necessary on this system and if so, create them
605 if (maybeCall(interfacesAndProperties, maybeMakeLinksWithArgsBound))
606 {
607 // The IBMCompatibleSystem interface is already on the bus and the
608 // links were created if applicable. Instruct the event loop to
609 // exit.
610 loop.exit(0);
611 // The match object isn't needed anymore, so destroy it on return.
612 return nullptr;
613 }
614 }
615
616 // The IBMCompatibleSystem interface has not yet been published. Move
617 // ownership of the match callback to the caller.
618 return interfacesAddedMatch;
619}
Adriana Kobylak53a27392021-06-14 17:42:40 +0000620
621/**
622 * @brief Update the Bios Attribute Table
623 *
624 * If an instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
625 * found, update the Bios Attribute Table with the appropriate host firmware
626 * data.
627 *
628 * @param[in] bus - D-Bus client connection.
629 * @param[in] extensionMap - Map of IBMCompatibleSystem names and host firmware
630 * file extensions.
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000631 * @param[in] elementsJsonFilePath - The Path to the json file
Adriana Kobylak53a27392021-06-14 17:42:40 +0000632 * @param[in] loop - Program event loop.
633 * @return nullptr
634 */
635std::shared_ptr<void> updateBiosAttrTable(
636 sdbusplus::bus::bus& bus,
637 std::map<std::string, std::vector<std::string>> extensionMap,
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000638 std::filesystem::path elementsJsonFilePath, sdeventplus::Event& loop)
Adriana Kobylak53a27392021-06-14 17:42:40 +0000639{
640 auto pExtensionMap =
641 std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000642 auto pElementsJsonFilePath =
643 std::make_shared<decltype(elementsJsonFilePath)>(
644 std::move(elementsJsonFilePath));
Adriana Kobylak53a27392021-06-14 17:42:40 +0000645
646 auto getManagedObjects = bus.new_method_call(
647 "xyz.openbmc_project.EntityManager", "/",
648 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
649 std::map<std::string,
650 std::map<std::string, std::variant<std::vector<std::string>>>>
651 interfacesAndProperties;
652 std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
653 objects;
654 try
655 {
656 auto reply = bus.call(getManagedObjects);
657 reply.read(objects);
658 }
659 catch (const sdbusplus::exception::SdBusError& e)
660 {}
661
Adriana Kobylakae0998f2021-06-16 19:52:24 +0000662 auto maybeSetAttrWithArgsBound =
663 std::bind(maybeSetBiosAttr, std::cref(*pExtensionMap),
664 std::cref(*pElementsJsonFilePath), std::placeholders::_1);
Adriana Kobylak53a27392021-06-14 17:42:40 +0000665
666 for (const auto& pair : objects)
667 {
668 std::tie(std::ignore, interfacesAndProperties) = pair;
669 if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound))
670 {
671 break;
672 }
673 }
674
675 loop.exit(0);
676 return nullptr;
677}
678
Brad Bishop099543e2020-11-09 15:37:58 -0500679} // namespace process_hostfirmware
680} // namespace functions