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