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