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