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