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