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