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