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