xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 1e5b7c8892238b5d17c269bfa0ecdaf60825e801)
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/json_utils.hpp>
31 #include <utils/sw_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     const 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     const 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 = *coreCountVal;
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                                     const uint64_t* preValue =
330                                         totalMemory.get_ptr<const 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                             sw_util::populateSoftwareInformation(
470                                 aResp, sw_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             if (ec.value() == boost::asio::error::host_unreachable)
934             {
935                 return;
936             }
937             messages::internalError(aResp->res);
938             return;
939         }
940 
941         BMCWEB_LOG_DEBUG << "Boot source: " << bootSourceStr;
942 
943         auto rfSource = dbusToRfBootSource(bootSourceStr);
944         if (!rfSource.empty())
945         {
946             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = rfSource;
947         }
948 
949         // Get BootMode as BootSourceOverrideTarget is constructed
950         // from both BootSource and BootMode
951         getBootOverrideMode(aResp);
952         });
953 }
954 
955 /**
956  * @brief This functions abstracts all the logic behind getting a
957  * "BootSourceOverrideEnabled" property from an overall boot override enable
958  * state
959  *
960  * @param[in] aResp     Shared pointer for generating response message.
961  *
962  * @return None.
963  */
964 
965 inline void
966     processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
967                               const bool bootOverrideEnableSetting)
968 {
969     if (!bootOverrideEnableSetting)
970     {
971         aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled";
972         return;
973     }
974 
975     // If boot source override is enabled, we need to check 'one_time'
976     // property to set a correct value for the "BootSourceOverrideEnabled"
977     sdbusplus::asio::getProperty<bool>(
978         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
979         "/xyz/openbmc_project/control/host0/boot/one_time",
980         "xyz.openbmc_project.Object.Enable", "Enabled",
981         [aResp](const boost::system::error_code ec, bool oneTimeSetting) {
982         if (ec)
983         {
984             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
985             messages::internalError(aResp->res);
986             return;
987         }
988 
989         if (oneTimeSetting)
990         {
991             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Once";
992         }
993         else
994         {
995             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
996                 "Continuous";
997         }
998         });
999 }
1000 
1001 /**
1002  * @brief Retrieves boot override enable over DBUS
1003  *
1004  * @param[in] aResp     Shared pointer for generating response message.
1005  *
1006  * @return None.
1007  */
1008 
1009 inline void
1010     getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1011 {
1012     sdbusplus::asio::getProperty<bool>(
1013         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1014         "/xyz/openbmc_project/control/host0/boot",
1015         "xyz.openbmc_project.Object.Enable", "Enabled",
1016         [aResp](const boost::system::error_code ec,
1017                 const bool bootOverrideEnable) {
1018         if (ec)
1019         {
1020             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1021             if (ec.value() == boost::asio::error::host_unreachable)
1022             {
1023                 return;
1024             }
1025             messages::internalError(aResp->res);
1026             return;
1027         }
1028 
1029         processBootOverrideEnable(aResp, bootOverrideEnable);
1030         });
1031 }
1032 
1033 /**
1034  * @brief Retrieves boot source override properties
1035  *
1036  * @param[in] aResp     Shared pointer for generating response message.
1037  *
1038  * @return None.
1039  */
1040 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1041 {
1042     BMCWEB_LOG_DEBUG << "Get boot information.";
1043 
1044     getBootOverrideSource(aResp);
1045     getBootOverrideType(aResp);
1046     getBootOverrideEnable(aResp);
1047 }
1048 
1049 /**
1050  * @brief Retrieves the Last Reset Time
1051  *
1052  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1053  * and power off. Even though this is the "system" Redfish object look at the
1054  * chassis D-Bus interface for the LastStateChangeTime since this has the
1055  * last power operation time.
1056  *
1057  * @param[in] aResp     Shared pointer for generating response message.
1058  *
1059  * @return None.
1060  */
1061 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1062 {
1063     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1064 
1065     sdbusplus::asio::getProperty<uint64_t>(
1066         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1067         "/xyz/openbmc_project/state/chassis0",
1068         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime",
1069         [aResp](const boost::system::error_code ec, uint64_t lastResetTime) {
1070         if (ec)
1071         {
1072             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1073             return;
1074         }
1075 
1076         // LastStateChangeTime is epoch time, in milliseconds
1077         // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1078         uint64_t lastResetTimeStamp = lastResetTime / 1000;
1079 
1080         // Convert to ISO 8601 standard
1081         aResp->res.jsonValue["LastResetTime"] =
1082             crow::utility::getDateTimeUint(lastResetTimeStamp);
1083         });
1084 }
1085 
1086 /**
1087  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1088  *
1089  * @param[in] aResp     Shared pointer for generating response message.
1090  *
1091  * @return None.
1092  */
1093 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1094 {
1095     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1096 
1097     sdbusplus::asio::getProperty<bool>(
1098         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1099         "/xyz/openbmc_project/control/host0/auto_reboot",
1100         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1101         [aResp](const boost::system::error_code ec, bool autoRebootEnabled) {
1102         if (ec)
1103         {
1104             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1105             return;
1106         }
1107 
1108         BMCWEB_LOG_DEBUG << "Auto Reboot: " << autoRebootEnabled;
1109         if (autoRebootEnabled)
1110         {
1111             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1112                 "RetryAttempts";
1113             // If AutomaticRetry (AutoReboot) is enabled see how many
1114             // attempts are left
1115             sdbusplus::asio::getProperty<uint32_t>(
1116                 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
1117                 "/xyz/openbmc_project/state/host0",
1118                 "xyz.openbmc_project.Control.Boot.RebootAttempts",
1119                 "AttemptsLeft",
1120                 [aResp](const boost::system::error_code ec2,
1121                         const uint32_t autoRebootAttemptsLeft) {
1122                 if (ec2)
1123                 {
1124                     BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1125                     return;
1126                 }
1127 
1128                 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1129                                  << autoRebootAttemptsLeft;
1130 
1131                 aResp->res
1132                     .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
1133                     autoRebootAttemptsLeft;
1134                 });
1135         }
1136         else
1137         {
1138             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled";
1139         }
1140 
1141         // Not on D-Bus. Hardcoded here:
1142         // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1143         aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1144 
1145         // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1146         // and RetryAttempts. OpenBMC only supports Disabled and
1147         // RetryAttempts.
1148         aResp->res.jsonValue["Boot"]
1149                             ["AutomaticRetryConfig@Redfish.AllowableValues"] = {
1150             "Disabled", "RetryAttempts"};
1151         });
1152 }
1153 
1154 /**
1155  * @brief Retrieves power restore policy over DBUS.
1156  *
1157  * @param[in] aResp     Shared pointer for generating response message.
1158  *
1159  * @return None.
1160  */
1161 inline void
1162     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1163 {
1164     BMCWEB_LOG_DEBUG << "Get power restore policy";
1165 
1166     sdbusplus::asio::getProperty<std::string>(
1167         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1168         "/xyz/openbmc_project/control/host0/power_restore_policy",
1169         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1170         [aResp](const boost::system::error_code ec, const std::string& policy) {
1171         if (ec)
1172         {
1173             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1174             return;
1175         }
1176 
1177         const boost::container::flat_map<std::string, std::string> policyMaps = {
1178             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
1179              "AlwaysOn"},
1180             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
1181              "AlwaysOff"},
1182             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
1183              "LastState"},
1184             // Return `AlwaysOff` when power restore policy set to "None"
1185             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None",
1186              "AlwaysOff"}};
1187 
1188         auto policyMapsIt = policyMaps.find(policy);
1189         if (policyMapsIt == policyMaps.end())
1190         {
1191             messages::internalError(aResp->res);
1192             return;
1193         }
1194 
1195         aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1196         });
1197 }
1198 
1199 /**
1200  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1201  * TPM is required for booting the host.
1202  *
1203  * @param[in] aResp     Shared pointer for generating response message.
1204  *
1205  * @return None.
1206  */
1207 inline void getTrustedModuleRequiredToBoot(
1208     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1209 {
1210     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1211 
1212     crow::connections::systemBus->async_method_call(
1213         [aResp](const boost::system::error_code ec,
1214                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1215         if (ec)
1216         {
1217             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1218                              << ec;
1219             // This is an optional D-Bus object so just return if
1220             // error occurs
1221             return;
1222         }
1223         if (subtree.empty())
1224         {
1225             // As noted above, this is an optional interface so just return
1226             // if there is no instance found
1227             return;
1228         }
1229 
1230         /* When there is more than one TPMEnable object... */
1231         if (subtree.size() > 1)
1232         {
1233             BMCWEB_LOG_DEBUG
1234                 << "DBUS response has more than 1 TPM Enable object:"
1235                 << subtree.size();
1236             // Throw an internal Error and return
1237             messages::internalError(aResp->res);
1238             return;
1239         }
1240 
1241         // Make sure the Dbus response map has a service and objectPath
1242         // field
1243         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1244         {
1245             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1246             messages::internalError(aResp->res);
1247             return;
1248         }
1249 
1250         const std::string& path = subtree[0].first;
1251         const std::string& serv = subtree[0].second.begin()->first;
1252 
1253         // Valid TPM Enable object found, now reading the current value
1254         sdbusplus::asio::getProperty<bool>(
1255             *crow::connections::systemBus, serv, path,
1256             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1257             [aResp](const boost::system::error_code ec2, bool tpmRequired) {
1258             if (ec2)
1259             {
1260                 BMCWEB_LOG_DEBUG << "D-BUS response error on TPM.Policy Get"
1261                                  << ec2;
1262                 messages::internalError(aResp->res);
1263                 return;
1264             }
1265 
1266             if (tpmRequired)
1267             {
1268                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1269                     "Required";
1270             }
1271             else
1272             {
1273                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1274                     "Disabled";
1275             }
1276             });
1277         },
1278         "xyz.openbmc_project.ObjectMapper",
1279         "/xyz/openbmc_project/object_mapper",
1280         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1281         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1282 }
1283 
1284 /**
1285  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1286  * TPM is required for booting the host.
1287  *
1288  * @param[in] aResp         Shared pointer for generating response message.
1289  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1290  *
1291  * @return None.
1292  */
1293 inline void setTrustedModuleRequiredToBoot(
1294     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1295 {
1296     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1297 
1298     crow::connections::systemBus->async_method_call(
1299         [aResp, tpmRequired](const boost::system::error_code ec,
1300                              dbus::utility::MapperGetSubTreeResponse& subtree) {
1301         if (ec)
1302         {
1303             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1304                              << ec;
1305             messages::internalError(aResp->res);
1306             return;
1307         }
1308         if (subtree.empty())
1309         {
1310             messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1311                                              "TrustedModuleRequiredToBoot");
1312             return;
1313         }
1314 
1315         /* When there is more than one TPMEnable object... */
1316         if (subtree.size() > 1)
1317         {
1318             BMCWEB_LOG_DEBUG
1319                 << "DBUS response has more than 1 TPM Enable object:"
1320                 << subtree.size();
1321             // Throw an internal Error and return
1322             messages::internalError(aResp->res);
1323             return;
1324         }
1325 
1326         // Make sure the Dbus response map has a service and objectPath
1327         // field
1328         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1329         {
1330             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1331             messages::internalError(aResp->res);
1332             return;
1333         }
1334 
1335         const std::string& path = subtree[0].first;
1336         const std::string& serv = subtree[0].second.begin()->first;
1337 
1338         if (serv.empty())
1339         {
1340             BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1341             messages::internalError(aResp->res);
1342             return;
1343         }
1344 
1345         // Valid TPM Enable object found, now setting the value
1346         crow::connections::systemBus->async_method_call(
1347             [aResp](const boost::system::error_code ec2) {
1348             if (ec2)
1349             {
1350                 BMCWEB_LOG_DEBUG
1351                     << "DBUS response error: Set TrustedModuleRequiredToBoot"
1352                     << ec2;
1353                 messages::internalError(aResp->res);
1354                 return;
1355             }
1356             BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1357             },
1358             serv, path, "org.freedesktop.DBus.Properties", "Set",
1359             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1360             dbus::utility::DbusVariantType(tpmRequired));
1361         },
1362         "xyz.openbmc_project.ObjectMapper",
1363         "/xyz/openbmc_project/object_mapper",
1364         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1365         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1366 }
1367 
1368 /**
1369  * @brief Sets boot properties into DBUS object(s).
1370  *
1371  * @param[in] aResp           Shared pointer for generating response message.
1372  * @param[in] bootType        The boot type to set.
1373  * @return Integer error code.
1374  */
1375 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1376                         const std::optional<std::string>& bootType)
1377 {
1378     std::string bootTypeStr;
1379 
1380     if (!bootType)
1381     {
1382         return;
1383     }
1384 
1385     // Source target specified
1386     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1387     // Figure out which DBUS interface and property to use
1388     if (*bootType == "Legacy")
1389     {
1390         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1391     }
1392     else if (*bootType == "UEFI")
1393     {
1394         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1395     }
1396     else
1397     {
1398         BMCWEB_LOG_DEBUG << "Invalid property value for "
1399                             "BootSourceOverrideMode: "
1400                          << *bootType;
1401         messages::propertyValueNotInList(aResp->res, *bootType,
1402                                          "BootSourceOverrideMode");
1403         return;
1404     }
1405 
1406     // Act on validated parameters
1407     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1408 
1409     crow::connections::systemBus->async_method_call(
1410         [aResp](const boost::system::error_code ec) {
1411         if (ec)
1412         {
1413             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1414             if (ec.value() == boost::asio::error::host_unreachable)
1415             {
1416                 messages::resourceNotFound(aResp->res, "Set", "BootType");
1417                 return;
1418             }
1419             messages::internalError(aResp->res);
1420             return;
1421         }
1422         BMCWEB_LOG_DEBUG << "Boot type update done.";
1423         },
1424         "xyz.openbmc_project.Settings",
1425         "/xyz/openbmc_project/control/host0/boot",
1426         "org.freedesktop.DBus.Properties", "Set",
1427         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1428         dbus::utility::DbusVariantType(bootTypeStr));
1429 }
1430 
1431 /**
1432  * @brief Sets boot properties into DBUS object(s).
1433  *
1434  * @param[in] aResp           Shared pointer for generating response message.
1435  * @param[in] bootType        The boot type to set.
1436  * @return Integer error code.
1437  */
1438 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1439                           const std::optional<std::string>& bootEnable)
1440 {
1441     if (!bootEnable)
1442     {
1443         return;
1444     }
1445     // Source target specified
1446     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1447 
1448     bool bootOverrideEnable = false;
1449     bool bootOverridePersistent = false;
1450     // Figure out which DBUS interface and property to use
1451     if (*bootEnable == "Disabled")
1452     {
1453         bootOverrideEnable = false;
1454     }
1455     else if (*bootEnable == "Once")
1456     {
1457         bootOverrideEnable = true;
1458         bootOverridePersistent = false;
1459     }
1460     else if (*bootEnable == "Continuous")
1461     {
1462         bootOverrideEnable = true;
1463         bootOverridePersistent = true;
1464     }
1465     else
1466     {
1467         BMCWEB_LOG_DEBUG
1468             << "Invalid property value for BootSourceOverrideEnabled: "
1469             << *bootEnable;
1470         messages::propertyValueNotInList(aResp->res, *bootEnable,
1471                                          "BootSourceOverrideEnabled");
1472         return;
1473     }
1474 
1475     // Act on validated parameters
1476     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1477 
1478     crow::connections::systemBus->async_method_call(
1479         [aResp](const boost::system::error_code ec2) {
1480         if (ec2)
1481         {
1482             BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
1483             messages::internalError(aResp->res);
1484             return;
1485         }
1486         BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1487         },
1488         "xyz.openbmc_project.Settings",
1489         "/xyz/openbmc_project/control/host0/boot",
1490         "org.freedesktop.DBus.Properties", "Set",
1491         "xyz.openbmc_project.Object.Enable", "Enabled",
1492         dbus::utility::DbusVariantType(bootOverrideEnable));
1493 
1494     if (!bootOverrideEnable)
1495     {
1496         return;
1497     }
1498 
1499     // In case boot override is enabled we need to set correct value for the
1500     // 'one_time' enable DBus interface
1501     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1502                      << bootOverridePersistent;
1503 
1504     crow::connections::systemBus->async_method_call(
1505         [aResp](const boost::system::error_code ec) {
1506         if (ec)
1507         {
1508             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1509             messages::internalError(aResp->res);
1510             return;
1511         }
1512         BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1513         },
1514         "xyz.openbmc_project.Settings",
1515         "/xyz/openbmc_project/control/host0/boot/one_time",
1516         "org.freedesktop.DBus.Properties", "Set",
1517         "xyz.openbmc_project.Object.Enable", "Enabled",
1518         dbus::utility::DbusVariantType(!bootOverridePersistent));
1519 }
1520 
1521 /**
1522  * @brief Sets boot properties into DBUS object(s).
1523  *
1524  * @param[in] aResp           Shared pointer for generating response message.
1525  * @param[in] bootSource      The boot source to set.
1526  *
1527  * @return Integer error code.
1528  */
1529 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1530                                 const std::optional<std::string>& bootSource)
1531 {
1532     std::string bootSourceStr;
1533     std::string bootModeStr;
1534 
1535     if (!bootSource)
1536     {
1537         return;
1538     }
1539 
1540     // Source target specified
1541     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1542     // Figure out which DBUS interface and property to use
1543     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr) !=
1544         0)
1545     {
1546         BMCWEB_LOG_DEBUG
1547             << "Invalid property value for BootSourceOverrideTarget: "
1548             << *bootSource;
1549         messages::propertyValueNotInList(aResp->res, *bootSource,
1550                                          "BootSourceTargetOverride");
1551         return;
1552     }
1553 
1554     // Act on validated parameters
1555     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1556     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1557 
1558     crow::connections::systemBus->async_method_call(
1559         [aResp](const boost::system::error_code ec) {
1560         if (ec)
1561         {
1562             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1563             messages::internalError(aResp->res);
1564             return;
1565         }
1566         BMCWEB_LOG_DEBUG << "Boot source update done.";
1567         },
1568         "xyz.openbmc_project.Settings",
1569         "/xyz/openbmc_project/control/host0/boot",
1570         "org.freedesktop.DBus.Properties", "Set",
1571         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1572         dbus::utility::DbusVariantType(bootSourceStr));
1573 
1574     crow::connections::systemBus->async_method_call(
1575         [aResp](const boost::system::error_code ec) {
1576         if (ec)
1577         {
1578             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1579             messages::internalError(aResp->res);
1580             return;
1581         }
1582         BMCWEB_LOG_DEBUG << "Boot mode update done.";
1583         },
1584         "xyz.openbmc_project.Settings",
1585         "/xyz/openbmc_project/control/host0/boot",
1586         "org.freedesktop.DBus.Properties", "Set",
1587         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1588         dbus::utility::DbusVariantType(bootModeStr));
1589 }
1590 
1591 /**
1592  * @brief Sets Boot source override properties.
1593  *
1594  * @param[in] aResp      Shared pointer for generating response message.
1595  * @param[in] bootSource The boot source from incoming RF request.
1596  * @param[in] bootType   The boot type from incoming RF request.
1597  * @param[in] bootEnable The boot override enable from incoming RF request.
1598  *
1599  * @return Integer error code.
1600  */
1601 
1602 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1603                               const std::optional<std::string>& bootSource,
1604                               const std::optional<std::string>& bootType,
1605                               const std::optional<std::string>& bootEnable)
1606 {
1607     BMCWEB_LOG_DEBUG << "Set boot information.";
1608 
1609     setBootModeOrSource(aResp, bootSource);
1610     setBootType(aResp, bootType);
1611     setBootEnable(aResp, bootEnable);
1612 }
1613 
1614 /**
1615  * @brief Sets AssetTag
1616  *
1617  * @param[in] aResp   Shared pointer for generating response message.
1618  * @param[in] assetTag  "AssetTag" from request.
1619  *
1620  * @return None.
1621  */
1622 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1623                         const std::string& assetTag)
1624 {
1625     crow::connections::systemBus->async_method_call(
1626         [aResp,
1627          assetTag](const boost::system::error_code ec,
1628                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
1629         if (ec)
1630         {
1631             BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1632             messages::internalError(aResp->res);
1633             return;
1634         }
1635         if (subtree.empty())
1636         {
1637             BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1638             messages::internalError(aResp->res);
1639             return;
1640         }
1641         // Assume only 1 system D-Bus object
1642         // Throw an error if there is more than 1
1643         if (subtree.size() > 1)
1644         {
1645             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1646             messages::internalError(aResp->res);
1647             return;
1648         }
1649         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1650         {
1651             BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1652             messages::internalError(aResp->res);
1653             return;
1654         }
1655 
1656         const std::string& path = subtree[0].first;
1657         const std::string& service = subtree[0].second.begin()->first;
1658 
1659         if (service.empty())
1660         {
1661             BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1662             messages::internalError(aResp->res);
1663             return;
1664         }
1665 
1666         crow::connections::systemBus->async_method_call(
1667             [aResp](const boost::system::error_code ec2) {
1668             if (ec2)
1669             {
1670                 BMCWEB_LOG_DEBUG << "D-Bus response error on AssetTag Set "
1671                                  << ec2;
1672                 messages::internalError(aResp->res);
1673                 return;
1674             }
1675             },
1676             service, path, "org.freedesktop.DBus.Properties", "Set",
1677             "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1678             dbus::utility::DbusVariantType(assetTag));
1679         },
1680         "xyz.openbmc_project.ObjectMapper",
1681         "/xyz/openbmc_project/object_mapper",
1682         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1683         "/xyz/openbmc_project/inventory", int32_t(0),
1684         std::array<const char*, 1>{
1685             "xyz.openbmc_project.Inventory.Item.System"});
1686 }
1687 
1688 /**
1689  * @brief Sets automaticRetry (Auto Reboot)
1690  *
1691  * @param[in] aResp   Shared pointer for generating response message.
1692  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1693  *
1694  * @return None.
1695  */
1696 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1697                               const std::string& automaticRetryConfig)
1698 {
1699     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1700 
1701     // OpenBMC only supports "Disabled" and "RetryAttempts".
1702     bool autoRebootEnabled = false;
1703 
1704     if (automaticRetryConfig == "Disabled")
1705     {
1706         autoRebootEnabled = false;
1707     }
1708     else if (automaticRetryConfig == "RetryAttempts")
1709     {
1710         autoRebootEnabled = true;
1711     }
1712     else
1713     {
1714         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: "
1715                          << automaticRetryConfig;
1716         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1717                                          "AutomaticRetryConfig");
1718         return;
1719     }
1720 
1721     crow::connections::systemBus->async_method_call(
1722         [aResp](const boost::system::error_code ec) {
1723         if (ec)
1724         {
1725             messages::internalError(aResp->res);
1726             return;
1727         }
1728         },
1729         "xyz.openbmc_project.Settings",
1730         "/xyz/openbmc_project/control/host0/auto_reboot",
1731         "org.freedesktop.DBus.Properties", "Set",
1732         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1733         dbus::utility::DbusVariantType(autoRebootEnabled));
1734 }
1735 
1736 /**
1737  * @brief Sets power restore policy properties.
1738  *
1739  * @param[in] aResp   Shared pointer for generating response message.
1740  * @param[in] policy  power restore policy properties from request.
1741  *
1742  * @return None.
1743  */
1744 inline void
1745     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1746                           const std::string& policy)
1747 {
1748     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1749 
1750     const boost::container::flat_map<std::string, std::string> policyMaps = {
1751         {"AlwaysOn",
1752          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"},
1753         {"AlwaysOff",
1754          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"},
1755         {"LastState",
1756          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}};
1757 
1758     std::string powerRestorPolicy;
1759 
1760     auto policyMapsIt = policyMaps.find(policy);
1761     if (policyMapsIt == policyMaps.end())
1762     {
1763         messages::propertyValueNotInList(aResp->res, policy,
1764                                          "PowerRestorePolicy");
1765         return;
1766     }
1767 
1768     powerRestorPolicy = policyMapsIt->second;
1769 
1770     crow::connections::systemBus->async_method_call(
1771         [aResp](const boost::system::error_code ec) {
1772         if (ec)
1773         {
1774             messages::internalError(aResp->res);
1775             return;
1776         }
1777         },
1778         "xyz.openbmc_project.Settings",
1779         "/xyz/openbmc_project/control/host0/power_restore_policy",
1780         "org.freedesktop.DBus.Properties", "Set",
1781         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1782         dbus::utility::DbusVariantType(powerRestorPolicy));
1783 }
1784 
1785 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1786 /**
1787  * @brief Retrieves provisioning status
1788  *
1789  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1790  *
1791  * @return None.
1792  */
1793 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1794 {
1795     BMCWEB_LOG_DEBUG << "Get OEM information.";
1796     crow::connections::systemBus->async_method_call(
1797         [aResp](const boost::system::error_code ec,
1798                 const dbus::utility::DBusPropertiesMap& propertiesList) {
1799         nlohmann::json& oemPFR =
1800             aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1801         aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1802             "#OemComputerSystem.OpenBmc";
1803         oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1804 
1805         if (ec)
1806         {
1807             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1808             // not an error, don't have to have the interface
1809             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1810             return;
1811         }
1812 
1813         const bool* provState = nullptr;
1814         const bool* lockState = nullptr;
1815         for (const std::pair<std::string, dbus::utility::DbusVariantType>&
1816                  property : propertiesList)
1817         {
1818             if (property.first == "UfmProvisioned")
1819             {
1820                 provState = std::get_if<bool>(&property.second);
1821             }
1822             else if (property.first == "UfmLocked")
1823             {
1824                 lockState = std::get_if<bool>(&property.second);
1825             }
1826         }
1827 
1828         if ((provState == nullptr) || (lockState == nullptr))
1829         {
1830             BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1831             messages::internalError(aResp->res);
1832             return;
1833         }
1834 
1835         if (*provState == true)
1836         {
1837             if (*lockState == true)
1838             {
1839                 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1840             }
1841             else
1842             {
1843                 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1844             }
1845         }
1846         else
1847         {
1848             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1849         }
1850         },
1851         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1852         "org.freedesktop.DBus.Properties", "GetAll",
1853         "xyz.openbmc_project.PFR.Attributes");
1854 }
1855 #endif
1856 
1857 /**
1858  * @brief Translate the PowerMode to a response message.
1859  *
1860  * @param[in] aResp  Shared pointer for generating response message.
1861  * @param[in] modeValue  PowerMode value to be translated
1862  *
1863  * @return None.
1864  */
1865 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1866                                const std::string& modeValue)
1867 {
1868     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
1869     {
1870         aResp->res.jsonValue["PowerMode"] = "Static";
1871     }
1872     else if (
1873         modeValue ==
1874         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
1875     {
1876         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
1877     }
1878     else if (modeValue ==
1879              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
1880     {
1881         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
1882     }
1883     else if (modeValue ==
1884              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
1885     {
1886         aResp->res.jsonValue["PowerMode"] = "OEM";
1887     }
1888     else
1889     {
1890         // Any other values would be invalid
1891         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
1892         messages::internalError(aResp->res);
1893     }
1894 }
1895 
1896 /**
1897  * @brief Retrieves system power mode
1898  *
1899  * @param[in] aResp  Shared pointer for generating response message.
1900  *
1901  * @return None.
1902  */
1903 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1904 {
1905     BMCWEB_LOG_DEBUG << "Get power mode.";
1906 
1907     // Get Power Mode object path:
1908     crow::connections::systemBus->async_method_call(
1909         [aResp](const boost::system::error_code ec,
1910                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1911         if (ec)
1912         {
1913             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
1914                              << ec;
1915             // This is an optional D-Bus object so just return if
1916             // error occurs
1917             return;
1918         }
1919         if (subtree.empty())
1920         {
1921             // As noted above, this is an optional interface so just return
1922             // if there is no instance found
1923             return;
1924         }
1925         if (subtree.size() > 1)
1926         {
1927             // More then one PowerMode object is not supported and is an
1928             // error
1929             BMCWEB_LOG_DEBUG
1930                 << "Found more than 1 system D-Bus Power.Mode objects: "
1931                 << subtree.size();
1932             messages::internalError(aResp->res);
1933             return;
1934         }
1935         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
1936         {
1937             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
1938             messages::internalError(aResp->res);
1939             return;
1940         }
1941         const std::string& path = subtree[0].first;
1942         const std::string& service = subtree[0].second.begin()->first;
1943         if (service.empty())
1944         {
1945             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
1946             messages::internalError(aResp->res);
1947             return;
1948         }
1949         // Valid Power Mode object found, now read the current value
1950         sdbusplus::asio::getProperty<std::string>(
1951             *crow::connections::systemBus, service, path,
1952             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
1953             [aResp](const boost::system::error_code ec2,
1954                     const std::string& pmode) {
1955             if (ec2)
1956             {
1957                 BMCWEB_LOG_DEBUG << "DBUS response error on PowerMode Get: "
1958                                  << ec2;
1959                 messages::internalError(aResp->res);
1960                 return;
1961             }
1962 
1963             aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = {
1964                 "Static", "MaximumPerformance", "PowerSaving"};
1965 
1966             BMCWEB_LOG_DEBUG << "Current power mode: " << pmode;
1967             translatePowerMode(aResp, pmode);
1968             });
1969         },
1970         "xyz.openbmc_project.ObjectMapper",
1971         "/xyz/openbmc_project/object_mapper",
1972         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1973         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
1974 }
1975 
1976 /**
1977  * @brief Validate the specified mode is valid and return the PowerMode
1978  * name associated with that string
1979  *
1980  * @param[in] aResp   Shared pointer for generating response message.
1981  * @param[in] modeString  String representing the desired PowerMode
1982  *
1983  * @return PowerMode value or empty string if mode is not valid
1984  */
1985 inline std::string
1986     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1987                       const std::string& modeString)
1988 {
1989     std::string mode;
1990 
1991     if (modeString == "Static")
1992     {
1993         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
1994     }
1995     else if (modeString == "MaximumPerformance")
1996     {
1997         mode =
1998             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
1999     }
2000     else if (modeString == "PowerSaving")
2001     {
2002         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2003     }
2004     else
2005     {
2006         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2007     }
2008     return mode;
2009 }
2010 
2011 /**
2012  * @brief Sets system power mode.
2013  *
2014  * @param[in] aResp   Shared pointer for generating response message.
2015  * @param[in] pmode   System power mode from request.
2016  *
2017  * @return None.
2018  */
2019 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2020                          const std::string& pmode)
2021 {
2022     BMCWEB_LOG_DEBUG << "Set power mode.";
2023 
2024     std::string powerMode = validatePowerMode(aResp, pmode);
2025     if (powerMode.empty())
2026     {
2027         return;
2028     }
2029 
2030     // Get Power Mode object path:
2031     crow::connections::systemBus->async_method_call(
2032         [aResp,
2033          powerMode](const boost::system::error_code ec,
2034                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2035         if (ec)
2036         {
2037             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
2038                              << ec;
2039             // This is an optional D-Bus object, but user attempted to patch
2040             messages::internalError(aResp->res);
2041             return;
2042         }
2043         if (subtree.empty())
2044         {
2045             // This is an optional D-Bus object, but user attempted to patch
2046             messages::resourceNotFound(aResp->res, "ComputerSystem",
2047                                        "PowerMode");
2048             return;
2049         }
2050         if (subtree.size() > 1)
2051         {
2052             // More then one PowerMode object is not supported and is an
2053             // error
2054             BMCWEB_LOG_DEBUG
2055                 << "Found more than 1 system D-Bus Power.Mode objects: "
2056                 << subtree.size();
2057             messages::internalError(aResp->res);
2058             return;
2059         }
2060         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2061         {
2062             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2063             messages::internalError(aResp->res);
2064             return;
2065         }
2066         const std::string& path = subtree[0].first;
2067         const std::string& service = subtree[0].second.begin()->first;
2068         if (service.empty())
2069         {
2070             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2071             messages::internalError(aResp->res);
2072             return;
2073         }
2074 
2075         BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2076                          << path;
2077 
2078         // Set the Power Mode property
2079         crow::connections::systemBus->async_method_call(
2080             [aResp](const boost::system::error_code ec2) {
2081             if (ec2)
2082             {
2083                 messages::internalError(aResp->res);
2084                 return;
2085             }
2086             },
2087             service, path, "org.freedesktop.DBus.Properties", "Set",
2088             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2089             dbus::utility::DbusVariantType(powerMode));
2090         },
2091         "xyz.openbmc_project.ObjectMapper",
2092         "/xyz/openbmc_project/object_mapper",
2093         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2094         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2095 }
2096 
2097 /**
2098  * @brief Translates watchdog timeout action DBUS property value to redfish.
2099  *
2100  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2101  *
2102  * @return Returns as a string, the timeout action in Redfish terms. If
2103  * translation cannot be done, returns an empty string.
2104  */
2105 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2106 {
2107     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2108     {
2109         return "None";
2110     }
2111     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2112     {
2113         return "ResetSystem";
2114     }
2115     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2116     {
2117         return "PowerDown";
2118     }
2119     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2120     {
2121         return "PowerCycle";
2122     }
2123 
2124     return "";
2125 }
2126 
2127 /**
2128  *@brief Translates timeout action from Redfish to DBUS property value.
2129  *
2130  *@param[in] rfAction The timeout action in Redfish.
2131  *
2132  *@return Returns as a string, the time_out action as expected by DBUS.
2133  *If translation cannot be done, returns an empty string.
2134  */
2135 
2136 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2137 {
2138     if (rfAction == "None")
2139     {
2140         return "xyz.openbmc_project.State.Watchdog.Action.None";
2141     }
2142     if (rfAction == "PowerCycle")
2143     {
2144         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2145     }
2146     if (rfAction == "PowerDown")
2147     {
2148         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2149     }
2150     if (rfAction == "ResetSystem")
2151     {
2152         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2153     }
2154 
2155     return "";
2156 }
2157 
2158 /**
2159  * @brief Retrieves host watchdog timer properties over DBUS
2160  *
2161  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2162  *
2163  * @return None.
2164  */
2165 inline void
2166     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2167 {
2168     BMCWEB_LOG_DEBUG << "Get host watchodg";
2169     crow::connections::systemBus->async_method_call(
2170         [aResp](const boost::system::error_code ec,
2171                 const dbus::utility::DBusPropertiesMap& properties) {
2172         if (ec)
2173         {
2174             // watchdog service is stopped
2175             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2176             return;
2177         }
2178 
2179         BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2180 
2181         nlohmann::json& hostWatchdogTimer =
2182             aResp->res.jsonValue["HostWatchdogTimer"];
2183 
2184         // watchdog service is running/enabled
2185         hostWatchdogTimer["Status"]["State"] = "Enabled";
2186 
2187         for (const auto& property : properties)
2188         {
2189             BMCWEB_LOG_DEBUG << "prop=" << property.first;
2190             if (property.first == "Enabled")
2191             {
2192                 const bool* state = std::get_if<bool>(&property.second);
2193 
2194                 if (state == nullptr)
2195                 {
2196                     messages::internalError(aResp->res);
2197                     return;
2198                 }
2199 
2200                 hostWatchdogTimer["FunctionEnabled"] = *state;
2201             }
2202             else if (property.first == "ExpireAction")
2203             {
2204                 const std::string* s =
2205                     std::get_if<std::string>(&property.second);
2206                 if (s == nullptr)
2207                 {
2208                     messages::internalError(aResp->res);
2209                     return;
2210                 }
2211 
2212                 std::string action = dbusToRfWatchdogAction(*s);
2213                 if (action.empty())
2214                 {
2215                     messages::internalError(aResp->res);
2216                     return;
2217                 }
2218                 hostWatchdogTimer["TimeoutAction"] = action;
2219             }
2220         }
2221         },
2222         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2223         "org.freedesktop.DBus.Properties", "GetAll",
2224         "xyz.openbmc_project.State.Watchdog");
2225 }
2226 
2227 /**
2228  * @brief Sets Host WatchDog Timer properties.
2229  *
2230  * @param[in] aResp      Shared pointer for generating response message.
2231  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2232  *                       RF request.
2233  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2234  *
2235  * @return None.
2236  */
2237 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2238                              const std::optional<bool> wdtEnable,
2239                              const std::optional<std::string>& wdtTimeOutAction)
2240 {
2241     BMCWEB_LOG_DEBUG << "Set host watchdog";
2242 
2243     if (wdtTimeOutAction)
2244     {
2245         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2246         // check if TimeOut Action is Valid
2247         if (wdtTimeOutActStr.empty())
2248         {
2249             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2250                              << *wdtTimeOutAction;
2251             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2252                                              "TimeoutAction");
2253             return;
2254         }
2255 
2256         crow::connections::systemBus->async_method_call(
2257             [aResp](const boost::system::error_code ec) {
2258             if (ec)
2259             {
2260                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2261                 messages::internalError(aResp->res);
2262                 return;
2263             }
2264             },
2265             "xyz.openbmc_project.Watchdog",
2266             "/xyz/openbmc_project/watchdog/host0",
2267             "org.freedesktop.DBus.Properties", "Set",
2268             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2269             dbus::utility::DbusVariantType(wdtTimeOutActStr));
2270     }
2271 
2272     if (wdtEnable)
2273     {
2274         crow::connections::systemBus->async_method_call(
2275             [aResp](const boost::system::error_code ec) {
2276             if (ec)
2277             {
2278                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2279                 messages::internalError(aResp->res);
2280                 return;
2281             }
2282             },
2283             "xyz.openbmc_project.Watchdog",
2284             "/xyz/openbmc_project/watchdog/host0",
2285             "org.freedesktop.DBus.Properties", "Set",
2286             "xyz.openbmc_project.State.Watchdog", "Enabled",
2287             dbus::utility::DbusVariantType(*wdtEnable));
2288     }
2289 }
2290 
2291 /**
2292  * @brief Parse the Idle Power Saver properties into json
2293  *
2294  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2295  * @param[in] properties  IPS property data from DBus.
2296  *
2297  * @return true if successful
2298  */
2299 inline bool
2300     parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2301                        const dbus::utility::DBusPropertiesMap& properties)
2302 {
2303     for (const auto& property : properties)
2304     {
2305         if (property.first == "Enabled")
2306         {
2307             const bool* state = std::get_if<bool>(&property.second);
2308             if (state == nullptr)
2309             {
2310                 return false;
2311             }
2312             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state;
2313         }
2314         else if (property.first == "EnterUtilizationPercent")
2315         {
2316             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2317             if (util == nullptr)
2318             {
2319                 return false;
2320             }
2321             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2322         }
2323         else if (property.first == "EnterDwellTime")
2324         {
2325             // Convert Dbus time from milliseconds to seconds
2326             const uint64_t* timeMilliseconds =
2327                 std::get_if<uint64_t>(&property.second);
2328             if (timeMilliseconds == nullptr)
2329             {
2330                 return false;
2331             }
2332             const std::chrono::duration<uint64_t, std::milli> ms(
2333                 *timeMilliseconds);
2334             aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2335                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2336                     .count();
2337         }
2338         else if (property.first == "ExitUtilizationPercent")
2339         {
2340             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2341             if (util == nullptr)
2342             {
2343                 return false;
2344             }
2345             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2346         }
2347         else if (property.first == "ExitDwellTime")
2348         {
2349             // Convert Dbus time from milliseconds to seconds
2350             const uint64_t* timeMilliseconds =
2351                 std::get_if<uint64_t>(&property.second);
2352             if (timeMilliseconds == nullptr)
2353             {
2354                 return false;
2355             }
2356             const std::chrono::duration<uint64_t, std::milli> ms(
2357                 *timeMilliseconds);
2358             aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2359                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2360                     .count();
2361         }
2362         else
2363         {
2364             BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: "
2365                                << property.first;
2366         }
2367     }
2368 
2369     return true;
2370 }
2371 
2372 /**
2373  * @brief Retrieves host watchdog timer properties over DBUS
2374  *
2375  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2376  *
2377  * @return None.
2378  */
2379 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2380 {
2381     BMCWEB_LOG_DEBUG << "Get idle power saver parameters";
2382 
2383     // Get IdlePowerSaver object path:
2384     crow::connections::systemBus->async_method_call(
2385         [aResp](const boost::system::error_code ec,
2386                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2387         if (ec)
2388         {
2389             BMCWEB_LOG_DEBUG
2390                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2391                 << ec;
2392             messages::internalError(aResp->res);
2393             return;
2394         }
2395         if (subtree.empty())
2396         {
2397             // This is an optional interface so just return
2398             // if there is no instance found
2399             BMCWEB_LOG_DEBUG << "No instances found";
2400             return;
2401         }
2402         if (subtree.size() > 1)
2403         {
2404             // More then one PowerIdlePowerSaver object is not supported and
2405             // is an error
2406             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus "
2407                                 "Power.IdlePowerSaver objects: "
2408                              << subtree.size();
2409             messages::internalError(aResp->res);
2410             return;
2411         }
2412         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2413         {
2414             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2415             messages::internalError(aResp->res);
2416             return;
2417         }
2418         const std::string& path = subtree[0].first;
2419         const std::string& service = subtree[0].second.begin()->first;
2420         if (service.empty())
2421         {
2422             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2423             messages::internalError(aResp->res);
2424             return;
2425         }
2426 
2427         // Valid IdlePowerSaver object found, now read the current values
2428         crow::connections::systemBus->async_method_call(
2429             [aResp](const boost::system::error_code ec2,
2430                     const dbus::utility::DBusPropertiesMap& properties) {
2431             if (ec2)
2432             {
2433                 BMCWEB_LOG_ERROR
2434                     << "DBUS response error on IdlePowerSaver GetAll: " << ec2;
2435                 messages::internalError(aResp->res);
2436                 return;
2437             }
2438 
2439             if (!parseIpsProperties(aResp, properties))
2440             {
2441                 messages::internalError(aResp->res);
2442                 return;
2443             }
2444             },
2445             service, path, "org.freedesktop.DBus.Properties", "GetAll",
2446             "xyz.openbmc_project.Control.Power.IdlePowerSaver");
2447         },
2448         "xyz.openbmc_project.ObjectMapper",
2449         "/xyz/openbmc_project/object_mapper",
2450         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2451         std::array<const char*, 1>{
2452             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2453 
2454     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters";
2455 }
2456 
2457 /**
2458  * @brief Sets Idle Power Saver properties.
2459  *
2460  * @param[in] aResp      Shared pointer for generating response message.
2461  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2462  *                       RF request.
2463  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2464  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2465  * before entering idle state.
2466  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2467  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2468  * before exiting idle state
2469  *
2470  * @return None.
2471  */
2472 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2473                               const std::optional<bool> ipsEnable,
2474                               const std::optional<uint8_t> ipsEnterUtil,
2475                               const std::optional<uint64_t> ipsEnterTime,
2476                               const std::optional<uint8_t> ipsExitUtil,
2477                               const std::optional<uint64_t> ipsExitTime)
2478 {
2479     BMCWEB_LOG_DEBUG << "Set idle power saver properties";
2480 
2481     // Get IdlePowerSaver object path:
2482     crow::connections::systemBus->async_method_call(
2483         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2484          ipsExitTime](const boost::system::error_code ec,
2485                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
2486         if (ec)
2487         {
2488             BMCWEB_LOG_DEBUG
2489                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2490                 << ec;
2491             messages::internalError(aResp->res);
2492             return;
2493         }
2494         if (subtree.empty())
2495         {
2496             // This is an optional D-Bus object, but user attempted to patch
2497             messages::resourceNotFound(aResp->res, "ComputerSystem",
2498                                        "IdlePowerSaver");
2499             return;
2500         }
2501         if (subtree.size() > 1)
2502         {
2503             // More then one PowerIdlePowerSaver object is not supported and
2504             // is an error
2505             BMCWEB_LOG_DEBUG
2506                 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: "
2507                 << subtree.size();
2508             messages::internalError(aResp->res);
2509             return;
2510         }
2511         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2512         {
2513             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2514             messages::internalError(aResp->res);
2515             return;
2516         }
2517         const std::string& path = subtree[0].first;
2518         const std::string& service = subtree[0].second.begin()->first;
2519         if (service.empty())
2520         {
2521             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2522             messages::internalError(aResp->res);
2523             return;
2524         }
2525 
2526         // Valid Power IdlePowerSaver object found, now set any values that
2527         // need to be updated
2528 
2529         if (ipsEnable)
2530         {
2531             crow::connections::systemBus->async_method_call(
2532                 [aResp](const boost::system::error_code ec2) {
2533                 if (ec2)
2534                 {
2535                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2536                     messages::internalError(aResp->res);
2537                     return;
2538                 }
2539                 },
2540                 service, path, "org.freedesktop.DBus.Properties", "Set",
2541                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", "Enabled",
2542                 dbus::utility::DbusVariantType(*ipsEnable));
2543         }
2544         if (ipsEnterUtil)
2545         {
2546             crow::connections::systemBus->async_method_call(
2547                 [aResp](const boost::system::error_code ec2) {
2548                 if (ec2)
2549                 {
2550                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2551                     messages::internalError(aResp->res);
2552                     return;
2553                 }
2554                 },
2555                 service, path, "org.freedesktop.DBus.Properties", "Set",
2556                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2557                 "EnterUtilizationPercent",
2558                 dbus::utility::DbusVariantType(*ipsEnterUtil));
2559         }
2560         if (ipsEnterTime)
2561         {
2562             // Convert from seconds into milliseconds for DBus
2563             const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2564             crow::connections::systemBus->async_method_call(
2565                 [aResp](const boost::system::error_code ec2) {
2566                 if (ec2)
2567                 {
2568                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2569                     messages::internalError(aResp->res);
2570                     return;
2571                 }
2572                 },
2573                 service, path, "org.freedesktop.DBus.Properties", "Set",
2574                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2575                 "EnterDwellTime",
2576                 dbus::utility::DbusVariantType(timeMilliseconds));
2577         }
2578         if (ipsExitUtil)
2579         {
2580             crow::connections::systemBus->async_method_call(
2581                 [aResp](const boost::system::error_code ec2) {
2582                 if (ec2)
2583                 {
2584                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2585                     messages::internalError(aResp->res);
2586                     return;
2587                 }
2588                 },
2589                 service, path, "org.freedesktop.DBus.Properties", "Set",
2590                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2591                 "ExitUtilizationPercent",
2592                 dbus::utility::DbusVariantType(*ipsExitUtil));
2593         }
2594         if (ipsExitTime)
2595         {
2596             // Convert from seconds into milliseconds for DBus
2597             const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2598             crow::connections::systemBus->async_method_call(
2599                 [aResp](const boost::system::error_code ec2) {
2600                 if (ec2)
2601                 {
2602                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2603                     messages::internalError(aResp->res);
2604                     return;
2605                 }
2606                 },
2607                 service, path, "org.freedesktop.DBus.Properties", "Set",
2608                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2609                 "ExitDwellTime",
2610                 dbus::utility::DbusVariantType(timeMilliseconds));
2611         }
2612         },
2613         "xyz.openbmc_project.ObjectMapper",
2614         "/xyz/openbmc_project/object_mapper",
2615         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2616         std::array<const char*, 1>{
2617             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2618 
2619     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters";
2620 }
2621 
2622 /**
2623  * SystemsCollection derived class for delivering ComputerSystems Collection
2624  * Schema
2625  */
2626 inline void requestRoutesSystemsCollection(App& app)
2627 {
2628     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2629         .privileges(redfish::privileges::getComputerSystemCollection)
2630         .methods(boost::beast::http::verb::get)(
2631             [&app](const crow::Request& req,
2632                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2633         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2634         {
2635             return;
2636         }
2637         asyncResp->res.jsonValue["@odata.type"] =
2638             "#ComputerSystemCollection.ComputerSystemCollection";
2639         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2640         asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2641 
2642         sdbusplus::asio::getProperty<std::string>(
2643             *crow::connections::systemBus, "xyz.openbmc_project.Settings",
2644             "/xyz/openbmc_project/network/hypervisor",
2645             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
2646             [asyncResp](const boost::system::error_code ec2,
2647                         const std::string& /*hostName*/) {
2648             nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"];
2649             ifaceArray = nlohmann::json::array();
2650             auto& count = asyncResp->res.jsonValue["Members@odata.count"];
2651 
2652             nlohmann::json::object_t system;
2653             system["@odata.id"] = "/redfish/v1/Systems/system";
2654             ifaceArray.push_back(std::move(system));
2655             count = ifaceArray.size();
2656             if (!ec2)
2657             {
2658                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
2659                 nlohmann::json::object_t hypervisor;
2660                 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor";
2661                 ifaceArray.push_back(std::move(hypervisor));
2662                 count = ifaceArray.size();
2663             }
2664             });
2665         });
2666 }
2667 
2668 /**
2669  * Function transceives data with dbus directly.
2670  */
2671 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2672 {
2673     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2674     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2675     constexpr char const* interfaceName =
2676         "xyz.openbmc_project.Control.Host.NMI";
2677     constexpr char const* method = "NMI";
2678 
2679     crow::connections::systemBus->async_method_call(
2680         [asyncResp](const boost::system::error_code ec) {
2681         if (ec)
2682         {
2683             BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2684             messages::internalError(asyncResp->res);
2685             return;
2686         }
2687         messages::success(asyncResp->res);
2688         },
2689         serviceName, objectPath, interfaceName, method);
2690 }
2691 
2692 /**
2693  * SystemActionsReset class supports handle POST method for Reset action.
2694  * The class retrieves and sends data directly to D-Bus.
2695  */
2696 inline void requestRoutesSystemActionsReset(App& app)
2697 {
2698     /**
2699      * Function handles POST method request.
2700      * Analyzes POST body message before sends Reset request data to D-Bus.
2701      */
2702     BMCWEB_ROUTE(app,
2703                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2704         .privileges(redfish::privileges::postComputerSystem)
2705         .methods(boost::beast::http::verb::post)(
2706             [&app](const crow::Request& req,
2707                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2708         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2709         {
2710             return;
2711         }
2712         std::string resetType;
2713         if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
2714                                        resetType))
2715         {
2716             return;
2717         }
2718 
2719         // Get the command and host vs. chassis
2720         std::string command;
2721         bool hostCommand = true;
2722         if ((resetType == "On") || (resetType == "ForceOn"))
2723         {
2724             command = "xyz.openbmc_project.State.Host.Transition.On";
2725             hostCommand = true;
2726         }
2727         else if (resetType == "ForceOff")
2728         {
2729             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2730             hostCommand = false;
2731         }
2732         else if (resetType == "ForceRestart")
2733         {
2734             command =
2735                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2736             hostCommand = true;
2737         }
2738         else if (resetType == "GracefulShutdown")
2739         {
2740             command = "xyz.openbmc_project.State.Host.Transition.Off";
2741             hostCommand = true;
2742         }
2743         else if (resetType == "GracefulRestart")
2744         {
2745             command =
2746                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2747             hostCommand = true;
2748         }
2749         else if (resetType == "PowerCycle")
2750         {
2751             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2752             hostCommand = true;
2753         }
2754         else if (resetType == "Nmi")
2755         {
2756             doNMI(asyncResp);
2757             return;
2758         }
2759         else
2760         {
2761             messages::actionParameterUnknown(asyncResp->res, "Reset",
2762                                              resetType);
2763             return;
2764         }
2765 
2766         if (hostCommand)
2767         {
2768             crow::connections::systemBus->async_method_call(
2769                 [asyncResp, resetType](const boost::system::error_code ec) {
2770                 if (ec)
2771                 {
2772                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2773                     if (ec.value() == boost::asio::error::invalid_argument)
2774                     {
2775                         messages::actionParameterNotSupported(
2776                             asyncResp->res, resetType, "Reset");
2777                     }
2778                     else
2779                     {
2780                         messages::internalError(asyncResp->res);
2781                     }
2782                     return;
2783                 }
2784                 messages::success(asyncResp->res);
2785                 },
2786                 "xyz.openbmc_project.State.Host",
2787                 "/xyz/openbmc_project/state/host0",
2788                 "org.freedesktop.DBus.Properties", "Set",
2789                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2790                 dbus::utility::DbusVariantType{command});
2791         }
2792         else
2793         {
2794             crow::connections::systemBus->async_method_call(
2795                 [asyncResp, resetType](const boost::system::error_code ec) {
2796                 if (ec)
2797                 {
2798                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2799                     if (ec.value() == boost::asio::error::invalid_argument)
2800                     {
2801                         messages::actionParameterNotSupported(
2802                             asyncResp->res, resetType, "Reset");
2803                     }
2804                     else
2805                     {
2806                         messages::internalError(asyncResp->res);
2807                     }
2808                     return;
2809                 }
2810                 messages::success(asyncResp->res);
2811                 },
2812                 "xyz.openbmc_project.State.Chassis",
2813                 "/xyz/openbmc_project/state/chassis0",
2814                 "org.freedesktop.DBus.Properties", "Set",
2815                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2816                 dbus::utility::DbusVariantType{command});
2817         }
2818         });
2819 }
2820 
2821 /**
2822  * Systems derived class for delivering Computer Systems Schema.
2823  */
2824 inline void requestRoutesSystems(App& app)
2825 {
2826 
2827     /**
2828      * Functions triggers appropriate requests on DBus
2829      */
2830     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2831         .privileges(redfish::privileges::getComputerSystem)
2832         .methods(boost::beast::http::verb::get)(
2833             [&app](const crow::Request& req,
2834                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2835         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2836         {
2837             return;
2838         }
2839         asyncResp->res.jsonValue["@odata.type"] =
2840             "#ComputerSystem.v1_16_0.ComputerSystem";
2841         asyncResp->res.jsonValue["Name"] = "system";
2842         asyncResp->res.jsonValue["Id"] = "system";
2843         asyncResp->res.jsonValue["SystemType"] = "Physical";
2844         asyncResp->res.jsonValue["Description"] = "Computer System";
2845         asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2846         asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2847             "Disabled";
2848         asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2849             uint64_t(0);
2850         asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2851             "Disabled";
2852         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
2853 
2854         asyncResp->res.jsonValue["Processors"]["@odata.id"] =
2855             "/redfish/v1/Systems/system/Processors";
2856         asyncResp->res.jsonValue["Memory"]["@odata.id"] =
2857             "/redfish/v1/Systems/system/Memory";
2858         asyncResp->res.jsonValue["Storage"]["@odata.id"] =
2859             "/redfish/v1/Systems/system/Storage";
2860 
2861         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] =
2862             "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset";
2863         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]
2864                                 ["@Redfish.ActionInfo"] =
2865             "/redfish/v1/Systems/system/ResetActionInfo";
2866 
2867         asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2868             "/redfish/v1/Systems/system/LogServices";
2869         asyncResp->res.jsonValue["Bios"]["@odata.id"] =
2870             "/redfish/v1/Systems/system/Bios";
2871 
2872         nlohmann::json::array_t managedBy;
2873         nlohmann::json& manager = managedBy.emplace_back();
2874         manager["@odata.id"] = "/redfish/v1/Managers/bmc";
2875         asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
2876         asyncResp->res.jsonValue["Status"]["Health"] = "OK";
2877         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
2878 
2879         // Fill in SerialConsole info
2880         asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
2881         asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] =
2882             true;
2883 
2884         // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
2885         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] =
2886             true;
2887         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200;
2888         asyncResp->res
2889             .jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
2890             "Press ~. to exit console";
2891 
2892 #ifdef BMCWEB_ENABLE_KVM
2893         // Fill in GraphicalConsole info
2894         asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
2895         asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] =
2896             4;
2897         asyncResp->res
2898             .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = {"KVMIP"};
2899 
2900 #endif // BMCWEB_ENABLE_KVM
2901         constexpr const std::array<const char*, 4> inventoryForSystems = {
2902             "xyz.openbmc_project.Inventory.Item.Dimm",
2903             "xyz.openbmc_project.Inventory.Item.Cpu",
2904             "xyz.openbmc_project.Inventory.Item.Drive",
2905             "xyz.openbmc_project.Inventory.Item.StorageController"};
2906 
2907         auto health = std::make_shared<HealthPopulate>(asyncResp);
2908         crow::connections::systemBus->async_method_call(
2909             [health](const boost::system::error_code ec,
2910                      const std::vector<std::string>& resp) {
2911             if (ec)
2912             {
2913                 // no inventory
2914                 return;
2915             }
2916 
2917             health->inventory = resp;
2918             },
2919             "xyz.openbmc_project.ObjectMapper",
2920             "/xyz/openbmc_project/object_mapper",
2921             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2922             int32_t(0), inventoryForSystems);
2923 
2924         health->populate();
2925 
2926         getMainChassisId(asyncResp,
2927                          [](const std::string& chassisId,
2928                             const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
2929             nlohmann::json::array_t chassisArray;
2930             nlohmann::json& chassis = chassisArray.emplace_back();
2931             chassis["@odata.id"] = "/redfish/v1/Chassis/" + chassisId;
2932             aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray);
2933         });
2934 
2935         getLocationIndicatorActive(asyncResp);
2936         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2937         getIndicatorLedState(asyncResp);
2938         getComputerSystem(asyncResp, health);
2939         getHostState(asyncResp);
2940         getBootProperties(asyncResp);
2941         getBootProgress(asyncResp);
2942         getPCIeDeviceList(asyncResp, "PCIeDevices");
2943         getHostWatchdogTimer(asyncResp);
2944         getPowerRestorePolicy(asyncResp);
2945         getAutomaticRetry(asyncResp);
2946         getLastResetTime(asyncResp);
2947 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2948         getProvisioningStatus(asyncResp);
2949 #endif
2950         getTrustedModuleRequiredToBoot(asyncResp);
2951         getPowerMode(asyncResp);
2952         getIdlePowerSaver(asyncResp);
2953         });
2954 
2955     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2956         .privileges(redfish::privileges::patchComputerSystem)
2957         .methods(boost::beast::http::verb::patch)(
2958             [&app](const crow::Request& req,
2959                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2960         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2961         {
2962             return;
2963         }
2964         std::optional<bool> locationIndicatorActive;
2965         std::optional<std::string> indicatorLed;
2966         std::optional<std::string> assetTag;
2967         std::optional<std::string> powerRestorePolicy;
2968         std::optional<std::string> powerMode;
2969         std::optional<bool> wdtEnable;
2970         std::optional<std::string> wdtTimeOutAction;
2971         std::optional<std::string> bootSource;
2972         std::optional<std::string> bootType;
2973         std::optional<std::string> bootEnable;
2974         std::optional<std::string> bootAutomaticRetry;
2975         std::optional<bool> bootTrustedModuleRequired;
2976         std::optional<bool> ipsEnable;
2977         std::optional<uint8_t> ipsEnterUtil;
2978         std::optional<uint64_t> ipsEnterTime;
2979         std::optional<uint8_t> ipsExitUtil;
2980         std::optional<uint64_t> ipsExitTime;
2981 
2982         // clang-format off
2983         if (!json_util::readJsonPatch(
2984                 req, asyncResp->res,
2985                 "IndicatorLED", indicatorLed,
2986                 "LocationIndicatorActive", locationIndicatorActive,
2987                 "AssetTag", assetTag,
2988                 "PowerRestorePolicy", powerRestorePolicy,
2989                 "PowerMode", powerMode,
2990                 "HostWatchdogTimer/FunctionEnabled", wdtEnable,
2991                 "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,
2992                 "Boot/BootSourceOverrideTarget", bootSource,
2993                 "Boot/BootSourceOverrideMode", bootType,
2994                 "Boot/BootSourceOverrideEnabled", bootEnable,
2995                 "Boot/AutomaticRetryConfig", bootAutomaticRetry,
2996                 "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
2997                 "IdlePowerSaver/Enabled", ipsEnable,
2998                 "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
2999                 "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,
3000                 "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,
3001                 "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime))
3002         {
3003             return;
3004         }
3005         // clang-format on
3006 
3007         asyncResp->res.result(boost::beast::http::status::no_content);
3008 
3009         if (assetTag)
3010         {
3011             setAssetTag(asyncResp, *assetTag);
3012         }
3013 
3014         if (wdtEnable || wdtTimeOutAction)
3015         {
3016             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3017         }
3018 
3019         if (bootSource || bootType || bootEnable)
3020         {
3021             setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3022         }
3023         if (bootAutomaticRetry)
3024         {
3025             setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3026         }
3027 
3028         if (bootTrustedModuleRequired)
3029         {
3030             setTrustedModuleRequiredToBoot(asyncResp,
3031                                            *bootTrustedModuleRequired);
3032         }
3033 
3034         if (locationIndicatorActive)
3035         {
3036             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3037         }
3038 
3039         // TODO (Gunnar): Remove IndicatorLED after enough time has
3040         // passed
3041         if (indicatorLed)
3042         {
3043             setIndicatorLedState(asyncResp, *indicatorLed);
3044             asyncResp->res.addHeader(boost::beast::http::field::warning,
3045                                      "299 - \"IndicatorLED is deprecated. Use "
3046                                      "LocationIndicatorActive instead.\"");
3047         }
3048 
3049         if (powerRestorePolicy)
3050         {
3051             setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3052         }
3053 
3054         if (powerMode)
3055         {
3056             setPowerMode(asyncResp, *powerMode);
3057         }
3058 
3059         if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil ||
3060             ipsExitTime)
3061         {
3062             setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3063                               ipsExitUtil, ipsExitTime);
3064         }
3065         });
3066 }
3067 
3068 /**
3069  * SystemResetActionInfo derived class for delivering Computer Systems
3070  * ResetType AllowableValues using ResetInfo schema.
3071  */
3072 inline void requestRoutesSystemResetActionInfo(App& app)
3073 {
3074     /**
3075      * Functions triggers appropriate requests on DBus
3076      */
3077     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
3078         .privileges(redfish::privileges::getActionInfo)
3079         .methods(boost::beast::http::verb::get)(
3080             [&app](const crow::Request& req,
3081                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3082         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3083         {
3084             return;
3085         }
3086 
3087         asyncResp->res.jsonValue["@odata.id"] =
3088             "/redfish/v1/Systems/system/ResetActionInfo";
3089         asyncResp->res.jsonValue["@odata.type"] =
3090             "#ActionInfo.v1_1_2.ActionInfo";
3091         asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3092         asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3093 
3094         nlohmann::json::array_t parameters;
3095         nlohmann::json::object_t parameter;
3096 
3097         parameter["Name"] = "ResetType";
3098         parameter["Required"] = true;
3099         parameter["DataType"] = "String";
3100         nlohmann::json::array_t allowableValues;
3101         allowableValues.emplace_back("On");
3102         allowableValues.emplace_back("ForceOff");
3103         allowableValues.emplace_back("ForceOn");
3104         allowableValues.emplace_back("ForceRestart");
3105         allowableValues.emplace_back("GracefulRestart");
3106         allowableValues.emplace_back("GracefulShutdown");
3107         allowableValues.emplace_back("PowerCycle");
3108         allowableValues.emplace_back("Nmi");
3109         parameter["AllowableValues"] = std::move(allowableValues);
3110         parameters.emplace_back(std::move(parameter));
3111 
3112         asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3113         });
3114 }
3115 } // namespace redfish
3116