xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 2b82937ecef572954b49569177b16831cbc09cfe)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include "dbus_singleton.hpp"
19 #include "health.hpp"
20 #include "led.hpp"
21 #include "pcie.hpp"
22 #include "query.hpp"
23 #include "redfish_util.hpp"
24 #include "utils/time_utils.hpp"
25 
26 #include <app.hpp>
27 #include <boost/container/flat_map.hpp>
28 #include <dbus_utility.hpp>
29 #include <registries/privilege_registry.hpp>
30 #include <sdbusplus/asio/property.hpp>
31 #include <utils/json_utils.hpp>
32 #include <utils/sw_utils.hpp>
33 
34 #include <variant>
35 
36 namespace redfish
37 {
38 
39 /**
40  * @brief Updates the Functional State of DIMMs
41  *
42  * @param[in] aResp Shared pointer for completing asynchronous calls
43  * @param[in] dimmState Dimm's Functional state, true/false
44  *
45  * @return None.
46  */
47 inline void
48     updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
49                          bool isDimmFunctional)
50 {
51     BMCWEB_LOG_DEBUG << "Dimm Functional: " << isDimmFunctional;
52 
53     // Set it as Enabled if at least one DIMM is functional
54     // Update STATE only if previous State was DISABLED and current Dimm is
55     // ENABLED.
56     const nlohmann::json& prevMemSummary =
57         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
58     if (prevMemSummary == "Disabled")
59     {
60         if (isDimmFunctional)
61         {
62             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
63                 "Enabled";
64         }
65     }
66 }
67 
68 /*
69  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
70  *
71  * @param[in] aResp Shared pointer for completing asynchronous calls
72  * @param[in] cpuPresenceState CPU present or not
73  *
74  * @return None.
75  */
76 inline void
77     modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
78                            bool isCpuPresent)
79 {
80     BMCWEB_LOG_DEBUG << "Cpu Present: " << isCpuPresent;
81 
82     if (isCpuPresent)
83     {
84         nlohmann::json& procCount =
85             aResp->res.jsonValue["ProcessorSummary"]["Count"];
86         auto* procCountPtr =
87             procCount.get_ptr<nlohmann::json::number_integer_t*>();
88         if (procCountPtr != nullptr)
89         {
90             // shouldn't be possible to be nullptr
91             *procCountPtr += 1;
92         }
93     }
94 }
95 
96 /*
97  * @brief Update "ProcessorSummary" "Status" "State" based on
98  *        CPU Functional State
99  *
100  * @param[in] aResp Shared pointer for completing asynchronous calls
101  * @param[in] cpuFunctionalState is CPU functional true/false
102  *
103  * @return None.
104  */
105 inline void
106     modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
107                              bool isCpuFunctional)
108 {
109     BMCWEB_LOG_DEBUG << "Cpu Functional: " << isCpuFunctional;
110 
111     const nlohmann::json& prevProcState =
112         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
113 
114     // Set it as Enabled if at least one CPU is functional
115     // Update STATE only if previous State was Non_Functional and current CPU is
116     // Functional.
117     if (prevProcState == "Disabled")
118     {
119         if (isCpuFunctional)
120         {
121             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
122                 "Enabled";
123         }
124     }
125 }
126 
127 inline void
128     getProcessorProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
129                            const std::string& service, const std::string& path,
130                            const dbus::utility::DBusPropertiesMap& properties)
131 {
132 
133     BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties.";
134 
135     auto getCpuPresenceState = [aResp](const boost::system::error_code ec3,
136                                        const bool cpuPresenceCheck) {
137         if (ec3)
138         {
139             BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
140             return;
141         }
142         modifyCpuPresenceState(aResp, cpuPresenceCheck);
143     };
144 
145     auto getCpuFunctionalState = [aResp](const boost::system::error_code ec3,
146                                          const bool cpuFunctionalCheck) {
147         if (ec3)
148         {
149             BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
150             return;
151         }
152         modifyCpuFunctionalState(aResp, cpuFunctionalCheck);
153     };
154 
155     // Get the Presence of CPU
156     sdbusplus::asio::getProperty<bool>(
157         *crow::connections::systemBus, service, path,
158         "xyz.openbmc_project.Inventory.Item", "Present",
159         std::move(getCpuPresenceState));
160 
161     // Get the Functional State
162     sdbusplus::asio::getProperty<bool>(
163         *crow::connections::systemBus, service, path,
164         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
165         std::move(getCpuFunctionalState));
166 
167     for (const auto& property : properties)
168     {
169 
170         // TODO: Get Model
171 
172         // Get CoreCount
173         if (property.first == "CoreCount")
174         {
175 
176             // Get CPU CoreCount and add it to the total
177             const uint16_t* coreCountVal =
178                 std::get_if<uint16_t>(&property.second);
179 
180             if (coreCountVal == nullptr)
181             {
182                 messages::internalError(aResp->res);
183                 return;
184             }
185 
186             nlohmann::json& coreCount =
187                 aResp->res.jsonValue["ProcessorSummary"]["CoreCount"];
188             uint64_t* coreCountPtr = coreCount.get_ptr<uint64_t*>();
189 
190             if (coreCountPtr == nullptr)
191             {
192                 coreCount = *coreCountVal;
193             }
194             else
195             {
196                 *coreCountPtr += *coreCountVal;
197             }
198         }
199     }
200 }
201 
202 /*
203  * @brief Get ProcessorSummary fields
204  *
205  * @param[in] aResp Shared pointer for completing asynchronous calls
206  * @param[in] service dbus service for Cpu Information
207  * @param[in] path dbus path for Cpu
208  *
209  * @return None.
210  */
211 inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
212                                 const std::string& service,
213                                 const std::string& path)
214 {
215 
216     crow::connections::systemBus->async_method_call(
217         [aResp, service,
218          path](const boost::system::error_code ec2,
219                const dbus::utility::DBusPropertiesMap& properties) {
220         if (ec2)
221         {
222             BMCWEB_LOG_ERROR << "DBUS response error " << ec2;
223             messages::internalError(aResp->res);
224             return;
225         }
226         getProcessorProperties(aResp, service, path, properties);
227         },
228         service, path, "org.freedesktop.DBus.Properties", "GetAll",
229         "xyz.openbmc_project.Inventory.Item.Cpu");
230 }
231 
232 /*
233  * @brief Retrieves computer system properties over dbus
234  *
235  * @param[in] aResp Shared pointer for completing asynchronous calls
236  * @param[in] systemHealth  Shared HealthPopulate pointer
237  *
238  * @return None.
239  */
240 inline void
241     getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
242                       const std::shared_ptr<HealthPopulate>& systemHealth)
243 {
244     BMCWEB_LOG_DEBUG << "Get available system components.";
245 
246     crow::connections::systemBus->async_method_call(
247         [aResp,
248          systemHealth](const boost::system::error_code ec,
249                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
250         if (ec)
251         {
252             BMCWEB_LOG_DEBUG << "DBUS response error";
253             messages::internalError(aResp->res);
254             return;
255         }
256         // Iterate over all retrieved ObjectPaths.
257         for (const std::pair<
258                  std::string,
259                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
260                  object : subtree)
261         {
262             const std::string& path = object.first;
263             BMCWEB_LOG_DEBUG << "Got path: " << path;
264             const std::vector<std::pair<std::string, std::vector<std::string>>>&
265                 connectionNames = object.second;
266             if (connectionNames.empty())
267             {
268                 continue;
269             }
270 
271             auto memoryHealth = std::make_shared<HealthPopulate>(
272                 aResp, "/MemorySummary/Status"_json_pointer);
273 
274             auto cpuHealth = std::make_shared<HealthPopulate>(
275                 aResp, "/ProcessorSummary/Status"_json_pointer);
276 
277             systemHealth->children.emplace_back(memoryHealth);
278             systemHealth->children.emplace_back(cpuHealth);
279 
280             // This is not system, so check if it's cpu, dimm, UUID or
281             // BiosVer
282             for (const auto& connection : connectionNames)
283             {
284                 for (const auto& interfaceName : connection.second)
285                 {
286                     if (interfaceName ==
287                         "xyz.openbmc_project.Inventory.Item.Dimm")
288                     {
289                         BMCWEB_LOG_DEBUG
290                             << "Found Dimm, now get its properties.";
291 
292                         crow::connections::systemBus->async_method_call(
293                             [aResp, service{connection.first},
294                              path](const boost::system::error_code ec2,
295                                    const dbus::utility::DBusPropertiesMap&
296                                        properties) {
297                             if (ec2)
298                             {
299                                 BMCWEB_LOG_ERROR << "DBUS response error "
300                                                  << ec2;
301                                 messages::internalError(aResp->res);
302                                 return;
303                             }
304                             BMCWEB_LOG_DEBUG << "Got " << properties.size()
305                                              << " Dimm properties.";
306 
307                             if (!properties.empty())
308                             {
309                                 for (const std::pair<
310                                          std::string,
311                                          dbus::utility::DbusVariantType>&
312                                          property : properties)
313                                 {
314                                     if (property.first != "MemorySizeInKB")
315                                     {
316                                         continue;
317                                     }
318                                     const uint32_t* value =
319                                         std::get_if<uint32_t>(&property.second);
320                                     if (value == nullptr)
321                                     {
322                                         BMCWEB_LOG_DEBUG
323                                             << "Find incorrect type of MemorySize";
324                                         continue;
325                                     }
326                                     nlohmann::json& totalMemory =
327                                         aResp->res
328                                             .jsonValue["MemorySummary"]
329                                                       ["TotalSystemMemoryGiB"];
330                                     const uint64_t* preValue =
331                                         totalMemory.get_ptr<const uint64_t*>();
332                                     if (preValue == nullptr)
333                                     {
334                                         continue;
335                                     }
336                                     aResp->res
337                                         .jsonValue["MemorySummary"]
338                                                   ["TotalSystemMemoryGiB"] =
339                                         *value / (1024 * 1024) + *preValue;
340                                     aResp->res.jsonValue["MemorySummary"]
341                                                         ["Status"]["State"] =
342                                         "Enabled";
343                                 }
344                             }
345                             else
346                             {
347                                 sdbusplus::asio::getProperty<bool>(
348                                     *crow::connections::systemBus, service,
349                                     path,
350                                     "xyz.openbmc_project.State."
351                                     "Decorator.OperationalStatus",
352                                     "Functional",
353                                     [aResp](const boost::system::error_code ec3,
354                                             bool dimmState) {
355                                     if (ec3)
356                                     {
357                                         BMCWEB_LOG_ERROR
358                                             << "DBUS response error " << ec3;
359                                         return;
360                                     }
361                                     updateDimmProperties(aResp, dimmState);
362                                     });
363                             }
364                             },
365                             connection.first, path,
366                             "org.freedesktop.DBus.Properties", "GetAll",
367                             "xyz.openbmc_project.Inventory.Item.Dimm");
368 
369                         memoryHealth->inventory.emplace_back(path);
370                     }
371                     else if (interfaceName ==
372                              "xyz.openbmc_project.Inventory.Item.Cpu")
373                     {
374                         BMCWEB_LOG_DEBUG
375                             << "Found Cpu, now get its properties.";
376 
377                         getProcessorSummary(aResp, connection.first, path);
378 
379                         cpuHealth->inventory.emplace_back(path);
380                     }
381                     else if (interfaceName == "xyz.openbmc_project.Common.UUID")
382                     {
383                         BMCWEB_LOG_DEBUG
384                             << "Found UUID, now get its properties.";
385                         crow::connections::systemBus->async_method_call(
386                             [aResp](const boost::system::error_code ec3,
387                                     const dbus::utility::DBusPropertiesMap&
388                                         properties) {
389                             if (ec3)
390                             {
391                                 BMCWEB_LOG_DEBUG << "DBUS response error "
392                                                  << ec3;
393                                 messages::internalError(aResp->res);
394                                 return;
395                             }
396                             BMCWEB_LOG_DEBUG << "Got " << properties.size()
397                                              << " UUID properties.";
398                             for (const std::pair<
399                                      std::string,
400                                      dbus::utility::DbusVariantType>& property :
401                                  properties)
402                             {
403                                 if (property.first == "UUID")
404                                 {
405                                     const std::string* value =
406                                         std::get_if<std::string>(
407                                             &property.second);
408 
409                                     if (value != nullptr)
410                                     {
411                                         std::string valueStr = *value;
412                                         if (valueStr.size() == 32)
413                                         {
414                                             valueStr.insert(8, 1, '-');
415                                             valueStr.insert(13, 1, '-');
416                                             valueStr.insert(18, 1, '-');
417                                             valueStr.insert(23, 1, '-');
418                                         }
419                                         BMCWEB_LOG_DEBUG << "UUID = "
420                                                          << valueStr;
421                                         aResp->res.jsonValue["UUID"] = valueStr;
422                                     }
423                                 }
424                             }
425                             },
426                             connection.first, path,
427                             "org.freedesktop.DBus.Properties", "GetAll",
428                             "xyz.openbmc_project.Common.UUID");
429                     }
430                     else if (interfaceName ==
431                              "xyz.openbmc_project.Inventory.Item.System")
432                     {
433                         crow::connections::systemBus->async_method_call(
434                             [aResp](const boost::system::error_code ec2,
435                                     const dbus::utility::DBusPropertiesMap&
436                                         propertiesList) {
437                             if (ec2)
438                             {
439                                 // doesn't have to include this
440                                 // interface
441                                 return;
442                             }
443                             BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
444                                              << " properties for system";
445                             for (const std::pair<
446                                      std::string,
447                                      dbus::utility::DbusVariantType>& property :
448                                  propertiesList)
449                             {
450                                 const std::string& propertyName =
451                                     property.first;
452                                 if ((propertyName == "PartNumber") ||
453                                     (propertyName == "SerialNumber") ||
454                                     (propertyName == "Manufacturer") ||
455                                     (propertyName == "Model") ||
456                                     (propertyName == "SubModel"))
457                                 {
458                                     const std::string* value =
459                                         std::get_if<std::string>(
460                                             &property.second);
461                                     if (value != nullptr)
462                                     {
463                                         aResp->res.jsonValue[propertyName] =
464                                             *value;
465                                     }
466                                 }
467                             }
468 
469                             // Grab the bios version
470                             sw_util::populateSoftwareInformation(
471                                 aResp, sw_util::biosPurpose, "BiosVersion",
472                                 false);
473                             },
474                             connection.first, path,
475                             "org.freedesktop.DBus.Properties", "GetAll",
476                             "xyz.openbmc_project.Inventory.Decorator.Asset");
477 
478                         sdbusplus::asio::getProperty<std::string>(
479                             *crow::connections::systemBus, connection.first,
480                             path,
481                             "xyz.openbmc_project.Inventory.Decorator."
482                             "AssetTag",
483                             "AssetTag",
484                             [aResp](const boost::system::error_code ec2,
485                                     const std::string& value) {
486                             if (ec2)
487                             {
488                                 // doesn't have to include this
489                                 // interface
490                                 return;
491                             }
492 
493                             aResp->res.jsonValue["AssetTag"] = value;
494                             });
495                     }
496                 }
497             }
498         }
499         },
500         "xyz.openbmc_project.ObjectMapper",
501         "/xyz/openbmc_project/object_mapper",
502         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
503         "/xyz/openbmc_project/inventory", int32_t(0),
504         std::array<const char*, 5>{
505             "xyz.openbmc_project.Inventory.Decorator.Asset",
506             "xyz.openbmc_project.Inventory.Item.Cpu",
507             "xyz.openbmc_project.Inventory.Item.Dimm",
508             "xyz.openbmc_project.Inventory.Item.System",
509             "xyz.openbmc_project.Common.UUID",
510         });
511 }
512 
513 /**
514  * @brief Retrieves host state properties over dbus
515  *
516  * @param[in] aResp     Shared pointer for completing asynchronous calls.
517  *
518  * @return None.
519  */
520 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
521 {
522     BMCWEB_LOG_DEBUG << "Get host information.";
523     sdbusplus::asio::getProperty<std::string>(
524         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
525         "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host",
526         "CurrentHostState",
527         [aResp](const boost::system::error_code ec,
528                 const std::string& hostState) {
529         if (ec)
530         {
531             if (ec == boost::system::errc::host_unreachable)
532             {
533                 // Service not available, no error, just don't return
534                 // host state info
535                 BMCWEB_LOG_DEBUG << "Service not available " << ec;
536                 return;
537             }
538             BMCWEB_LOG_ERROR << "DBUS response error " << ec;
539             messages::internalError(aResp->res);
540             return;
541         }
542 
543         BMCWEB_LOG_DEBUG << "Host state: " << hostState;
544         // Verify Host State
545         if (hostState == "xyz.openbmc_project.State.Host.HostState.Running")
546         {
547             aResp->res.jsonValue["PowerState"] = "On";
548             aResp->res.jsonValue["Status"]["State"] = "Enabled";
549         }
550         else if (hostState ==
551                  "xyz.openbmc_project.State.Host.HostState.Quiesced")
552         {
553             aResp->res.jsonValue["PowerState"] = "On";
554             aResp->res.jsonValue["Status"]["State"] = "Quiesced";
555         }
556         else if (hostState ==
557                  "xyz.openbmc_project.State.Host.HostState.DiagnosticMode")
558         {
559             aResp->res.jsonValue["PowerState"] = "On";
560             aResp->res.jsonValue["Status"]["State"] = "InTest";
561         }
562         else if (
563             hostState ==
564             "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning")
565         {
566             aResp->res.jsonValue["PowerState"] = "PoweringOn";
567             aResp->res.jsonValue["Status"]["State"] = "Starting";
568         }
569         else if (hostState ==
570                  "xyz.openbmc_project.State.Host.HostState.TransitioningToOff")
571         {
572             aResp->res.jsonValue["PowerState"] = "PoweringOff";
573             aResp->res.jsonValue["Status"]["State"] = "Disabled";
574         }
575         else
576         {
577             aResp->res.jsonValue["PowerState"] = "Off";
578             aResp->res.jsonValue["Status"]["State"] = "Disabled";
579         }
580         });
581 }
582 
583 /**
584  * @brief Translates boot source DBUS property value to redfish.
585  *
586  * @param[in] dbusSource    The boot source in DBUS speak.
587  *
588  * @return Returns as a string, the boot source in Redfish terms. If translation
589  * cannot be done, returns an empty string.
590  */
591 inline std::string dbusToRfBootSource(const std::string& dbusSource)
592 {
593     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
594     {
595         return "None";
596     }
597     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
598     {
599         return "Hdd";
600     }
601     if (dbusSource ==
602         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
603     {
604         return "Cd";
605     }
606     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
607     {
608         return "Pxe";
609     }
610     if (dbusSource ==
611         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
612     {
613         return "Usb";
614     }
615     return "";
616 }
617 
618 /**
619  * @brief Translates boot type DBUS property value to redfish.
620  *
621  * @param[in] dbusType    The boot type in DBUS speak.
622  *
623  * @return Returns as a string, the boot type in Redfish terms. If translation
624  * cannot be done, returns an empty string.
625  */
626 inline std::string dbusToRfBootType(const std::string& dbusType)
627 {
628     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy")
629     {
630         return "Legacy";
631     }
632     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI")
633     {
634         return "UEFI";
635     }
636     return "";
637 }
638 
639 /**
640  * @brief Translates boot mode DBUS property value to redfish.
641  *
642  * @param[in] dbusMode    The boot mode in DBUS speak.
643  *
644  * @return Returns as a string, the boot mode in Redfish terms. If translation
645  * cannot be done, returns an empty string.
646  */
647 inline std::string dbusToRfBootMode(const std::string& dbusMode)
648 {
649     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
650     {
651         return "None";
652     }
653     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
654     {
655         return "Diags";
656     }
657     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
658     {
659         return "BiosSetup";
660     }
661     return "";
662 }
663 
664 /**
665  * @brief Translates boot progress DBUS property value to redfish.
666  *
667  * @param[in] dbusBootProgress    The boot progress in DBUS speak.
668  *
669  * @return Returns as a string, the boot progress in Redfish terms. If
670  *         translation cannot be done, returns "None".
671  */
672 inline std::string dbusToRfBootProgress(const std::string& dbusBootProgress)
673 {
674     // Now convert the D-Bus BootProgress to the appropriate Redfish
675     // enum
676     std::string rfBpLastState = "None";
677     if (dbusBootProgress == "xyz.openbmc_project.State.Boot.Progress."
678                             "ProgressStages.Unspecified")
679     {
680         rfBpLastState = "None";
681     }
682     else if (dbusBootProgress ==
683              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
684              "PrimaryProcInit")
685     {
686         rfBpLastState = "PrimaryProcessorInitializationStarted";
687     }
688     else if (dbusBootProgress ==
689              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
690              "BusInit")
691     {
692         rfBpLastState = "BusInitializationStarted";
693     }
694     else if (dbusBootProgress ==
695              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
696              "MemoryInit")
697     {
698         rfBpLastState = "MemoryInitializationStarted";
699     }
700     else if (dbusBootProgress ==
701              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
702              "SecondaryProcInit")
703     {
704         rfBpLastState = "SecondaryProcessorInitializationStarted";
705     }
706     else if (dbusBootProgress ==
707              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
708              "PCIInit")
709     {
710         rfBpLastState = "PCIResourceConfigStarted";
711     }
712     else if (dbusBootProgress ==
713              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
714              "SystemSetup")
715     {
716         rfBpLastState = "SetupEntered";
717     }
718     else if (dbusBootProgress ==
719              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
720              "SystemInitComplete")
721     {
722         rfBpLastState = "SystemHardwareInitializationComplete";
723     }
724     else if (dbusBootProgress ==
725              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
726              "OSStart")
727     {
728         rfBpLastState = "OSBootStarted";
729     }
730     else if (dbusBootProgress ==
731              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
732              "OSRunning")
733     {
734         rfBpLastState = "OSRunning";
735     }
736     else
737     {
738         BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
739                          << dbusBootProgress;
740         // Just return the default
741     }
742     return rfBpLastState;
743 }
744 
745 /**
746  * @brief Translates boot source from Redfish to the DBus boot paths.
747  *
748  * @param[in] rfSource    The boot source in Redfish.
749  * @param[out] bootSource The DBus source
750  * @param[out] bootMode   the DBus boot mode
751  *
752  * @return Integer error code.
753  */
754 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
755                                 const std::string& rfSource,
756                                 std::string& bootSource, std::string& bootMode)
757 {
758     bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
759     bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
760 
761     if (rfSource == "None")
762     {
763         return 0;
764     }
765     if (rfSource == "Pxe")
766     {
767         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
768     }
769     else if (rfSource == "Hdd")
770     {
771         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
772     }
773     else if (rfSource == "Diags")
774     {
775         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
776     }
777     else if (rfSource == "Cd")
778     {
779         bootSource =
780             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
781     }
782     else if (rfSource == "BiosSetup")
783     {
784         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
785     }
786     else if (rfSource == "Usb")
787     {
788         bootSource =
789             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
790     }
791     else
792     {
793         BMCWEB_LOG_DEBUG
794             << "Invalid property value for BootSourceOverrideTarget: "
795             << bootSource;
796         messages::propertyValueNotInList(aResp->res, rfSource,
797                                          "BootSourceTargetOverride");
798         return -1;
799     }
800     return 0;
801 }
802 
803 /**
804  * @brief Retrieves boot progress of the system
805  *
806  * @param[in] aResp  Shared pointer for generating response message.
807  *
808  * @return None.
809  */
810 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
811 {
812     sdbusplus::asio::getProperty<std::string>(
813         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
814         "/xyz/openbmc_project/state/host0",
815         "xyz.openbmc_project.State.Boot.Progress", "BootProgress",
816         [aResp](const boost::system::error_code ec,
817                 const std::string& bootProgressStr) {
818         if (ec)
819         {
820             // BootProgress is an optional object so just do nothing if
821             // not found
822             return;
823         }
824 
825         BMCWEB_LOG_DEBUG << "Boot Progress: " << bootProgressStr;
826 
827         aResp->res.jsonValue["BootProgress"]["LastState"] =
828             dbusToRfBootProgress(bootProgressStr);
829         });
830 }
831 
832 /**
833  * @brief Retrieves boot override type over DBUS and fills out the response
834  *
835  * @param[in] aResp         Shared pointer for generating response message.
836  *
837  * @return None.
838  */
839 
840 inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
841 {
842     sdbusplus::asio::getProperty<std::string>(
843         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
844         "/xyz/openbmc_project/control/host0/boot",
845         "xyz.openbmc_project.Control.Boot.Type", "BootType",
846         [aResp](const boost::system::error_code ec,
847                 const std::string& bootType) {
848         if (ec)
849         {
850             // not an error, don't have to have the interface
851             return;
852         }
853 
854         BMCWEB_LOG_DEBUG << "Boot type: " << bootType;
855 
856         aResp->res.jsonValue["Boot"]
857                             ["BootSourceOverrideMode@Redfish.AllowableValues"] =
858             {"Legacy", "UEFI"};
859 
860         auto rfType = dbusToRfBootType(bootType);
861         if (rfType.empty())
862         {
863             messages::internalError(aResp->res);
864             return;
865         }
866 
867         aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType;
868         });
869 }
870 
871 /**
872  * @brief Retrieves boot override mode over DBUS and fills out the response
873  *
874  * @param[in] aResp         Shared pointer for generating response message.
875  *
876  * @return None.
877  */
878 
879 inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
880 {
881     sdbusplus::asio::getProperty<std::string>(
882         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
883         "/xyz/openbmc_project/control/host0/boot",
884         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
885         [aResp](const boost::system::error_code ec,
886                 const std::string& bootModeStr) {
887         if (ec)
888         {
889             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
890             messages::internalError(aResp->res);
891             return;
892         }
893 
894         BMCWEB_LOG_DEBUG << "Boot mode: " << bootModeStr;
895 
896         aResp->res
897             .jsonValue["Boot"]
898                       ["BootSourceOverrideTarget@Redfish.AllowableValues"] = {
899             "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
900 
901         if (bootModeStr !=
902             "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
903         {
904             auto rfMode = dbusToRfBootMode(bootModeStr);
905             if (!rfMode.empty())
906             {
907                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
908                     rfMode;
909             }
910         }
911         });
912 }
913 
914 /**
915  * @brief Retrieves boot override source over DBUS
916  *
917  * @param[in] aResp         Shared pointer for generating response message.
918  *
919  * @return None.
920  */
921 
922 inline void
923     getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
924 {
925     sdbusplus::asio::getProperty<std::string>(
926         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
927         "/xyz/openbmc_project/control/host0/boot",
928         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
929         [aResp](const boost::system::error_code ec,
930                 const std::string& bootSourceStr) {
931         if (ec)
932         {
933             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
934             if (ec.value() == boost::asio::error::host_unreachable)
935             {
936                 return;
937             }
938             messages::internalError(aResp->res);
939             return;
940         }
941 
942         BMCWEB_LOG_DEBUG << "Boot source: " << bootSourceStr;
943 
944         auto rfSource = dbusToRfBootSource(bootSourceStr);
945         if (!rfSource.empty())
946         {
947             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = rfSource;
948         }
949 
950         // Get BootMode as BootSourceOverrideTarget is constructed
951         // from both BootSource and BootMode
952         getBootOverrideMode(aResp);
953         });
954 }
955 
956 /**
957  * @brief This functions abstracts all the logic behind getting a
958  * "BootSourceOverrideEnabled" property from an overall boot override enable
959  * state
960  *
961  * @param[in] aResp     Shared pointer for generating response message.
962  *
963  * @return None.
964  */
965 
966 inline void
967     processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
968                               const bool bootOverrideEnableSetting)
969 {
970     if (!bootOverrideEnableSetting)
971     {
972         aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled";
973         return;
974     }
975 
976     // If boot source override is enabled, we need to check 'one_time'
977     // property to set a correct value for the "BootSourceOverrideEnabled"
978     sdbusplus::asio::getProperty<bool>(
979         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
980         "/xyz/openbmc_project/control/host0/boot/one_time",
981         "xyz.openbmc_project.Object.Enable", "Enabled",
982         [aResp](const boost::system::error_code ec, bool oneTimeSetting) {
983         if (ec)
984         {
985             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
986             messages::internalError(aResp->res);
987             return;
988         }
989 
990         if (oneTimeSetting)
991         {
992             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Once";
993         }
994         else
995         {
996             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
997                 "Continuous";
998         }
999         });
1000 }
1001 
1002 /**
1003  * @brief Retrieves boot override enable over DBUS
1004  *
1005  * @param[in] aResp     Shared pointer for generating response message.
1006  *
1007  * @return None.
1008  */
1009 
1010 inline void
1011     getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1012 {
1013     sdbusplus::asio::getProperty<bool>(
1014         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1015         "/xyz/openbmc_project/control/host0/boot",
1016         "xyz.openbmc_project.Object.Enable", "Enabled",
1017         [aResp](const boost::system::error_code ec,
1018                 const bool bootOverrideEnable) {
1019         if (ec)
1020         {
1021             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1022             if (ec.value() == boost::asio::error::host_unreachable)
1023             {
1024                 return;
1025             }
1026             messages::internalError(aResp->res);
1027             return;
1028         }
1029 
1030         processBootOverrideEnable(aResp, bootOverrideEnable);
1031         });
1032 }
1033 
1034 /**
1035  * @brief Retrieves boot source override properties
1036  *
1037  * @param[in] aResp     Shared pointer for generating response message.
1038  *
1039  * @return None.
1040  */
1041 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1042 {
1043     BMCWEB_LOG_DEBUG << "Get boot information.";
1044 
1045     getBootOverrideSource(aResp);
1046     getBootOverrideType(aResp);
1047     getBootOverrideEnable(aResp);
1048 }
1049 
1050 /**
1051  * @brief Retrieves the Last Reset Time
1052  *
1053  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1054  * and power off. Even though this is the "system" Redfish object look at the
1055  * chassis D-Bus interface for the LastStateChangeTime since this has the
1056  * last power operation time.
1057  *
1058  * @param[in] aResp     Shared pointer for generating response message.
1059  *
1060  * @return None.
1061  */
1062 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1063 {
1064     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1065 
1066     sdbusplus::asio::getProperty<uint64_t>(
1067         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1068         "/xyz/openbmc_project/state/chassis0",
1069         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime",
1070         [aResp](const boost::system::error_code ec, uint64_t lastResetTime) {
1071         if (ec)
1072         {
1073             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1074             return;
1075         }
1076 
1077         // LastStateChangeTime is epoch time, in milliseconds
1078         // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1079         uint64_t lastResetTimeStamp = lastResetTime / 1000;
1080 
1081         // Convert to ISO 8601 standard
1082         aResp->res.jsonValue["LastResetTime"] =
1083             redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1084         });
1085 }
1086 
1087 /**
1088  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1089  *
1090  * @param[in] aResp     Shared pointer for generating response message.
1091  *
1092  * @return None.
1093  */
1094 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1095 {
1096     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1097 
1098     sdbusplus::asio::getProperty<bool>(
1099         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1100         "/xyz/openbmc_project/control/host0/auto_reboot",
1101         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1102         [aResp](const boost::system::error_code ec, bool autoRebootEnabled) {
1103         if (ec)
1104         {
1105             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1106             return;
1107         }
1108 
1109         BMCWEB_LOG_DEBUG << "Auto Reboot: " << autoRebootEnabled;
1110         if (autoRebootEnabled)
1111         {
1112             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1113                 "RetryAttempts";
1114             // If AutomaticRetry (AutoReboot) is enabled see how many
1115             // attempts are left
1116             sdbusplus::asio::getProperty<uint32_t>(
1117                 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
1118                 "/xyz/openbmc_project/state/host0",
1119                 "xyz.openbmc_project.Control.Boot.RebootAttempts",
1120                 "AttemptsLeft",
1121                 [aResp](const boost::system::error_code ec2,
1122                         const uint32_t autoRebootAttemptsLeft) {
1123                 if (ec2)
1124                 {
1125                     BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1126                     return;
1127                 }
1128 
1129                 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1130                                  << autoRebootAttemptsLeft;
1131 
1132                 aResp->res
1133                     .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
1134                     autoRebootAttemptsLeft;
1135                 });
1136         }
1137         else
1138         {
1139             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled";
1140         }
1141 
1142         // Not on D-Bus. Hardcoded here:
1143         // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1144         aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1145 
1146         // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1147         // and RetryAttempts. OpenBMC only supports Disabled and
1148         // RetryAttempts.
1149         aResp->res.jsonValue["Boot"]
1150                             ["AutomaticRetryConfig@Redfish.AllowableValues"] = {
1151             "Disabled", "RetryAttempts"};
1152         });
1153 }
1154 
1155 /**
1156  * @brief Retrieves power restore policy over DBUS.
1157  *
1158  * @param[in] aResp     Shared pointer for generating response message.
1159  *
1160  * @return None.
1161  */
1162 inline void
1163     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1164 {
1165     BMCWEB_LOG_DEBUG << "Get power restore policy";
1166 
1167     sdbusplus::asio::getProperty<std::string>(
1168         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1169         "/xyz/openbmc_project/control/host0/power_restore_policy",
1170         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1171         [aResp](const boost::system::error_code ec, const std::string& policy) {
1172         if (ec)
1173         {
1174             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1175             return;
1176         }
1177 
1178         const boost::container::flat_map<std::string, std::string> policyMaps = {
1179             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
1180              "AlwaysOn"},
1181             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
1182              "AlwaysOff"},
1183             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
1184              "LastState"},
1185             // Return `AlwaysOff` when power restore policy set to "None"
1186             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None",
1187              "AlwaysOff"}};
1188 
1189         auto policyMapsIt = policyMaps.find(policy);
1190         if (policyMapsIt == policyMaps.end())
1191         {
1192             messages::internalError(aResp->res);
1193             return;
1194         }
1195 
1196         aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1197         });
1198 }
1199 
1200 /**
1201  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1202  * TPM is required for booting the host.
1203  *
1204  * @param[in] aResp     Shared pointer for generating response message.
1205  *
1206  * @return None.
1207  */
1208 inline void getTrustedModuleRequiredToBoot(
1209     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1210 {
1211     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1212 
1213     crow::connections::systemBus->async_method_call(
1214         [aResp](const boost::system::error_code ec,
1215                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1216         if (ec)
1217         {
1218             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1219                              << ec;
1220             // This is an optional D-Bus object so just return if
1221             // error occurs
1222             return;
1223         }
1224         if (subtree.empty())
1225         {
1226             // As noted above, this is an optional interface so just return
1227             // if there is no instance found
1228             return;
1229         }
1230 
1231         /* When there is more than one TPMEnable object... */
1232         if (subtree.size() > 1)
1233         {
1234             BMCWEB_LOG_DEBUG
1235                 << "DBUS response has more than 1 TPM Enable object:"
1236                 << subtree.size();
1237             // Throw an internal Error and return
1238             messages::internalError(aResp->res);
1239             return;
1240         }
1241 
1242         // Make sure the Dbus response map has a service and objectPath
1243         // field
1244         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1245         {
1246             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1247             messages::internalError(aResp->res);
1248             return;
1249         }
1250 
1251         const std::string& path = subtree[0].first;
1252         const std::string& serv = subtree[0].second.begin()->first;
1253 
1254         // Valid TPM Enable object found, now reading the current value
1255         sdbusplus::asio::getProperty<bool>(
1256             *crow::connections::systemBus, serv, path,
1257             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1258             [aResp](const boost::system::error_code ec2, bool tpmRequired) {
1259             if (ec2)
1260             {
1261                 BMCWEB_LOG_DEBUG << "D-BUS response error on TPM.Policy Get"
1262                                  << ec2;
1263                 messages::internalError(aResp->res);
1264                 return;
1265             }
1266 
1267             if (tpmRequired)
1268             {
1269                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1270                     "Required";
1271             }
1272             else
1273             {
1274                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1275                     "Disabled";
1276             }
1277             });
1278         },
1279         "xyz.openbmc_project.ObjectMapper",
1280         "/xyz/openbmc_project/object_mapper",
1281         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1282         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1283 }
1284 
1285 /**
1286  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1287  * TPM is required for booting the host.
1288  *
1289  * @param[in] aResp         Shared pointer for generating response message.
1290  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1291  *
1292  * @return None.
1293  */
1294 inline void setTrustedModuleRequiredToBoot(
1295     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1296 {
1297     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1298 
1299     crow::connections::systemBus->async_method_call(
1300         [aResp, tpmRequired](const boost::system::error_code ec,
1301                              dbus::utility::MapperGetSubTreeResponse& subtree) {
1302         if (ec)
1303         {
1304             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1305                              << ec;
1306             messages::internalError(aResp->res);
1307             return;
1308         }
1309         if (subtree.empty())
1310         {
1311             messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1312                                              "TrustedModuleRequiredToBoot");
1313             return;
1314         }
1315 
1316         /* When there is more than one TPMEnable object... */
1317         if (subtree.size() > 1)
1318         {
1319             BMCWEB_LOG_DEBUG
1320                 << "DBUS response has more than 1 TPM Enable object:"
1321                 << subtree.size();
1322             // Throw an internal Error and return
1323             messages::internalError(aResp->res);
1324             return;
1325         }
1326 
1327         // Make sure the Dbus response map has a service and objectPath
1328         // field
1329         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1330         {
1331             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1332             messages::internalError(aResp->res);
1333             return;
1334         }
1335 
1336         const std::string& path = subtree[0].first;
1337         const std::string& serv = subtree[0].second.begin()->first;
1338 
1339         if (serv.empty())
1340         {
1341             BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1342             messages::internalError(aResp->res);
1343             return;
1344         }
1345 
1346         // Valid TPM Enable object found, now setting the value
1347         crow::connections::systemBus->async_method_call(
1348             [aResp](const boost::system::error_code ec2) {
1349             if (ec2)
1350             {
1351                 BMCWEB_LOG_DEBUG
1352                     << "DBUS response error: Set TrustedModuleRequiredToBoot"
1353                     << ec2;
1354                 messages::internalError(aResp->res);
1355                 return;
1356             }
1357             BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1358             },
1359             serv, path, "org.freedesktop.DBus.Properties", "Set",
1360             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1361             dbus::utility::DbusVariantType(tpmRequired));
1362         },
1363         "xyz.openbmc_project.ObjectMapper",
1364         "/xyz/openbmc_project/object_mapper",
1365         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1366         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1367 }
1368 
1369 /**
1370  * @brief Sets boot properties into DBUS object(s).
1371  *
1372  * @param[in] aResp           Shared pointer for generating response message.
1373  * @param[in] bootType        The boot type to set.
1374  * @return Integer error code.
1375  */
1376 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1377                         const std::optional<std::string>& bootType)
1378 {
1379     std::string bootTypeStr;
1380 
1381     if (!bootType)
1382     {
1383         return;
1384     }
1385 
1386     // Source target specified
1387     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1388     // Figure out which DBUS interface and property to use
1389     if (*bootType == "Legacy")
1390     {
1391         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1392     }
1393     else if (*bootType == "UEFI")
1394     {
1395         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1396     }
1397     else
1398     {
1399         BMCWEB_LOG_DEBUG << "Invalid property value for "
1400                             "BootSourceOverrideMode: "
1401                          << *bootType;
1402         messages::propertyValueNotInList(aResp->res, *bootType,
1403                                          "BootSourceOverrideMode");
1404         return;
1405     }
1406 
1407     // Act on validated parameters
1408     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1409 
1410     crow::connections::systemBus->async_method_call(
1411         [aResp](const boost::system::error_code ec) {
1412         if (ec)
1413         {
1414             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1415             if (ec.value() == boost::asio::error::host_unreachable)
1416             {
1417                 messages::resourceNotFound(aResp->res, "Set", "BootType");
1418                 return;
1419             }
1420             messages::internalError(aResp->res);
1421             return;
1422         }
1423         BMCWEB_LOG_DEBUG << "Boot type update done.";
1424         },
1425         "xyz.openbmc_project.Settings",
1426         "/xyz/openbmc_project/control/host0/boot",
1427         "org.freedesktop.DBus.Properties", "Set",
1428         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1429         dbus::utility::DbusVariantType(bootTypeStr));
1430 }
1431 
1432 /**
1433  * @brief Sets boot properties into DBUS object(s).
1434  *
1435  * @param[in] aResp           Shared pointer for generating response message.
1436  * @param[in] bootType        The boot type to set.
1437  * @return Integer error code.
1438  */
1439 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1440                           const std::optional<std::string>& bootEnable)
1441 {
1442     if (!bootEnable)
1443     {
1444         return;
1445     }
1446     // Source target specified
1447     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1448 
1449     bool bootOverrideEnable = false;
1450     bool bootOverridePersistent = false;
1451     // Figure out which DBUS interface and property to use
1452     if (*bootEnable == "Disabled")
1453     {
1454         bootOverrideEnable = false;
1455     }
1456     else if (*bootEnable == "Once")
1457     {
1458         bootOverrideEnable = true;
1459         bootOverridePersistent = false;
1460     }
1461     else if (*bootEnable == "Continuous")
1462     {
1463         bootOverrideEnable = true;
1464         bootOverridePersistent = true;
1465     }
1466     else
1467     {
1468         BMCWEB_LOG_DEBUG
1469             << "Invalid property value for BootSourceOverrideEnabled: "
1470             << *bootEnable;
1471         messages::propertyValueNotInList(aResp->res, *bootEnable,
1472                                          "BootSourceOverrideEnabled");
1473         return;
1474     }
1475 
1476     // Act on validated parameters
1477     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1478 
1479     crow::connections::systemBus->async_method_call(
1480         [aResp](const boost::system::error_code ec2) {
1481         if (ec2)
1482         {
1483             BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
1484             messages::internalError(aResp->res);
1485             return;
1486         }
1487         BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1488         },
1489         "xyz.openbmc_project.Settings",
1490         "/xyz/openbmc_project/control/host0/boot",
1491         "org.freedesktop.DBus.Properties", "Set",
1492         "xyz.openbmc_project.Object.Enable", "Enabled",
1493         dbus::utility::DbusVariantType(bootOverrideEnable));
1494 
1495     if (!bootOverrideEnable)
1496     {
1497         return;
1498     }
1499 
1500     // In case boot override is enabled we need to set correct value for the
1501     // 'one_time' enable DBus interface
1502     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1503                      << bootOverridePersistent;
1504 
1505     crow::connections::systemBus->async_method_call(
1506         [aResp](const boost::system::error_code ec) {
1507         if (ec)
1508         {
1509             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1510             messages::internalError(aResp->res);
1511             return;
1512         }
1513         BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1514         },
1515         "xyz.openbmc_project.Settings",
1516         "/xyz/openbmc_project/control/host0/boot/one_time",
1517         "org.freedesktop.DBus.Properties", "Set",
1518         "xyz.openbmc_project.Object.Enable", "Enabled",
1519         dbus::utility::DbusVariantType(!bootOverridePersistent));
1520 }
1521 
1522 /**
1523  * @brief Sets boot properties into DBUS object(s).
1524  *
1525  * @param[in] aResp           Shared pointer for generating response message.
1526  * @param[in] bootSource      The boot source to set.
1527  *
1528  * @return Integer error code.
1529  */
1530 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1531                                 const std::optional<std::string>& bootSource)
1532 {
1533     std::string bootSourceStr;
1534     std::string bootModeStr;
1535 
1536     if (!bootSource)
1537     {
1538         return;
1539     }
1540 
1541     // Source target specified
1542     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1543     // Figure out which DBUS interface and property to use
1544     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr) !=
1545         0)
1546     {
1547         BMCWEB_LOG_DEBUG
1548             << "Invalid property value for BootSourceOverrideTarget: "
1549             << *bootSource;
1550         messages::propertyValueNotInList(aResp->res, *bootSource,
1551                                          "BootSourceTargetOverride");
1552         return;
1553     }
1554 
1555     // Act on validated parameters
1556     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1557     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1558 
1559     crow::connections::systemBus->async_method_call(
1560         [aResp](const boost::system::error_code ec) {
1561         if (ec)
1562         {
1563             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1564             messages::internalError(aResp->res);
1565             return;
1566         }
1567         BMCWEB_LOG_DEBUG << "Boot source update done.";
1568         },
1569         "xyz.openbmc_project.Settings",
1570         "/xyz/openbmc_project/control/host0/boot",
1571         "org.freedesktop.DBus.Properties", "Set",
1572         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1573         dbus::utility::DbusVariantType(bootSourceStr));
1574 
1575     crow::connections::systemBus->async_method_call(
1576         [aResp](const boost::system::error_code ec) {
1577         if (ec)
1578         {
1579             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1580             messages::internalError(aResp->res);
1581             return;
1582         }
1583         BMCWEB_LOG_DEBUG << "Boot mode update done.";
1584         },
1585         "xyz.openbmc_project.Settings",
1586         "/xyz/openbmc_project/control/host0/boot",
1587         "org.freedesktop.DBus.Properties", "Set",
1588         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1589         dbus::utility::DbusVariantType(bootModeStr));
1590 }
1591 
1592 /**
1593  * @brief Sets Boot source override properties.
1594  *
1595  * @param[in] aResp      Shared pointer for generating response message.
1596  * @param[in] bootSource The boot source from incoming RF request.
1597  * @param[in] bootType   The boot type from incoming RF request.
1598  * @param[in] bootEnable The boot override enable from incoming RF request.
1599  *
1600  * @return Integer error code.
1601  */
1602 
1603 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1604                               const std::optional<std::string>& bootSource,
1605                               const std::optional<std::string>& bootType,
1606                               const std::optional<std::string>& bootEnable)
1607 {
1608     BMCWEB_LOG_DEBUG << "Set boot information.";
1609 
1610     setBootModeOrSource(aResp, bootSource);
1611     setBootType(aResp, bootType);
1612     setBootEnable(aResp, bootEnable);
1613 }
1614 
1615 /**
1616  * @brief Sets AssetTag
1617  *
1618  * @param[in] aResp   Shared pointer for generating response message.
1619  * @param[in] assetTag  "AssetTag" from request.
1620  *
1621  * @return None.
1622  */
1623 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1624                         const std::string& assetTag)
1625 {
1626     crow::connections::systemBus->async_method_call(
1627         [aResp,
1628          assetTag](const boost::system::error_code ec,
1629                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
1630         if (ec)
1631         {
1632             BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1633             messages::internalError(aResp->res);
1634             return;
1635         }
1636         if (subtree.empty())
1637         {
1638             BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1639             messages::internalError(aResp->res);
1640             return;
1641         }
1642         // Assume only 1 system D-Bus object
1643         // Throw an error if there is more than 1
1644         if (subtree.size() > 1)
1645         {
1646             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1647             messages::internalError(aResp->res);
1648             return;
1649         }
1650         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1651         {
1652             BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1653             messages::internalError(aResp->res);
1654             return;
1655         }
1656 
1657         const std::string& path = subtree[0].first;
1658         const std::string& service = subtree[0].second.begin()->first;
1659 
1660         if (service.empty())
1661         {
1662             BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1663             messages::internalError(aResp->res);
1664             return;
1665         }
1666 
1667         crow::connections::systemBus->async_method_call(
1668             [aResp](const boost::system::error_code ec2) {
1669             if (ec2)
1670             {
1671                 BMCWEB_LOG_DEBUG << "D-Bus response error on AssetTag Set "
1672                                  << ec2;
1673                 messages::internalError(aResp->res);
1674                 return;
1675             }
1676             },
1677             service, path, "org.freedesktop.DBus.Properties", "Set",
1678             "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1679             dbus::utility::DbusVariantType(assetTag));
1680         },
1681         "xyz.openbmc_project.ObjectMapper",
1682         "/xyz/openbmc_project/object_mapper",
1683         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1684         "/xyz/openbmc_project/inventory", int32_t(0),
1685         std::array<const char*, 1>{
1686             "xyz.openbmc_project.Inventory.Item.System"});
1687 }
1688 
1689 /**
1690  * @brief Sets automaticRetry (Auto Reboot)
1691  *
1692  * @param[in] aResp   Shared pointer for generating response message.
1693  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1694  *
1695  * @return None.
1696  */
1697 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1698                               const std::string& automaticRetryConfig)
1699 {
1700     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1701 
1702     // OpenBMC only supports "Disabled" and "RetryAttempts".
1703     bool autoRebootEnabled = false;
1704 
1705     if (automaticRetryConfig == "Disabled")
1706     {
1707         autoRebootEnabled = false;
1708     }
1709     else if (automaticRetryConfig == "RetryAttempts")
1710     {
1711         autoRebootEnabled = true;
1712     }
1713     else
1714     {
1715         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: "
1716                          << automaticRetryConfig;
1717         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1718                                          "AutomaticRetryConfig");
1719         return;
1720     }
1721 
1722     crow::connections::systemBus->async_method_call(
1723         [aResp](const boost::system::error_code ec) {
1724         if (ec)
1725         {
1726             messages::internalError(aResp->res);
1727             return;
1728         }
1729         },
1730         "xyz.openbmc_project.Settings",
1731         "/xyz/openbmc_project/control/host0/auto_reboot",
1732         "org.freedesktop.DBus.Properties", "Set",
1733         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1734         dbus::utility::DbusVariantType(autoRebootEnabled));
1735 }
1736 
1737 /**
1738  * @brief Sets power restore policy properties.
1739  *
1740  * @param[in] aResp   Shared pointer for generating response message.
1741  * @param[in] policy  power restore policy properties from request.
1742  *
1743  * @return None.
1744  */
1745 inline void
1746     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1747                           const std::string& policy)
1748 {
1749     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1750 
1751     const boost::container::flat_map<std::string, std::string> policyMaps = {
1752         {"AlwaysOn",
1753          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"},
1754         {"AlwaysOff",
1755          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"},
1756         {"LastState",
1757          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}};
1758 
1759     std::string powerRestorPolicy;
1760 
1761     auto policyMapsIt = policyMaps.find(policy);
1762     if (policyMapsIt == policyMaps.end())
1763     {
1764         messages::propertyValueNotInList(aResp->res, policy,
1765                                          "PowerRestorePolicy");
1766         return;
1767     }
1768 
1769     powerRestorPolicy = policyMapsIt->second;
1770 
1771     crow::connections::systemBus->async_method_call(
1772         [aResp](const boost::system::error_code ec) {
1773         if (ec)
1774         {
1775             messages::internalError(aResp->res);
1776             return;
1777         }
1778         },
1779         "xyz.openbmc_project.Settings",
1780         "/xyz/openbmc_project/control/host0/power_restore_policy",
1781         "org.freedesktop.DBus.Properties", "Set",
1782         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1783         dbus::utility::DbusVariantType(powerRestorPolicy));
1784 }
1785 
1786 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1787 /**
1788  * @brief Retrieves provisioning status
1789  *
1790  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1791  *
1792  * @return None.
1793  */
1794 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1795 {
1796     BMCWEB_LOG_DEBUG << "Get OEM information.";
1797     crow::connections::systemBus->async_method_call(
1798         [aResp](const boost::system::error_code ec,
1799                 const dbus::utility::DBusPropertiesMap& propertiesList) {
1800         nlohmann::json& oemPFR =
1801             aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1802         aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1803             "#OemComputerSystem.OpenBmc";
1804         oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1805 
1806         if (ec)
1807         {
1808             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1809             // not an error, don't have to have the interface
1810             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1811             return;
1812         }
1813 
1814         const bool* provState = nullptr;
1815         const bool* lockState = nullptr;
1816         for (const std::pair<std::string, dbus::utility::DbusVariantType>&
1817                  property : propertiesList)
1818         {
1819             if (property.first == "UfmProvisioned")
1820             {
1821                 provState = std::get_if<bool>(&property.second);
1822             }
1823             else if (property.first == "UfmLocked")
1824             {
1825                 lockState = std::get_if<bool>(&property.second);
1826             }
1827         }
1828 
1829         if ((provState == nullptr) || (lockState == nullptr))
1830         {
1831             BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1832             messages::internalError(aResp->res);
1833             return;
1834         }
1835 
1836         if (*provState == true)
1837         {
1838             if (*lockState == true)
1839             {
1840                 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1841             }
1842             else
1843             {
1844                 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1845             }
1846         }
1847         else
1848         {
1849             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1850         }
1851         },
1852         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1853         "org.freedesktop.DBus.Properties", "GetAll",
1854         "xyz.openbmc_project.PFR.Attributes");
1855 }
1856 #endif
1857 
1858 /**
1859  * @brief Translate the PowerMode to a response message.
1860  *
1861  * @param[in] aResp  Shared pointer for generating response message.
1862  * @param[in] modeValue  PowerMode value to be translated
1863  *
1864  * @return None.
1865  */
1866 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1867                                const std::string& modeValue)
1868 {
1869     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
1870     {
1871         aResp->res.jsonValue["PowerMode"] = "Static";
1872     }
1873     else if (
1874         modeValue ==
1875         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
1876     {
1877         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
1878     }
1879     else if (modeValue ==
1880              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
1881     {
1882         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
1883     }
1884     else if (modeValue ==
1885              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
1886     {
1887         aResp->res.jsonValue["PowerMode"] = "OEM";
1888     }
1889     else
1890     {
1891         // Any other values would be invalid
1892         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
1893         messages::internalError(aResp->res);
1894     }
1895 }
1896 
1897 /**
1898  * @brief Retrieves system power mode
1899  *
1900  * @param[in] aResp  Shared pointer for generating response message.
1901  *
1902  * @return None.
1903  */
1904 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1905 {
1906     BMCWEB_LOG_DEBUG << "Get power mode.";
1907 
1908     // Get Power Mode object path:
1909     crow::connections::systemBus->async_method_call(
1910         [aResp](const boost::system::error_code ec,
1911                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1912         if (ec)
1913         {
1914             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
1915                              << ec;
1916             // This is an optional D-Bus object so just return if
1917             // error occurs
1918             return;
1919         }
1920         if (subtree.empty())
1921         {
1922             // As noted above, this is an optional interface so just return
1923             // if there is no instance found
1924             return;
1925         }
1926         if (subtree.size() > 1)
1927         {
1928             // More then one PowerMode object is not supported and is an
1929             // error
1930             BMCWEB_LOG_DEBUG
1931                 << "Found more than 1 system D-Bus Power.Mode objects: "
1932                 << subtree.size();
1933             messages::internalError(aResp->res);
1934             return;
1935         }
1936         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
1937         {
1938             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
1939             messages::internalError(aResp->res);
1940             return;
1941         }
1942         const std::string& path = subtree[0].first;
1943         const std::string& service = subtree[0].second.begin()->first;
1944         if (service.empty())
1945         {
1946             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
1947             messages::internalError(aResp->res);
1948             return;
1949         }
1950         // Valid Power Mode object found, now read the current value
1951         sdbusplus::asio::getProperty<std::string>(
1952             *crow::connections::systemBus, service, path,
1953             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
1954             [aResp](const boost::system::error_code ec2,
1955                     const std::string& pmode) {
1956             if (ec2)
1957             {
1958                 BMCWEB_LOG_DEBUG << "DBUS response error on PowerMode Get: "
1959                                  << ec2;
1960                 messages::internalError(aResp->res);
1961                 return;
1962             }
1963 
1964             aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = {
1965                 "Static", "MaximumPerformance", "PowerSaving"};
1966 
1967             BMCWEB_LOG_DEBUG << "Current power mode: " << pmode;
1968             translatePowerMode(aResp, pmode);
1969             });
1970         },
1971         "xyz.openbmc_project.ObjectMapper",
1972         "/xyz/openbmc_project/object_mapper",
1973         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1974         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
1975 }
1976 
1977 /**
1978  * @brief Validate the specified mode is valid and return the PowerMode
1979  * name associated with that string
1980  *
1981  * @param[in] aResp   Shared pointer for generating response message.
1982  * @param[in] modeString  String representing the desired PowerMode
1983  *
1984  * @return PowerMode value or empty string if mode is not valid
1985  */
1986 inline std::string
1987     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1988                       const std::string& modeString)
1989 {
1990     std::string mode;
1991 
1992     if (modeString == "Static")
1993     {
1994         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
1995     }
1996     else if (modeString == "MaximumPerformance")
1997     {
1998         mode =
1999             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2000     }
2001     else if (modeString == "PowerSaving")
2002     {
2003         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2004     }
2005     else
2006     {
2007         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2008     }
2009     return mode;
2010 }
2011 
2012 /**
2013  * @brief Sets system power mode.
2014  *
2015  * @param[in] aResp   Shared pointer for generating response message.
2016  * @param[in] pmode   System power mode from request.
2017  *
2018  * @return None.
2019  */
2020 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2021                          const std::string& pmode)
2022 {
2023     BMCWEB_LOG_DEBUG << "Set power mode.";
2024 
2025     std::string powerMode = validatePowerMode(aResp, pmode);
2026     if (powerMode.empty())
2027     {
2028         return;
2029     }
2030 
2031     // Get Power Mode object path:
2032     crow::connections::systemBus->async_method_call(
2033         [aResp,
2034          powerMode](const boost::system::error_code ec,
2035                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2036         if (ec)
2037         {
2038             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
2039                              << ec;
2040             // This is an optional D-Bus object, but user attempted to patch
2041             messages::internalError(aResp->res);
2042             return;
2043         }
2044         if (subtree.empty())
2045         {
2046             // This is an optional D-Bus object, but user attempted to patch
2047             messages::resourceNotFound(aResp->res, "ComputerSystem",
2048                                        "PowerMode");
2049             return;
2050         }
2051         if (subtree.size() > 1)
2052         {
2053             // More then one PowerMode object is not supported and is an
2054             // error
2055             BMCWEB_LOG_DEBUG
2056                 << "Found more than 1 system D-Bus Power.Mode objects: "
2057                 << subtree.size();
2058             messages::internalError(aResp->res);
2059             return;
2060         }
2061         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2062         {
2063             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2064             messages::internalError(aResp->res);
2065             return;
2066         }
2067         const std::string& path = subtree[0].first;
2068         const std::string& service = subtree[0].second.begin()->first;
2069         if (service.empty())
2070         {
2071             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2072             messages::internalError(aResp->res);
2073             return;
2074         }
2075 
2076         BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2077                          << path;
2078 
2079         // Set the Power Mode property
2080         crow::connections::systemBus->async_method_call(
2081             [aResp](const boost::system::error_code ec2) {
2082             if (ec2)
2083             {
2084                 messages::internalError(aResp->res);
2085                 return;
2086             }
2087             },
2088             service, path, "org.freedesktop.DBus.Properties", "Set",
2089             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2090             dbus::utility::DbusVariantType(powerMode));
2091         },
2092         "xyz.openbmc_project.ObjectMapper",
2093         "/xyz/openbmc_project/object_mapper",
2094         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2095         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2096 }
2097 
2098 /**
2099  * @brief Translates watchdog timeout action DBUS property value to redfish.
2100  *
2101  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2102  *
2103  * @return Returns as a string, the timeout action in Redfish terms. If
2104  * translation cannot be done, returns an empty string.
2105  */
2106 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2107 {
2108     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2109     {
2110         return "None";
2111     }
2112     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2113     {
2114         return "ResetSystem";
2115     }
2116     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2117     {
2118         return "PowerDown";
2119     }
2120     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2121     {
2122         return "PowerCycle";
2123     }
2124 
2125     return "";
2126 }
2127 
2128 /**
2129  *@brief Translates timeout action from Redfish to DBUS property value.
2130  *
2131  *@param[in] rfAction The timeout action in Redfish.
2132  *
2133  *@return Returns as a string, the time_out action as expected by DBUS.
2134  *If translation cannot be done, returns an empty string.
2135  */
2136 
2137 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2138 {
2139     if (rfAction == "None")
2140     {
2141         return "xyz.openbmc_project.State.Watchdog.Action.None";
2142     }
2143     if (rfAction == "PowerCycle")
2144     {
2145         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2146     }
2147     if (rfAction == "PowerDown")
2148     {
2149         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2150     }
2151     if (rfAction == "ResetSystem")
2152     {
2153         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2154     }
2155 
2156     return "";
2157 }
2158 
2159 /**
2160  * @brief Retrieves host watchdog timer properties over DBUS
2161  *
2162  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2163  *
2164  * @return None.
2165  */
2166 inline void
2167     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2168 {
2169     BMCWEB_LOG_DEBUG << "Get host watchodg";
2170     crow::connections::systemBus->async_method_call(
2171         [aResp](const boost::system::error_code ec,
2172                 const dbus::utility::DBusPropertiesMap& properties) {
2173         if (ec)
2174         {
2175             // watchdog service is stopped
2176             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2177             return;
2178         }
2179 
2180         BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2181 
2182         nlohmann::json& hostWatchdogTimer =
2183             aResp->res.jsonValue["HostWatchdogTimer"];
2184 
2185         // watchdog service is running/enabled
2186         hostWatchdogTimer["Status"]["State"] = "Enabled";
2187 
2188         for (const auto& property : properties)
2189         {
2190             BMCWEB_LOG_DEBUG << "prop=" << property.first;
2191             if (property.first == "Enabled")
2192             {
2193                 const bool* state = std::get_if<bool>(&property.second);
2194 
2195                 if (state == nullptr)
2196                 {
2197                     messages::internalError(aResp->res);
2198                     return;
2199                 }
2200 
2201                 hostWatchdogTimer["FunctionEnabled"] = *state;
2202             }
2203             else if (property.first == "ExpireAction")
2204             {
2205                 const std::string* s =
2206                     std::get_if<std::string>(&property.second);
2207                 if (s == nullptr)
2208                 {
2209                     messages::internalError(aResp->res);
2210                     return;
2211                 }
2212 
2213                 std::string action = dbusToRfWatchdogAction(*s);
2214                 if (action.empty())
2215                 {
2216                     messages::internalError(aResp->res);
2217                     return;
2218                 }
2219                 hostWatchdogTimer["TimeoutAction"] = action;
2220             }
2221         }
2222         },
2223         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2224         "org.freedesktop.DBus.Properties", "GetAll",
2225         "xyz.openbmc_project.State.Watchdog");
2226 }
2227 
2228 /**
2229  * @brief Sets Host WatchDog Timer properties.
2230  *
2231  * @param[in] aResp      Shared pointer for generating response message.
2232  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2233  *                       RF request.
2234  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2235  *
2236  * @return None.
2237  */
2238 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2239                              const std::optional<bool> wdtEnable,
2240                              const std::optional<std::string>& wdtTimeOutAction)
2241 {
2242     BMCWEB_LOG_DEBUG << "Set host watchdog";
2243 
2244     if (wdtTimeOutAction)
2245     {
2246         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2247         // check if TimeOut Action is Valid
2248         if (wdtTimeOutActStr.empty())
2249         {
2250             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2251                              << *wdtTimeOutAction;
2252             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2253                                              "TimeoutAction");
2254             return;
2255         }
2256 
2257         crow::connections::systemBus->async_method_call(
2258             [aResp](const boost::system::error_code ec) {
2259             if (ec)
2260             {
2261                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2262                 messages::internalError(aResp->res);
2263                 return;
2264             }
2265             },
2266             "xyz.openbmc_project.Watchdog",
2267             "/xyz/openbmc_project/watchdog/host0",
2268             "org.freedesktop.DBus.Properties", "Set",
2269             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2270             dbus::utility::DbusVariantType(wdtTimeOutActStr));
2271     }
2272 
2273     if (wdtEnable)
2274     {
2275         crow::connections::systemBus->async_method_call(
2276             [aResp](const boost::system::error_code ec) {
2277             if (ec)
2278             {
2279                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2280                 messages::internalError(aResp->res);
2281                 return;
2282             }
2283             },
2284             "xyz.openbmc_project.Watchdog",
2285             "/xyz/openbmc_project/watchdog/host0",
2286             "org.freedesktop.DBus.Properties", "Set",
2287             "xyz.openbmc_project.State.Watchdog", "Enabled",
2288             dbus::utility::DbusVariantType(*wdtEnable));
2289     }
2290 }
2291 
2292 /**
2293  * @brief Parse the Idle Power Saver properties into json
2294  *
2295  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2296  * @param[in] properties  IPS property data from DBus.
2297  *
2298  * @return true if successful
2299  */
2300 inline bool
2301     parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2302                        const dbus::utility::DBusPropertiesMap& properties)
2303 {
2304     for (const auto& property : properties)
2305     {
2306         if (property.first == "Enabled")
2307         {
2308             const bool* state = std::get_if<bool>(&property.second);
2309             if (state == nullptr)
2310             {
2311                 return false;
2312             }
2313             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state;
2314         }
2315         else if (property.first == "EnterUtilizationPercent")
2316         {
2317             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2318             if (util == nullptr)
2319             {
2320                 return false;
2321             }
2322             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2323         }
2324         else if (property.first == "EnterDwellTime")
2325         {
2326             // Convert Dbus time from milliseconds to seconds
2327             const uint64_t* timeMilliseconds =
2328                 std::get_if<uint64_t>(&property.second);
2329             if (timeMilliseconds == nullptr)
2330             {
2331                 return false;
2332             }
2333             const std::chrono::duration<uint64_t, std::milli> ms(
2334                 *timeMilliseconds);
2335             aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2336                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2337                     .count();
2338         }
2339         else if (property.first == "ExitUtilizationPercent")
2340         {
2341             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2342             if (util == nullptr)
2343             {
2344                 return false;
2345             }
2346             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2347         }
2348         else if (property.first == "ExitDwellTime")
2349         {
2350             // Convert Dbus time from milliseconds to seconds
2351             const uint64_t* timeMilliseconds =
2352                 std::get_if<uint64_t>(&property.second);
2353             if (timeMilliseconds == nullptr)
2354             {
2355                 return false;
2356             }
2357             const std::chrono::duration<uint64_t, std::milli> ms(
2358                 *timeMilliseconds);
2359             aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2360                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2361                     .count();
2362         }
2363         else
2364         {
2365             BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: "
2366                                << property.first;
2367         }
2368     }
2369 
2370     return true;
2371 }
2372 
2373 /**
2374  * @brief Retrieves host watchdog timer properties over DBUS
2375  *
2376  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2377  *
2378  * @return None.
2379  */
2380 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2381 {
2382     BMCWEB_LOG_DEBUG << "Get idle power saver parameters";
2383 
2384     // Get IdlePowerSaver object path:
2385     crow::connections::systemBus->async_method_call(
2386         [aResp](const boost::system::error_code ec,
2387                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2388         if (ec)
2389         {
2390             BMCWEB_LOG_DEBUG
2391                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2392                 << ec;
2393             messages::internalError(aResp->res);
2394             return;
2395         }
2396         if (subtree.empty())
2397         {
2398             // This is an optional interface so just return
2399             // if there is no instance found
2400             BMCWEB_LOG_DEBUG << "No instances found";
2401             return;
2402         }
2403         if (subtree.size() > 1)
2404         {
2405             // More then one PowerIdlePowerSaver object is not supported and
2406             // is an error
2407             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus "
2408                                 "Power.IdlePowerSaver objects: "
2409                              << subtree.size();
2410             messages::internalError(aResp->res);
2411             return;
2412         }
2413         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2414         {
2415             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2416             messages::internalError(aResp->res);
2417             return;
2418         }
2419         const std::string& path = subtree[0].first;
2420         const std::string& service = subtree[0].second.begin()->first;
2421         if (service.empty())
2422         {
2423             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2424             messages::internalError(aResp->res);
2425             return;
2426         }
2427 
2428         // Valid IdlePowerSaver object found, now read the current values
2429         crow::connections::systemBus->async_method_call(
2430             [aResp](const boost::system::error_code ec2,
2431                     const dbus::utility::DBusPropertiesMap& properties) {
2432             if (ec2)
2433             {
2434                 BMCWEB_LOG_ERROR
2435                     << "DBUS response error on IdlePowerSaver GetAll: " << ec2;
2436                 messages::internalError(aResp->res);
2437                 return;
2438             }
2439 
2440             if (!parseIpsProperties(aResp, properties))
2441             {
2442                 messages::internalError(aResp->res);
2443                 return;
2444             }
2445             },
2446             service, path, "org.freedesktop.DBus.Properties", "GetAll",
2447             "xyz.openbmc_project.Control.Power.IdlePowerSaver");
2448         },
2449         "xyz.openbmc_project.ObjectMapper",
2450         "/xyz/openbmc_project/object_mapper",
2451         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2452         std::array<const char*, 1>{
2453             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2454 
2455     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters";
2456 }
2457 
2458 /**
2459  * @brief Sets Idle Power Saver properties.
2460  *
2461  * @param[in] aResp      Shared pointer for generating response message.
2462  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2463  *                       RF request.
2464  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2465  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2466  * before entering idle state.
2467  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2468  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2469  * before exiting idle state
2470  *
2471  * @return None.
2472  */
2473 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2474                               const std::optional<bool> ipsEnable,
2475                               const std::optional<uint8_t> ipsEnterUtil,
2476                               const std::optional<uint64_t> ipsEnterTime,
2477                               const std::optional<uint8_t> ipsExitUtil,
2478                               const std::optional<uint64_t> ipsExitTime)
2479 {
2480     BMCWEB_LOG_DEBUG << "Set idle power saver properties";
2481 
2482     // Get IdlePowerSaver object path:
2483     crow::connections::systemBus->async_method_call(
2484         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2485          ipsExitTime](const boost::system::error_code ec,
2486                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
2487         if (ec)
2488         {
2489             BMCWEB_LOG_DEBUG
2490                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2491                 << ec;
2492             messages::internalError(aResp->res);
2493             return;
2494         }
2495         if (subtree.empty())
2496         {
2497             // This is an optional D-Bus object, but user attempted to patch
2498             messages::resourceNotFound(aResp->res, "ComputerSystem",
2499                                        "IdlePowerSaver");
2500             return;
2501         }
2502         if (subtree.size() > 1)
2503         {
2504             // More then one PowerIdlePowerSaver object is not supported and
2505             // is an error
2506             BMCWEB_LOG_DEBUG
2507                 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: "
2508                 << subtree.size();
2509             messages::internalError(aResp->res);
2510             return;
2511         }
2512         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2513         {
2514             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2515             messages::internalError(aResp->res);
2516             return;
2517         }
2518         const std::string& path = subtree[0].first;
2519         const std::string& service = subtree[0].second.begin()->first;
2520         if (service.empty())
2521         {
2522             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2523             messages::internalError(aResp->res);
2524             return;
2525         }
2526 
2527         // Valid Power IdlePowerSaver object found, now set any values that
2528         // need to be updated
2529 
2530         if (ipsEnable)
2531         {
2532             crow::connections::systemBus->async_method_call(
2533                 [aResp](const boost::system::error_code ec2) {
2534                 if (ec2)
2535                 {
2536                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2537                     messages::internalError(aResp->res);
2538                     return;
2539                 }
2540                 },
2541                 service, path, "org.freedesktop.DBus.Properties", "Set",
2542                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", "Enabled",
2543                 dbus::utility::DbusVariantType(*ipsEnable));
2544         }
2545         if (ipsEnterUtil)
2546         {
2547             crow::connections::systemBus->async_method_call(
2548                 [aResp](const boost::system::error_code ec2) {
2549                 if (ec2)
2550                 {
2551                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2552                     messages::internalError(aResp->res);
2553                     return;
2554                 }
2555                 },
2556                 service, path, "org.freedesktop.DBus.Properties", "Set",
2557                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2558                 "EnterUtilizationPercent",
2559                 dbus::utility::DbusVariantType(*ipsEnterUtil));
2560         }
2561         if (ipsEnterTime)
2562         {
2563             // Convert from seconds into milliseconds for DBus
2564             const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2565             crow::connections::systemBus->async_method_call(
2566                 [aResp](const boost::system::error_code ec2) {
2567                 if (ec2)
2568                 {
2569                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2570                     messages::internalError(aResp->res);
2571                     return;
2572                 }
2573                 },
2574                 service, path, "org.freedesktop.DBus.Properties", "Set",
2575                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2576                 "EnterDwellTime",
2577                 dbus::utility::DbusVariantType(timeMilliseconds));
2578         }
2579         if (ipsExitUtil)
2580         {
2581             crow::connections::systemBus->async_method_call(
2582                 [aResp](const boost::system::error_code ec2) {
2583                 if (ec2)
2584                 {
2585                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2586                     messages::internalError(aResp->res);
2587                     return;
2588                 }
2589                 },
2590                 service, path, "org.freedesktop.DBus.Properties", "Set",
2591                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2592                 "ExitUtilizationPercent",
2593                 dbus::utility::DbusVariantType(*ipsExitUtil));
2594         }
2595         if (ipsExitTime)
2596         {
2597             // Convert from seconds into milliseconds for DBus
2598             const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2599             crow::connections::systemBus->async_method_call(
2600                 [aResp](const boost::system::error_code ec2) {
2601                 if (ec2)
2602                 {
2603                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2604                     messages::internalError(aResp->res);
2605                     return;
2606                 }
2607                 },
2608                 service, path, "org.freedesktop.DBus.Properties", "Set",
2609                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2610                 "ExitDwellTime",
2611                 dbus::utility::DbusVariantType(timeMilliseconds));
2612         }
2613         },
2614         "xyz.openbmc_project.ObjectMapper",
2615         "/xyz/openbmc_project/object_mapper",
2616         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2617         std::array<const char*, 1>{
2618             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2619 
2620     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters";
2621 }
2622 
2623 /**
2624  * SystemsCollection derived class for delivering ComputerSystems Collection
2625  * Schema
2626  */
2627 inline void requestRoutesSystemsCollection(App& app)
2628 {
2629     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2630         .privileges(redfish::privileges::getComputerSystemCollection)
2631         .methods(boost::beast::http::verb::get)(
2632             [&app](const crow::Request& req,
2633                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2634         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2635         {
2636             return;
2637         }
2638         asyncResp->res.jsonValue["@odata.type"] =
2639             "#ComputerSystemCollection.ComputerSystemCollection";
2640         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2641         asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2642 
2643         sdbusplus::asio::getProperty<std::string>(
2644             *crow::connections::systemBus, "xyz.openbmc_project.Settings",
2645             "/xyz/openbmc_project/network/hypervisor",
2646             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
2647             [asyncResp](const boost::system::error_code ec2,
2648                         const std::string& /*hostName*/) {
2649             nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"];
2650             ifaceArray = nlohmann::json::array();
2651             auto& count = asyncResp->res.jsonValue["Members@odata.count"];
2652 
2653             nlohmann::json::object_t system;
2654             system["@odata.id"] = "/redfish/v1/Systems/system";
2655             ifaceArray.push_back(std::move(system));
2656             count = ifaceArray.size();
2657             if (!ec2)
2658             {
2659                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
2660                 nlohmann::json::object_t hypervisor;
2661                 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor";
2662                 ifaceArray.push_back(std::move(hypervisor));
2663                 count = ifaceArray.size();
2664             }
2665             });
2666         });
2667 }
2668 
2669 /**
2670  * Function transceives data with dbus directly.
2671  */
2672 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2673 {
2674     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2675     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2676     constexpr char const* interfaceName =
2677         "xyz.openbmc_project.Control.Host.NMI";
2678     constexpr char const* method = "NMI";
2679 
2680     crow::connections::systemBus->async_method_call(
2681         [asyncResp](const boost::system::error_code ec) {
2682         if (ec)
2683         {
2684             BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2685             messages::internalError(asyncResp->res);
2686             return;
2687         }
2688         messages::success(asyncResp->res);
2689         },
2690         serviceName, objectPath, interfaceName, method);
2691 }
2692 
2693 /**
2694  * SystemActionsReset class supports handle POST method for Reset action.
2695  * The class retrieves and sends data directly to D-Bus.
2696  */
2697 inline void requestRoutesSystemActionsReset(App& app)
2698 {
2699     /**
2700      * Function handles POST method request.
2701      * Analyzes POST body message before sends Reset request data to D-Bus.
2702      */
2703     BMCWEB_ROUTE(app,
2704                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2705         .privileges(redfish::privileges::postComputerSystem)
2706         .methods(boost::beast::http::verb::post)(
2707             [&app](const crow::Request& req,
2708                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2709         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2710         {
2711             return;
2712         }
2713         std::string resetType;
2714         if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
2715                                        resetType))
2716         {
2717             return;
2718         }
2719 
2720         // Get the command and host vs. chassis
2721         std::string command;
2722         bool hostCommand = true;
2723         if ((resetType == "On") || (resetType == "ForceOn"))
2724         {
2725             command = "xyz.openbmc_project.State.Host.Transition.On";
2726             hostCommand = true;
2727         }
2728         else if (resetType == "ForceOff")
2729         {
2730             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2731             hostCommand = false;
2732         }
2733         else if (resetType == "ForceRestart")
2734         {
2735             command =
2736                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2737             hostCommand = true;
2738         }
2739         else if (resetType == "GracefulShutdown")
2740         {
2741             command = "xyz.openbmc_project.State.Host.Transition.Off";
2742             hostCommand = true;
2743         }
2744         else if (resetType == "GracefulRestart")
2745         {
2746             command =
2747                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2748             hostCommand = true;
2749         }
2750         else if (resetType == "PowerCycle")
2751         {
2752             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2753             hostCommand = true;
2754         }
2755         else if (resetType == "Nmi")
2756         {
2757             doNMI(asyncResp);
2758             return;
2759         }
2760         else
2761         {
2762             messages::actionParameterUnknown(asyncResp->res, "Reset",
2763                                              resetType);
2764             return;
2765         }
2766 
2767         if (hostCommand)
2768         {
2769             crow::connections::systemBus->async_method_call(
2770                 [asyncResp, resetType](const boost::system::error_code ec) {
2771                 if (ec)
2772                 {
2773                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2774                     if (ec.value() == boost::asio::error::invalid_argument)
2775                     {
2776                         messages::actionParameterNotSupported(
2777                             asyncResp->res, resetType, "Reset");
2778                     }
2779                     else
2780                     {
2781                         messages::internalError(asyncResp->res);
2782                     }
2783                     return;
2784                 }
2785                 messages::success(asyncResp->res);
2786                 },
2787                 "xyz.openbmc_project.State.Host",
2788                 "/xyz/openbmc_project/state/host0",
2789                 "org.freedesktop.DBus.Properties", "Set",
2790                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2791                 dbus::utility::DbusVariantType{command});
2792         }
2793         else
2794         {
2795             crow::connections::systemBus->async_method_call(
2796                 [asyncResp, resetType](const boost::system::error_code ec) {
2797                 if (ec)
2798                 {
2799                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2800                     if (ec.value() == boost::asio::error::invalid_argument)
2801                     {
2802                         messages::actionParameterNotSupported(
2803                             asyncResp->res, resetType, "Reset");
2804                     }
2805                     else
2806                     {
2807                         messages::internalError(asyncResp->res);
2808                     }
2809                     return;
2810                 }
2811                 messages::success(asyncResp->res);
2812                 },
2813                 "xyz.openbmc_project.State.Chassis",
2814                 "/xyz/openbmc_project/state/chassis0",
2815                 "org.freedesktop.DBus.Properties", "Set",
2816                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2817                 dbus::utility::DbusVariantType{command});
2818         }
2819         });
2820 }
2821 
2822 /**
2823  * Systems derived class for delivering Computer Systems Schema.
2824  */
2825 inline void requestRoutesSystems(App& app)
2826 {
2827 
2828     /**
2829      * Functions triggers appropriate requests on DBus
2830      */
2831     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2832         .privileges(redfish::privileges::getComputerSystem)
2833         .methods(boost::beast::http::verb::get)(
2834             [&app](const crow::Request& req,
2835                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2836         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2837         {
2838             return;
2839         }
2840         asyncResp->res.jsonValue["@odata.type"] =
2841             "#ComputerSystem.v1_16_0.ComputerSystem";
2842         asyncResp->res.jsonValue["Name"] = "system";
2843         asyncResp->res.jsonValue["Id"] = "system";
2844         asyncResp->res.jsonValue["SystemType"] = "Physical";
2845         asyncResp->res.jsonValue["Description"] = "Computer System";
2846         asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2847         asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2848             "Disabled";
2849         asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2850             uint64_t(0);
2851         asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2852             "Disabled";
2853         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
2854 
2855         asyncResp->res.jsonValue["Processors"]["@odata.id"] =
2856             "/redfish/v1/Systems/system/Processors";
2857         asyncResp->res.jsonValue["Memory"]["@odata.id"] =
2858             "/redfish/v1/Systems/system/Memory";
2859         asyncResp->res.jsonValue["Storage"]["@odata.id"] =
2860             "/redfish/v1/Systems/system/Storage";
2861 
2862         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] =
2863             "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset";
2864         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]
2865                                 ["@Redfish.ActionInfo"] =
2866             "/redfish/v1/Systems/system/ResetActionInfo";
2867 
2868         asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2869             "/redfish/v1/Systems/system/LogServices";
2870         asyncResp->res.jsonValue["Bios"]["@odata.id"] =
2871             "/redfish/v1/Systems/system/Bios";
2872 
2873         nlohmann::json::array_t managedBy;
2874         nlohmann::json& manager = managedBy.emplace_back();
2875         manager["@odata.id"] = "/redfish/v1/Managers/bmc";
2876         asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
2877         asyncResp->res.jsonValue["Status"]["Health"] = "OK";
2878         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
2879 
2880         // Fill in SerialConsole info
2881         asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
2882         asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] =
2883             true;
2884 
2885         // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
2886         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] =
2887             true;
2888         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200;
2889         asyncResp->res
2890             .jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
2891             "Press ~. to exit console";
2892 
2893 #ifdef BMCWEB_ENABLE_KVM
2894         // Fill in GraphicalConsole info
2895         asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
2896         asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] =
2897             4;
2898         asyncResp->res
2899             .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = {"KVMIP"};
2900 
2901 #endif // BMCWEB_ENABLE_KVM
2902         constexpr const std::array<const char*, 4> inventoryForSystems = {
2903             "xyz.openbmc_project.Inventory.Item.Dimm",
2904             "xyz.openbmc_project.Inventory.Item.Cpu",
2905             "xyz.openbmc_project.Inventory.Item.Drive",
2906             "xyz.openbmc_project.Inventory.Item.StorageController"};
2907 
2908         auto health = std::make_shared<HealthPopulate>(asyncResp);
2909         crow::connections::systemBus->async_method_call(
2910             [health](const boost::system::error_code ec,
2911                      const std::vector<std::string>& resp) {
2912             if (ec)
2913             {
2914                 // no inventory
2915                 return;
2916             }
2917 
2918             health->inventory = resp;
2919             },
2920             "xyz.openbmc_project.ObjectMapper",
2921             "/xyz/openbmc_project/object_mapper",
2922             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2923             int32_t(0), inventoryForSystems);
2924 
2925         health->populate();
2926 
2927         getMainChassisId(asyncResp,
2928                          [](const std::string& chassisId,
2929                             const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
2930             nlohmann::json::array_t chassisArray;
2931             nlohmann::json& chassis = chassisArray.emplace_back();
2932             chassis["@odata.id"] = "/redfish/v1/Chassis/" + chassisId;
2933             aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray);
2934         });
2935 
2936         getLocationIndicatorActive(asyncResp);
2937         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2938         getIndicatorLedState(asyncResp);
2939         getComputerSystem(asyncResp, health);
2940         getHostState(asyncResp);
2941         getBootProperties(asyncResp);
2942         getBootProgress(asyncResp);
2943         getPCIeDeviceList(asyncResp, "PCIeDevices");
2944         getHostWatchdogTimer(asyncResp);
2945         getPowerRestorePolicy(asyncResp);
2946         getAutomaticRetry(asyncResp);
2947         getLastResetTime(asyncResp);
2948 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2949         getProvisioningStatus(asyncResp);
2950 #endif
2951         getTrustedModuleRequiredToBoot(asyncResp);
2952         getPowerMode(asyncResp);
2953         getIdlePowerSaver(asyncResp);
2954         });
2955 
2956     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2957         .privileges(redfish::privileges::patchComputerSystem)
2958         .methods(boost::beast::http::verb::patch)(
2959             [&app](const crow::Request& req,
2960                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2961         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2962         {
2963             return;
2964         }
2965         std::optional<bool> locationIndicatorActive;
2966         std::optional<std::string> indicatorLed;
2967         std::optional<std::string> assetTag;
2968         std::optional<std::string> powerRestorePolicy;
2969         std::optional<std::string> powerMode;
2970         std::optional<bool> wdtEnable;
2971         std::optional<std::string> wdtTimeOutAction;
2972         std::optional<std::string> bootSource;
2973         std::optional<std::string> bootType;
2974         std::optional<std::string> bootEnable;
2975         std::optional<std::string> bootAutomaticRetry;
2976         std::optional<bool> bootTrustedModuleRequired;
2977         std::optional<bool> ipsEnable;
2978         std::optional<uint8_t> ipsEnterUtil;
2979         std::optional<uint64_t> ipsEnterTime;
2980         std::optional<uint8_t> ipsExitUtil;
2981         std::optional<uint64_t> ipsExitTime;
2982 
2983         // clang-format off
2984         if (!json_util::readJsonPatch(
2985                 req, asyncResp->res,
2986                 "IndicatorLED", indicatorLed,
2987                 "LocationIndicatorActive", locationIndicatorActive,
2988                 "AssetTag", assetTag,
2989                 "PowerRestorePolicy", powerRestorePolicy,
2990                 "PowerMode", powerMode,
2991                 "HostWatchdogTimer/FunctionEnabled", wdtEnable,
2992                 "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,
2993                 "Boot/BootSourceOverrideTarget", bootSource,
2994                 "Boot/BootSourceOverrideMode", bootType,
2995                 "Boot/BootSourceOverrideEnabled", bootEnable,
2996                 "Boot/AutomaticRetryConfig", bootAutomaticRetry,
2997                 "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
2998                 "IdlePowerSaver/Enabled", ipsEnable,
2999                 "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
3000                 "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,
3001                 "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,
3002                 "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime))
3003         {
3004             return;
3005         }
3006         // clang-format on
3007 
3008         asyncResp->res.result(boost::beast::http::status::no_content);
3009 
3010         if (assetTag)
3011         {
3012             setAssetTag(asyncResp, *assetTag);
3013         }
3014 
3015         if (wdtEnable || wdtTimeOutAction)
3016         {
3017             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3018         }
3019 
3020         if (bootSource || bootType || bootEnable)
3021         {
3022             setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3023         }
3024         if (bootAutomaticRetry)
3025         {
3026             setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3027         }
3028 
3029         if (bootTrustedModuleRequired)
3030         {
3031             setTrustedModuleRequiredToBoot(asyncResp,
3032                                            *bootTrustedModuleRequired);
3033         }
3034 
3035         if (locationIndicatorActive)
3036         {
3037             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3038         }
3039 
3040         // TODO (Gunnar): Remove IndicatorLED after enough time has
3041         // passed
3042         if (indicatorLed)
3043         {
3044             setIndicatorLedState(asyncResp, *indicatorLed);
3045             asyncResp->res.addHeader(boost::beast::http::field::warning,
3046                                      "299 - \"IndicatorLED is deprecated. Use "
3047                                      "LocationIndicatorActive instead.\"");
3048         }
3049 
3050         if (powerRestorePolicy)
3051         {
3052             setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3053         }
3054 
3055         if (powerMode)
3056         {
3057             setPowerMode(asyncResp, *powerMode);
3058         }
3059 
3060         if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil ||
3061             ipsExitTime)
3062         {
3063             setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3064                               ipsExitUtil, ipsExitTime);
3065         }
3066         });
3067 }
3068 
3069 /**
3070  * SystemResetActionInfo derived class for delivering Computer Systems
3071  * ResetType AllowableValues using ResetInfo schema.
3072  */
3073 inline void requestRoutesSystemResetActionInfo(App& app)
3074 {
3075     /**
3076      * Functions triggers appropriate requests on DBus
3077      */
3078     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
3079         .privileges(redfish::privileges::getActionInfo)
3080         .methods(boost::beast::http::verb::get)(
3081             [&app](const crow::Request& req,
3082                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3083         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3084         {
3085             return;
3086         }
3087 
3088         asyncResp->res.jsonValue["@odata.id"] =
3089             "/redfish/v1/Systems/system/ResetActionInfo";
3090         asyncResp->res.jsonValue["@odata.type"] =
3091             "#ActionInfo.v1_1_2.ActionInfo";
3092         asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3093         asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3094 
3095         nlohmann::json::array_t parameters;
3096         nlohmann::json::object_t parameter;
3097 
3098         parameter["Name"] = "ResetType";
3099         parameter["Required"] = true;
3100         parameter["DataType"] = "String";
3101         nlohmann::json::array_t allowableValues;
3102         allowableValues.emplace_back("On");
3103         allowableValues.emplace_back("ForceOff");
3104         allowableValues.emplace_back("ForceOn");
3105         allowableValues.emplace_back("ForceRestart");
3106         allowableValues.emplace_back("GracefulRestart");
3107         allowableValues.emplace_back("GracefulShutdown");
3108         allowableValues.emplace_back("PowerCycle");
3109         allowableValues.emplace_back("Nmi");
3110         parameter["AllowableValues"] = std::move(allowableValues);
3111         parameters.emplace_back(std::move(parameter));
3112 
3113         asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3114         });
3115 }
3116 } // namespace redfish
3117