xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 844b4152)
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 "health.hpp"
19 #include "led.hpp"
20 #include "pcie.hpp"
21 #include "redfish_util.hpp"
22 
23 #include <boost/container/flat_map.hpp>
24 #include <node.hpp>
25 #include <utils/fw_utils.hpp>
26 #include <utils/json_utils.hpp>
27 
28 #include <variant>
29 
30 namespace redfish
31 {
32 
33 /**
34  * @brief Updates the Functional State of DIMMs
35  *
36  * @param[in] aResp Shared pointer for completing asynchronous calls
37  * @param[in] dimmState Dimm's Functional state, true/false
38  *
39  * @return None.
40  */
41 void updateDimmProperties(std::shared_ptr<AsyncResp> aResp,
42                           const std::variant<bool>& dimmState)
43 {
44     const bool* isDimmFunctional = std::get_if<bool>(&dimmState);
45     if (isDimmFunctional == nullptr)
46     {
47         messages::internalError(aResp->res);
48         return;
49     }
50     BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional;
51 
52     // Set it as Enabled if atleast one DIMM is functional
53     // Update STATE only if previous State was DISABLED and current Dimm is
54     // ENABLED.
55     nlohmann::json& prevMemSummary =
56         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
57     if (prevMemSummary == "Disabled")
58     {
59         if (*isDimmFunctional == true)
60         {
61             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
62                 "Enabled";
63         }
64     }
65 }
66 
67 /*
68  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
69  *
70  * @param[in] aResp Shared pointer for completing asynchronous calls
71  * @param[in] cpuPresenceState CPU present or not
72  *
73  * @return None.
74  */
75 void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp,
76                             const std::variant<bool>& cpuPresenceState)
77 {
78     const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState);
79 
80     if (isCpuPresent == nullptr)
81     {
82         messages::internalError(aResp->res);
83         return;
84     }
85     BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent;
86 
87     if (*isCpuPresent == true)
88     {
89         nlohmann::json& procCount =
90             aResp->res.jsonValue["ProcessorSummary"]["Count"];
91         auto procCountPtr =
92             procCount.get_ptr<nlohmann::json::number_integer_t*>();
93         if (procCountPtr != nullptr)
94         {
95             // shouldn't be possible to be nullptr
96             *procCountPtr += 1;
97         }
98     }
99 }
100 
101 /*
102  * @brief Update "ProcessorSummary" "Status" "State" based on
103  *        CPU Functional State
104  *
105  * @param[in] aResp Shared pointer for completing asynchronous calls
106  * @param[in] cpuFunctionalState is CPU functional true/false
107  *
108  * @return None.
109  */
110 void modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp,
111                               const std::variant<bool>& cpuFunctionalState)
112 {
113     const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState);
114 
115     if (isCpuFunctional == nullptr)
116     {
117         messages::internalError(aResp->res);
118         return;
119     }
120     BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional;
121 
122     nlohmann::json& prevProcState =
123         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
124 
125     // Set it as Enabled if atleast one CPU is functional
126     // Update STATE only if previous State was Non_Functional and current CPU is
127     // Functional.
128     if (prevProcState == "Disabled")
129     {
130         if (*isCpuFunctional == true)
131         {
132             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
133                 "Enabled";
134         }
135     }
136 }
137 
138 /*
139  * @brief Retrieves computer system properties over dbus
140  *
141  * @param[in] aResp Shared pointer for completing asynchronous calls
142  * @param[in] name  Computer system name from request
143  *
144  * @return None.
145  */
146 void getComputerSystem(std::shared_ptr<AsyncResp> aResp,
147                        std::shared_ptr<HealthPopulate> systemHealth)
148 {
149     BMCWEB_LOG_DEBUG << "Get available system components.";
150 
151     crow::connections::systemBus->async_method_call(
152         [aResp, systemHealth](
153             const boost::system::error_code ec,
154             const std::vector<std::pair<
155                 std::string,
156                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
157                 subtree) {
158             if (ec)
159             {
160                 BMCWEB_LOG_DEBUG << "DBUS response error";
161                 messages::internalError(aResp->res);
162                 return;
163             }
164             // Iterate over all retrieved ObjectPaths.
165             for (const std::pair<std::string,
166                                  std::vector<std::pair<
167                                      std::string, std::vector<std::string>>>>&
168                      object : subtree)
169             {
170                 const std::string& path = object.first;
171                 BMCWEB_LOG_DEBUG << "Got path: " << path;
172                 const std::vector<
173                     std::pair<std::string, std::vector<std::string>>>&
174                     connectionNames = object.second;
175                 if (connectionNames.size() < 1)
176                 {
177                     continue;
178                 }
179 
180                 auto memoryHealth = std::make_shared<HealthPopulate>(
181                     aResp, aResp->res.jsonValue["MemorySummary"]["Status"]);
182 
183                 auto cpuHealth = std::make_shared<HealthPopulate>(
184                     aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]);
185 
186                 systemHealth->children.emplace_back(memoryHealth);
187                 systemHealth->children.emplace_back(cpuHealth);
188 
189                 // This is not system, so check if it's cpu, dimm, UUID or
190                 // BiosVer
191                 for (const auto& connection : connectionNames)
192                 {
193                     for (const auto& interfaceName : connection.second)
194                     {
195                         if (interfaceName ==
196                             "xyz.openbmc_project.Inventory.Item.Dimm")
197                         {
198                             BMCWEB_LOG_DEBUG
199                                 << "Found Dimm, now get its properties.";
200 
201                             crow::connections::systemBus->async_method_call(
202                                 [aResp, service{connection.first},
203                                  path(std::move(path))](
204                                     const boost::system::error_code ec,
205                                     const std::vector<
206                                         std::pair<std::string, VariantType>>&
207                                         properties) {
208                                     if (ec)
209                                     {
210                                         BMCWEB_LOG_ERROR
211                                             << "DBUS response error " << ec;
212                                         messages::internalError(aResp->res);
213                                         return;
214                                     }
215                                     BMCWEB_LOG_DEBUG << "Got "
216                                                      << properties.size()
217                                                      << " Dimm properties.";
218 
219                                     if (properties.size() > 0)
220                                     {
221                                         for (const std::pair<std::string,
222                                                              VariantType>&
223                                                  property : properties)
224                                         {
225                                             if (property.first !=
226                                                 "MemorySizeInKB")
227                                             {
228                                                 continue;
229                                             }
230                                             const uint32_t* value =
231                                                 std::get_if<uint32_t>(
232                                                     &property.second);
233                                             if (value == nullptr)
234                                             {
235                                                 BMCWEB_LOG_DEBUG
236                                                     << "Find incorrect type of "
237                                                        "MemorySize";
238                                                 continue;
239                                             }
240                                             nlohmann::json& totalMemory =
241                                                 aResp->res
242                                                     .jsonValue["MemorySummar"
243                                                                "y"]
244                                                               ["TotalSystemMe"
245                                                                "moryGiB"];
246                                             uint64_t* preValue =
247                                                 totalMemory
248                                                     .get_ptr<uint64_t*>();
249                                             if (preValue == nullptr)
250                                             {
251                                                 continue;
252                                             }
253                                             aResp->res
254                                                 .jsonValue["MemorySummary"]
255                                                           ["TotalSystemMemoryGi"
256                                                            "B"] =
257                                                 *value / (1024 * 1024) +
258                                                 *preValue;
259                                             aResp->res
260                                                 .jsonValue["MemorySummary"]
261                                                           ["Status"]["State"] =
262                                                 "Enabled";
263                                         }
264                                     }
265                                     else
266                                     {
267                                         auto getDimmProperties =
268                                             [aResp](
269                                                 const boost::system::error_code
270                                                     ec,
271                                                 const std::variant<bool>&
272                                                     dimmState) {
273                                                 if (ec)
274                                                 {
275                                                     BMCWEB_LOG_ERROR
276                                                         << "DBUS response "
277                                                            "error "
278                                                         << ec;
279                                                     return;
280                                                 }
281                                                 updateDimmProperties(aResp,
282                                                                      dimmState);
283                                             };
284                                         crow::connections::systemBus
285                                             ->async_method_call(
286                                                 std::move(getDimmProperties),
287                                                 service, path,
288                                                 "org.freedesktop.DBus."
289                                                 "Properties",
290                                                 "Get",
291                                                 "xyz.openbmc_project.State."
292                                                 "Decorator.OperationalStatus",
293                                                 "Functional");
294                                     }
295                                 },
296                                 connection.first, path,
297                                 "org.freedesktop.DBus.Properties", "GetAll",
298                                 "xyz.openbmc_project.Inventory.Item.Dimm");
299 
300                             memoryHealth->inventory.emplace_back(path);
301                         }
302                         else if (interfaceName ==
303                                  "xyz.openbmc_project.Inventory.Item.Cpu")
304                         {
305                             BMCWEB_LOG_DEBUG
306                                 << "Found Cpu, now get its properties.";
307 
308                             crow::connections::systemBus->async_method_call(
309                                 [aResp, service{connection.first},
310                                  path(std::move(path))](
311                                     const boost::system::error_code ec,
312                                     const std::vector<
313                                         std::pair<std::string, VariantType>>&
314                                         properties) {
315                                     if (ec)
316                                     {
317                                         BMCWEB_LOG_ERROR
318                                             << "DBUS response error " << ec;
319                                         messages::internalError(aResp->res);
320                                         return;
321                                     }
322                                     BMCWEB_LOG_DEBUG << "Got "
323                                                      << properties.size()
324                                                      << " Cpu properties.";
325 
326                                     if (properties.size() > 0)
327                                     {
328                                         for (const auto& property : properties)
329                                         {
330                                             if (property.first ==
331                                                 "ProcessorFamily")
332                                             {
333                                                 const std::string* value =
334                                                     std::get_if<std::string>(
335                                                         &property.second);
336                                                 if (value != nullptr)
337                                                 {
338                                                     nlohmann::json&
339                                                         procSummary =
340                                                             aResp->res.jsonValue
341                                                                 ["ProcessorSumm"
342                                                                  "ary"];
343                                                     nlohmann::json& procCount =
344                                                         procSummary["Count"];
345 
346                                                     auto procCountPtr =
347                                                         procCount.get_ptr<
348                                                             nlohmann::json::
349                                                                 number_integer_t*>();
350                                                     if (procCountPtr != nullptr)
351                                                     {
352                                                         // shouldn't be possible
353                                                         // to be nullptr
354                                                         *procCountPtr += 1;
355                                                     }
356                                                     procSummary["Status"]
357                                                                ["State"] =
358                                                                    "Enabled";
359                                                     procSummary["Model"] =
360                                                         *value;
361                                                 }
362                                             }
363                                         }
364                                     }
365                                     else
366                                     {
367                                         auto getCpuPresenceState =
368                                             [aResp](
369                                                 const boost::system::error_code
370                                                     ec,
371                                                 const std::variant<bool>&
372                                                     cpuPresenceCheck) {
373                                                 if (ec)
374                                                 {
375                                                     BMCWEB_LOG_ERROR
376                                                         << "DBUS response "
377                                                            "error "
378                                                         << ec;
379                                                     return;
380                                                 }
381                                                 modifyCpuPresenceState(
382                                                     aResp, cpuPresenceCheck);
383                                             };
384 
385                                         auto getCpuFunctionalState =
386                                             [aResp](
387                                                 const boost::system::error_code
388                                                     ec,
389                                                 const std::variant<bool>&
390                                                     cpuFunctionalCheck) {
391                                                 if (ec)
392                                                 {
393                                                     BMCWEB_LOG_ERROR
394                                                         << "DBUS response "
395                                                            "error "
396                                                         << ec;
397                                                     return;
398                                                 }
399                                                 modifyCpuFunctionalState(
400                                                     aResp, cpuFunctionalCheck);
401                                             };
402                                         // Get the Presence of CPU
403                                         crow::connections::systemBus
404                                             ->async_method_call(
405                                                 std::move(getCpuPresenceState),
406                                                 service, path,
407                                                 "org.freedesktop.DBus."
408                                                 "Properties",
409                                                 "Get",
410                                                 "xyz.openbmc_project.Inventory."
411                                                 "Item",
412                                                 "Present");
413 
414                                         // Get the Functional State
415                                         crow::connections::systemBus
416                                             ->async_method_call(
417                                                 std::move(
418                                                     getCpuFunctionalState),
419                                                 service, path,
420                                                 "org.freedesktop.DBus."
421                                                 "Properties",
422                                                 "Get",
423                                                 "xyz.openbmc_project.State."
424                                                 "Decorator."
425                                                 "OperationalStatus",
426                                                 "Functional");
427 
428                                         // Get the MODEL from
429                                         // xyz.openbmc_project.Inventory.Decorator.Asset
430                                         // support it later as Model  is Empty
431                                         // currently.
432                                     }
433                                 },
434                                 connection.first, path,
435                                 "org.freedesktop.DBus.Properties", "GetAll",
436                                 "xyz.openbmc_project.Inventory.Item.Cpu");
437 
438                             cpuHealth->inventory.emplace_back(path);
439                         }
440                         else if (interfaceName ==
441                                  "xyz.openbmc_project.Common.UUID")
442                         {
443                             BMCWEB_LOG_DEBUG
444                                 << "Found UUID, now get its properties.";
445                             crow::connections::systemBus->async_method_call(
446                                 [aResp](
447                                     const boost::system::error_code ec,
448                                     const std::vector<
449                                         std::pair<std::string, VariantType>>&
450                                         properties) {
451                                     if (ec)
452                                     {
453                                         BMCWEB_LOG_DEBUG
454                                             << "DBUS response error " << ec;
455                                         messages::internalError(aResp->res);
456                                         return;
457                                     }
458                                     BMCWEB_LOG_DEBUG << "Got "
459                                                      << properties.size()
460                                                      << " UUID properties.";
461                                     for (const std::pair<std::string,
462                                                          VariantType>&
463                                              property : properties)
464                                     {
465                                         if (property.first == "UUID")
466                                         {
467                                             const std::string* value =
468                                                 std::get_if<std::string>(
469                                                     &property.second);
470 
471                                             if (value != nullptr)
472                                             {
473                                                 std::string valueStr = *value;
474                                                 if (valueStr.size() == 32)
475                                                 {
476                                                     valueStr.insert(8, 1, '-');
477                                                     valueStr.insert(13, 1, '-');
478                                                     valueStr.insert(18, 1, '-');
479                                                     valueStr.insert(23, 1, '-');
480                                                 }
481                                                 BMCWEB_LOG_DEBUG << "UUID = "
482                                                                  << valueStr;
483                                                 aResp->res.jsonValue["UUID"] =
484                                                     valueStr;
485                                             }
486                                         }
487                                     }
488                                 },
489                                 connection.first, path,
490                                 "org.freedesktop.DBus.Properties", "GetAll",
491                                 "xyz.openbmc_project.Common.UUID");
492                         }
493                         else if (interfaceName ==
494                                  "xyz.openbmc_project.Inventory.Item.System")
495                         {
496                             crow::connections::systemBus->async_method_call(
497                                 [aResp](
498                                     const boost::system::error_code ec,
499                                     const std::vector<
500                                         std::pair<std::string, VariantType>>&
501                                         propertiesList) {
502                                     if (ec)
503                                     {
504                                         // doesn't have to include this
505                                         // interface
506                                         return;
507                                     }
508                                     BMCWEB_LOG_DEBUG
509                                         << "Got " << propertiesList.size()
510                                         << " properties for system";
511                                     for (const std::pair<std::string,
512                                                          VariantType>&
513                                              property : propertiesList)
514                                     {
515                                         const std::string& propertyName =
516                                             property.first;
517                                         if ((propertyName == "PartNumber") ||
518                                             (propertyName == "SerialNumber") ||
519                                             (propertyName == "Manufacturer") ||
520                                             (propertyName == "Model"))
521                                         {
522                                             const std::string* value =
523                                                 std::get_if<std::string>(
524                                                     &property.second);
525                                             if (value != nullptr)
526                                             {
527                                                 aResp->res
528                                                     .jsonValue[propertyName] =
529                                                     *value;
530                                             }
531                                         }
532                                     }
533 
534                                     // Grab the bios version
535                                     fw_util::getActiveFwVersion(
536                                         aResp, fw_util::biosPurpose,
537                                         "BiosVersion");
538                                 },
539                                 connection.first, path,
540                                 "org.freedesktop.DBus.Properties", "GetAll",
541                                 "xyz.openbmc_project.Inventory.Decorator."
542                                 "Asset");
543 
544                             crow::connections::systemBus->async_method_call(
545                                 [aResp](
546                                     const boost::system::error_code ec,
547                                     const std::variant<std::string>& property) {
548                                     if (ec)
549                                     {
550                                         // doesn't have to include this
551                                         // interface
552                                         return;
553                                     }
554 
555                                     const std::string* value =
556                                         std::get_if<std::string>(&property);
557                                     if (value != nullptr)
558                                     {
559                                         aResp->res.jsonValue["AssetTag"] =
560                                             *value;
561                                     }
562                                 },
563                                 connection.first, path,
564                                 "org.freedesktop.DBus.Properties", "Get",
565                                 "xyz.openbmc_project.Inventory.Decorator."
566                                 "AssetTag",
567                                 "AssetTag");
568                         }
569                     }
570                 }
571             }
572         },
573         "xyz.openbmc_project.ObjectMapper",
574         "/xyz/openbmc_project/object_mapper",
575         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
576         "/xyz/openbmc_project/inventory", int32_t(0),
577         std::array<const char*, 5>{
578             "xyz.openbmc_project.Inventory.Decorator.Asset",
579             "xyz.openbmc_project.Inventory.Item.Cpu",
580             "xyz.openbmc_project.Inventory.Item.Dimm",
581             "xyz.openbmc_project.Inventory.Item.System",
582             "xyz.openbmc_project.Common.UUID",
583         });
584 }
585 
586 /**
587  * @brief Retrieves host state properties over dbus
588  *
589  * @param[in] aResp     Shared pointer for completing asynchronous calls.
590  *
591  * @return None.
592  */
593 void getHostState(std::shared_ptr<AsyncResp> aResp)
594 {
595     BMCWEB_LOG_DEBUG << "Get host information.";
596     crow::connections::systemBus->async_method_call(
597         [aResp](const boost::system::error_code ec,
598                 const std::variant<std::string>& hostState) {
599             if (ec)
600             {
601                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
602                 messages::internalError(aResp->res);
603                 return;
604             }
605 
606             const std::string* s = std::get_if<std::string>(&hostState);
607             BMCWEB_LOG_DEBUG << "Host state: " << *s;
608             if (s != nullptr)
609             {
610                 // Verify Host State
611                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
612                 {
613                     aResp->res.jsonValue["PowerState"] = "On";
614                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
615                 }
616                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
617                                "Quiesced")
618                 {
619                     aResp->res.jsonValue["PowerState"] = "On";
620                     aResp->res.jsonValue["Status"]["State"] = "Quiesced";
621                 }
622                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
623                                "DiagnosticMode")
624                 {
625                     aResp->res.jsonValue["PowerState"] = "On";
626                     aResp->res.jsonValue["Status"]["State"] = "InTest";
627                 }
628                 else
629                 {
630                     aResp->res.jsonValue["PowerState"] = "Off";
631                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
632                 }
633             }
634         },
635         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
636         "org.freedesktop.DBus.Properties", "Get",
637         "xyz.openbmc_project.State.Host", "CurrentHostState");
638 }
639 
640 /**
641  * @brief Traslates boot source DBUS property value to redfish.
642  *
643  * @param[in] dbusSource    The boot source in DBUS speak.
644  *
645  * @return Returns as a string, the boot source in Redfish terms. If translation
646  * cannot be done, returns an empty string.
647  */
648 static std::string dbusToRfBootSource(const std::string& dbusSource)
649 {
650     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
651     {
652         return "None";
653     }
654     else if (dbusSource ==
655              "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
656     {
657         return "Hdd";
658     }
659     else if (dbusSource ==
660              "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
661     {
662         return "Cd";
663     }
664     else if (dbusSource ==
665              "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
666     {
667         return "Pxe";
668     }
669     else if (dbusSource ==
670              "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
671     {
672         return "Usb";
673     }
674     else
675     {
676         return "";
677     }
678 }
679 
680 /**
681  * @brief Traslates boot mode DBUS property value to redfish.
682  *
683  * @param[in] dbusMode    The boot mode in DBUS speak.
684  *
685  * @return Returns as a string, the boot mode in Redfish terms. If translation
686  * cannot be done, returns an empty string.
687  */
688 static std::string dbusToRfBootMode(const std::string& dbusMode)
689 {
690     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
691     {
692         return "None";
693     }
694     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
695     {
696         return "Diags";
697     }
698     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
699     {
700         return "BiosSetup";
701     }
702     else
703     {
704         return "";
705     }
706 }
707 
708 /**
709  * @brief Traslates boot source from Redfish to the DBus boot paths.
710  *
711  * @param[in] rfSource    The boot source in Redfish.
712  * @param[out] bootSource The DBus source
713  * @param[out] bootMode   the DBus boot mode
714  *
715  * @return Integer error code.
716  */
717 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp,
718                                 const std::string& rfSource,
719                                 std::string& bootSource, std::string& bootMode)
720 {
721     // The caller has initialized the bootSource and bootMode to:
722     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
723     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
724     // Only modify the bootSource/bootMode variable needed to achieve the
725     // desired boot action.
726 
727     if (rfSource == "None")
728     {
729         return 0;
730     }
731     else if (rfSource == "Pxe")
732     {
733         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
734     }
735     else if (rfSource == "Hdd")
736     {
737         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
738     }
739     else if (rfSource == "Diags")
740     {
741         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
742     }
743     else if (rfSource == "Cd")
744     {
745         bootSource =
746             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
747     }
748     else if (rfSource == "BiosSetup")
749     {
750         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
751     }
752     else if (rfSource == "Usb")
753     {
754         bootSource =
755             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
756     }
757     else
758     {
759         BMCWEB_LOG_DEBUG << "Invalid property value for "
760                             "BootSourceOverrideTarget: "
761                          << bootSource;
762         messages::propertyValueNotInList(aResp->res, rfSource,
763                                          "BootSourceTargetOverride");
764         return -1;
765     }
766     return 0;
767 }
768 
769 /**
770  * @brief Retrieves boot mode over DBUS and fills out the response
771  *
772  * @param[in] aResp         Shared pointer for generating response message.
773  * @param[in] bootDbusObj   The dbus object to query for boot properties.
774  *
775  * @return None.
776  */
777 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
778                         std::string bootDbusObj)
779 {
780     crow::connections::systemBus->async_method_call(
781         [aResp](const boost::system::error_code ec,
782                 const std::variant<std::string>& bootMode) {
783             if (ec)
784             {
785                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
786                 messages::internalError(aResp->res);
787                 return;
788             }
789 
790             const std::string* bootModeStr =
791                 std::get_if<std::string>(&bootMode);
792 
793             if (!bootModeStr)
794             {
795                 messages::internalError(aResp->res);
796                 return;
797             }
798 
799             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
800 
801             // TODO (Santosh): Do we need to support override mode?
802             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
803             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
804                                          "AllowableValues"] = {
805                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
806 
807             if (*bootModeStr !=
808                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
809             {
810                 auto rfMode = dbusToRfBootMode(*bootModeStr);
811                 if (!rfMode.empty())
812                 {
813                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
814                         rfMode;
815                 }
816             }
817 
818             // If the BootSourceOverrideTarget is still "None" at the end,
819             // reset the BootSourceOverrideEnabled to indicate that
820             // overrides are disabled
821             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
822                 "None")
823             {
824                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
825                     "Disabled";
826             }
827         },
828         "xyz.openbmc_project.Settings", bootDbusObj,
829         "org.freedesktop.DBus.Properties", "Get",
830         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
831 }
832 
833 /**
834  * @brief Retrieves boot source over DBUS
835  *
836  * @param[in] aResp         Shared pointer for generating response message.
837  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
838  *
839  * @return None.
840  */
841 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
842 {
843     std::string bootDbusObj =
844         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
845                        : "/xyz/openbmc_project/control/host0/boot";
846 
847     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
848     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
849         (oneTimeEnabled) ? "Once" : "Continuous";
850 
851     crow::connections::systemBus->async_method_call(
852         [aResp, bootDbusObj](const boost::system::error_code ec,
853                              const std::variant<std::string>& bootSource) {
854             if (ec)
855             {
856                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
857                 messages::internalError(aResp->res);
858                 return;
859             }
860 
861             const std::string* bootSourceStr =
862                 std::get_if<std::string>(&bootSource);
863 
864             if (!bootSourceStr)
865             {
866                 messages::internalError(aResp->res);
867                 return;
868             }
869             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
870 
871             auto rfSource = dbusToRfBootSource(*bootSourceStr);
872             if (!rfSource.empty())
873             {
874                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
875                     rfSource;
876             }
877         },
878         "xyz.openbmc_project.Settings", bootDbusObj,
879         "org.freedesktop.DBus.Properties", "Get",
880         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
881     getBootMode(std::move(aResp), std::move(bootDbusObj));
882 }
883 
884 /**
885  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
886  * get boot source and boot mode.
887  *
888  * @param[in] aResp     Shared pointer for generating response message.
889  *
890  * @return None.
891  */
892 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
893 {
894     BMCWEB_LOG_DEBUG << "Get boot information.";
895 
896     crow::connections::systemBus->async_method_call(
897         [aResp](const boost::system::error_code ec,
898                 const std::variant<bool>& oneTime) {
899             if (ec)
900             {
901                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
902                 // not an error, don't have to have the interface
903                 return;
904             }
905 
906             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
907 
908             if (!oneTimePtr)
909             {
910                 messages::internalError(aResp->res);
911                 return;
912             }
913             getBootSource(aResp, *oneTimePtr);
914         },
915         "xyz.openbmc_project.Settings",
916         "/xyz/openbmc_project/control/host0/boot/one_time",
917         "org.freedesktop.DBus.Properties", "Get",
918         "xyz.openbmc_project.Object.Enable", "Enabled");
919 }
920 
921 /**
922  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
923  *
924  * @param[in] aResp     Shared pointer for generating response message.
925  *
926  * @return None.
927  */
928 void getAutomaticRetry(std::shared_ptr<AsyncResp> aResp)
929 {
930     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
931 
932     crow::connections::systemBus->async_method_call(
933         [aResp](const boost::system::error_code ec,
934                 std::variant<bool>& autoRebootEnabled) {
935             if (ec)
936             {
937                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
938                 return;
939             }
940 
941             const bool* autoRebootEnabledPtr =
942                 std::get_if<bool>(&autoRebootEnabled);
943 
944             if (!autoRebootEnabledPtr)
945             {
946                 messages::internalError(aResp->res);
947                 return;
948             }
949 
950             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
951             if (*autoRebootEnabledPtr == true)
952             {
953                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
954                     "RetryAttempts";
955                 // If AutomaticRetry (AutoReboot) is enabled see how many
956                 // attempts are left
957                 crow::connections::systemBus->async_method_call(
958                     [aResp](const boost::system::error_code ec,
959                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
960                         if (ec)
961                         {
962                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
963                             return;
964                         }
965 
966                         const uint32_t* autoRebootAttemptsLeftPtr =
967                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
968 
969                         if (!autoRebootAttemptsLeftPtr)
970                         {
971                             messages::internalError(aResp->res);
972                             return;
973                         }
974 
975                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
976                                          << *autoRebootAttemptsLeftPtr;
977 
978                         aResp->res
979                             .jsonValue["Boot"]
980                                       ["RemainingAutomaticRetryAttempts"] =
981                             *autoRebootAttemptsLeftPtr;
982                     },
983                     "xyz.openbmc_project.State.Host",
984                     "/xyz/openbmc_project/state/host0",
985                     "org.freedesktop.DBus.Properties", "Get",
986                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
987                     "AttemptsLeft");
988             }
989             else
990             {
991                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
992                     "Disabled";
993             }
994 
995             // Not on D-Bus. Hardcoded here:
996             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
997             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
998 
999             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1000             // and RetryAttempts. OpenBMC only supports Disabled and
1001             // RetryAttempts.
1002             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish."
1003                                          "AllowableValues"] = {"Disabled",
1004                                                                "RetryAttempts"};
1005         },
1006         "xyz.openbmc_project.Settings",
1007         "/xyz/openbmc_project/control/host0/auto_reboot",
1008         "org.freedesktop.DBus.Properties", "Get",
1009         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1010 }
1011 
1012 /**
1013  * @brief Retrieves power restore policy over DBUS.
1014  *
1015  * @param[in] aResp     Shared pointer for generating response message.
1016  *
1017  * @return None.
1018  */
1019 void getPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp)
1020 {
1021     BMCWEB_LOG_DEBUG << "Get power restore policy";
1022 
1023     crow::connections::systemBus->async_method_call(
1024         [aResp](const boost::system::error_code ec,
1025                 std::variant<std::string>& policy) {
1026             if (ec)
1027             {
1028                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1029                 return;
1030             }
1031 
1032             const boost::container::flat_map<std::string, std::string>
1033                 policyMaps = {
1034                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1035                      "AlwaysOn",
1036                      "AlwaysOn"},
1037                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1038                      "AlwaysOff",
1039                      "AlwaysOff"},
1040                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1041                      "LastState",
1042                      "LastState"}};
1043 
1044             const std::string* policyPtr = std::get_if<std::string>(&policy);
1045 
1046             if (!policyPtr)
1047             {
1048                 messages::internalError(aResp->res);
1049                 return;
1050             }
1051 
1052             auto policyMapsIt = policyMaps.find(*policyPtr);
1053             if (policyMapsIt == policyMaps.end())
1054             {
1055                 messages::internalError(aResp->res);
1056                 return;
1057             }
1058 
1059             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1060         },
1061         "xyz.openbmc_project.Settings",
1062         "/xyz/openbmc_project/control/host0/power_restore_policy",
1063         "org.freedesktop.DBus.Properties", "Get",
1064         "xyz.openbmc_project.Control.Power.RestorePolicy",
1065         "PowerRestorePolicy");
1066 }
1067 
1068 /**
1069  * @brief Sets boot properties into DBUS object(s).
1070  *
1071  * @param[in] aResp           Shared pointer for generating response message.
1072  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
1073  * @param[in] bootSource      The boot source to set.
1074  * @param[in] bootEnable      The source override "enable" to set.
1075  *
1076  * @return Integer error code.
1077  */
1078 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
1079                                 bool oneTimeEnabled,
1080                                 std::optional<std::string> bootSource,
1081                                 std::optional<std::string> bootEnable)
1082 {
1083     std::string bootSourceStr =
1084         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
1085     std::string bootModeStr =
1086         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
1087     bool oneTimeSetting = oneTimeEnabled;
1088     bool useBootSource = true;
1089 
1090     // Validate incoming parameters
1091     if (bootEnable)
1092     {
1093         if (*bootEnable == "Once")
1094         {
1095             oneTimeSetting = true;
1096         }
1097         else if (*bootEnable == "Continuous")
1098         {
1099             oneTimeSetting = false;
1100         }
1101         else if (*bootEnable == "Disabled")
1102         {
1103             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1104             oneTimeSetting = false;
1105             useBootSource = false;
1106         }
1107         else
1108         {
1109             BMCWEB_LOG_DEBUG << "Unsupported value for "
1110                                 "BootSourceOverrideEnabled: "
1111                              << *bootEnable;
1112             messages::propertyValueNotInList(aResp->res, *bootEnable,
1113                                              "BootSourceOverrideEnabled");
1114             return;
1115         }
1116     }
1117 
1118     if (bootSource && useBootSource)
1119     {
1120         // Source target specified
1121         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1122         // Figure out which DBUS interface and property to use
1123         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1124                                  bootModeStr))
1125         {
1126             BMCWEB_LOG_DEBUG
1127                 << "Invalid property value for BootSourceOverrideTarget: "
1128                 << *bootSource;
1129             messages::propertyValueNotInList(aResp->res, *bootSource,
1130                                              "BootSourceTargetOverride");
1131             return;
1132         }
1133     }
1134 
1135     // Act on validated parameters
1136     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1137     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1138     const char* bootObj =
1139         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1140                        : "/xyz/openbmc_project/control/host0/boot";
1141 
1142     crow::connections::systemBus->async_method_call(
1143         [aResp](const boost::system::error_code ec) {
1144             if (ec)
1145             {
1146                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1147                 messages::internalError(aResp->res);
1148                 return;
1149             }
1150             BMCWEB_LOG_DEBUG << "Boot source update done.";
1151         },
1152         "xyz.openbmc_project.Settings", bootObj,
1153         "org.freedesktop.DBus.Properties", "Set",
1154         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1155         std::variant<std::string>(bootSourceStr));
1156 
1157     crow::connections::systemBus->async_method_call(
1158         [aResp](const boost::system::error_code ec) {
1159             if (ec)
1160             {
1161                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1162                 messages::internalError(aResp->res);
1163                 return;
1164             }
1165             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1166         },
1167         "xyz.openbmc_project.Settings", bootObj,
1168         "org.freedesktop.DBus.Properties", "Set",
1169         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1170         std::variant<std::string>(bootModeStr));
1171 
1172     crow::connections::systemBus->async_method_call(
1173         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1174             if (ec)
1175             {
1176                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1177                 messages::internalError(aResp->res);
1178                 return;
1179             }
1180             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1181         },
1182         "xyz.openbmc_project.Settings",
1183         "/xyz/openbmc_project/control/host0/boot/one_time",
1184         "org.freedesktop.DBus.Properties", "Set",
1185         "xyz.openbmc_project.Object.Enable", "Enabled",
1186         std::variant<bool>(oneTimeSetting));
1187 }
1188 
1189 /**
1190  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1191  * set boot source/boot mode properties.
1192  *
1193  * @param[in] aResp      Shared pointer for generating response message.
1194  * @param[in] bootSource The boot source from incoming RF request.
1195  * @param[in] bootEnable The boot override enable from incoming RF request.
1196  *
1197  * @return Integer error code.
1198  */
1199 static void setBootSourceProperties(std::shared_ptr<AsyncResp> aResp,
1200                                     std::optional<std::string> bootSource,
1201                                     std::optional<std::string> bootEnable)
1202 {
1203     BMCWEB_LOG_DEBUG << "Set boot information.";
1204 
1205     crow::connections::systemBus->async_method_call(
1206         [aResp, bootSource{std::move(bootSource)},
1207          bootEnable{std::move(bootEnable)}](const boost::system::error_code ec,
1208                                             const std::variant<bool>& oneTime) {
1209             if (ec)
1210             {
1211                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1212                 messages::internalError(aResp->res);
1213                 return;
1214             }
1215 
1216             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1217 
1218             if (!oneTimePtr)
1219             {
1220                 messages::internalError(aResp->res);
1221                 return;
1222             }
1223 
1224             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1225 
1226             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1227                                 std::move(bootEnable));
1228         },
1229         "xyz.openbmc_project.Settings",
1230         "/xyz/openbmc_project/control/host0/boot/one_time",
1231         "org.freedesktop.DBus.Properties", "Get",
1232         "xyz.openbmc_project.Object.Enable", "Enabled");
1233 }
1234 
1235 /**
1236  * @brief Sets automaticRetry (Auto Reboot)
1237  *
1238  * @param[in] aResp   Shared pointer for generating response message.
1239  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1240  *
1241  * @return None.
1242  */
1243 static void setAutomaticRetry(std::shared_ptr<AsyncResp> aResp,
1244                               const std::string&& automaticRetryConfig)
1245 {
1246     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1247 
1248     // OpenBMC only supports "Disabled" and "RetryAttempts".
1249     bool autoRebootEnabled;
1250 
1251     if (automaticRetryConfig == "Disabled")
1252     {
1253         autoRebootEnabled = false;
1254     }
1255     else if (automaticRetryConfig == "RetryAttempts")
1256     {
1257         autoRebootEnabled = true;
1258     }
1259     else
1260     {
1261         BMCWEB_LOG_DEBUG << "Invalid property value for "
1262                             "AutomaticRetryConfig: "
1263                          << automaticRetryConfig;
1264         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1265                                          "AutomaticRetryConfig");
1266         return;
1267     }
1268 
1269     crow::connections::systemBus->async_method_call(
1270         [aResp](const boost::system::error_code ec) {
1271             if (ec)
1272             {
1273                 messages::internalError(aResp->res);
1274                 return;
1275             }
1276         },
1277         "xyz.openbmc_project.Settings",
1278         "/xyz/openbmc_project/control/host0/auto_reboot",
1279         "org.freedesktop.DBus.Properties", "Set",
1280         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1281         std::variant<bool>(autoRebootEnabled));
1282 }
1283 
1284 /**
1285  * @brief Sets power restore policy properties.
1286  *
1287  * @param[in] aResp   Shared pointer for generating response message.
1288  * @param[in] policy  power restore policy properties from request.
1289  *
1290  * @return None.
1291  */
1292 static void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp,
1293                                   std::optional<std::string> policy)
1294 {
1295     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1296 
1297     const boost::container::flat_map<std::string, std::string> policyMaps = {
1298         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1299                      "AlwaysOn"},
1300         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1301                       "AlwaysOff"},
1302         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1303                       "LastState"}};
1304 
1305     std::string powerRestorPolicy;
1306 
1307     auto policyMapsIt = policyMaps.find(*policy);
1308     if (policyMapsIt == policyMaps.end())
1309     {
1310         messages::internalError(aResp->res);
1311         return;
1312     }
1313 
1314     powerRestorPolicy = policyMapsIt->second;
1315 
1316     crow::connections::systemBus->async_method_call(
1317         [aResp](const boost::system::error_code ec) {
1318             if (ec)
1319             {
1320                 messages::internalError(aResp->res);
1321                 return;
1322             }
1323         },
1324         "xyz.openbmc_project.Settings",
1325         "/xyz/openbmc_project/control/host0/power_restore_policy",
1326         "org.freedesktop.DBus.Properties", "Set",
1327         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1328         std::variant<std::string>(powerRestorPolicy));
1329 }
1330 
1331 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1332 /**
1333  * @brief Retrieves provisioning status
1334  *
1335  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1336  *
1337  * @return None.
1338  */
1339 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1340 {
1341     BMCWEB_LOG_DEBUG << "Get OEM information.";
1342     crow::connections::systemBus->async_method_call(
1343         [aResp](const boost::system::error_code ec,
1344                 const std::vector<std::pair<std::string, VariantType>>&
1345                     propertiesList) {
1346             if (ec)
1347             {
1348                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1349                 messages::internalError(aResp->res);
1350                 return;
1351             }
1352 
1353             const bool* provState = nullptr;
1354             const bool* lockState = nullptr;
1355             for (const std::pair<std::string, VariantType>& property :
1356                  propertiesList)
1357             {
1358                 if (property.first == "UfmProvisioned")
1359                 {
1360                     provState = std::get_if<bool>(&property.second);
1361                 }
1362                 else if (property.first == "UfmLocked")
1363                 {
1364                     lockState = std::get_if<bool>(&property.second);
1365                 }
1366             }
1367 
1368             if ((provState == nullptr) || (lockState == nullptr))
1369             {
1370                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1371                 messages::internalError(aResp->res);
1372                 return;
1373             }
1374 
1375             nlohmann::json& oemPFR =
1376                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1377             if (*provState == true)
1378             {
1379                 if (*lockState == true)
1380                 {
1381                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1382                 }
1383                 else
1384                 {
1385                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1386                 }
1387             }
1388             else
1389             {
1390                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1391             }
1392         },
1393         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1394         "org.freedesktop.DBus.Properties", "GetAll",
1395         "xyz.openbmc_project.PFR.Attributes");
1396 }
1397 #endif
1398 
1399 /**
1400  * @brief Translates watchdog timeout action DBUS property value to redfish.
1401  *
1402  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1403  *
1404  * @return Returns as a string, the timeout action in Redfish terms. If
1405  * translation cannot be done, returns an empty string.
1406  */
1407 static std::string dbusToRfWatchdogAction(const std::string& dbusAction)
1408 {
1409     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1410     {
1411         return "None";
1412     }
1413     else if (dbusAction ==
1414              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1415     {
1416         return "ResetSystem";
1417     }
1418     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1419     {
1420         return "PowerDown";
1421     }
1422     else if (dbusAction ==
1423              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1424     {
1425         return "PowerCycle";
1426     }
1427 
1428     return "";
1429 }
1430 
1431 /**
1432  *@brief Translates timeout action from Redfish to DBUS property value.
1433  *
1434  *@param[in] rfAction The timeout action in Redfish.
1435  *
1436  *@return Returns as a string, the time_out action as expected by DBUS.
1437  *If translation cannot be done, returns an empty string.
1438  */
1439 
1440 static std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
1441 {
1442     if (rfAction == "None")
1443     {
1444         return "xyz.openbmc_project.State.Watchdog.Action.None";
1445     }
1446     else if (rfAction == "PowerCycle")
1447     {
1448         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1449     }
1450     else if (rfAction == "PowerDown")
1451     {
1452         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1453     }
1454     else if (rfAction == "ResetSystem")
1455     {
1456         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1457     }
1458 
1459     return "";
1460 }
1461 
1462 /**
1463  * @brief Retrieves host watchdog timer properties over DBUS
1464  *
1465  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1466  *
1467  * @return None.
1468  */
1469 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1470 {
1471     BMCWEB_LOG_DEBUG << "Get host watchodg";
1472     crow::connections::systemBus->async_method_call(
1473         [aResp](const boost::system::error_code ec,
1474                 PropertiesType& properties) {
1475             if (ec)
1476             {
1477                 // watchdog service is stopped
1478                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1479                 return;
1480             }
1481 
1482             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1483 
1484             nlohmann::json& hostWatchdogTimer =
1485                 aResp->res.jsonValue["HostWatchdogTimer"];
1486 
1487             // watchdog service is running/enabled
1488             hostWatchdogTimer["Status"]["State"] = "Enabled";
1489 
1490             for (const auto& property : properties)
1491             {
1492                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1493                 if (property.first == "Enabled")
1494                 {
1495                     const bool* state = std::get_if<bool>(&property.second);
1496 
1497                     if (!state)
1498                     {
1499                         messages::internalError(aResp->res);
1500                         continue;
1501                     }
1502 
1503                     hostWatchdogTimer["FunctionEnabled"] = *state;
1504                 }
1505                 else if (property.first == "ExpireAction")
1506                 {
1507                     const std::string* s =
1508                         std::get_if<std::string>(&property.second);
1509                     if (!s)
1510                     {
1511                         messages::internalError(aResp->res);
1512                         continue;
1513                     }
1514 
1515                     std::string action = dbusToRfWatchdogAction(*s);
1516                     if (action.empty())
1517                     {
1518                         messages::internalError(aResp->res);
1519                         continue;
1520                     }
1521                     hostWatchdogTimer["TimeoutAction"] = action;
1522                 }
1523             }
1524         },
1525         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1526         "org.freedesktop.DBus.Properties", "GetAll",
1527         "xyz.openbmc_project.State.Watchdog");
1528 }
1529 
1530 /**
1531  * @brief Sets Host WatchDog Timer properties.
1532  *
1533  * @param[in] aResp      Shared pointer for generating response message.
1534  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1535  *                       RF request.
1536  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1537  *
1538  * @return None.
1539  */
1540 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp,
1541                              const std::optional<bool> wdtEnable,
1542                              const std::optional<std::string>& wdtTimeOutAction)
1543 {
1544     BMCWEB_LOG_DEBUG << "Set host watchdog";
1545 
1546     if (wdtTimeOutAction)
1547     {
1548         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1549         // check if TimeOut Action is Valid
1550         if (wdtTimeOutActStr.empty())
1551         {
1552             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1553                              << *wdtTimeOutAction;
1554             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1555                                              "TimeoutAction");
1556             return;
1557         }
1558 
1559         crow::connections::systemBus->async_method_call(
1560             [aResp](const boost::system::error_code ec) {
1561                 if (ec)
1562                 {
1563                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1564                     messages::internalError(aResp->res);
1565                     return;
1566                 }
1567             },
1568             "xyz.openbmc_project.Watchdog",
1569             "/xyz/openbmc_project/watchdog/host0",
1570             "org.freedesktop.DBus.Properties", "Set",
1571             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1572             std::variant<std::string>(wdtTimeOutActStr));
1573     }
1574 
1575     if (wdtEnable)
1576     {
1577         crow::connections::systemBus->async_method_call(
1578             [aResp](const boost::system::error_code ec) {
1579                 if (ec)
1580                 {
1581                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1582                     messages::internalError(aResp->res);
1583                     return;
1584                 }
1585             },
1586             "xyz.openbmc_project.Watchdog",
1587             "/xyz/openbmc_project/watchdog/host0",
1588             "org.freedesktop.DBus.Properties", "Set",
1589             "xyz.openbmc_project.State.Watchdog", "Enabled",
1590             std::variant<bool>(*wdtEnable));
1591     }
1592 }
1593 
1594 /**
1595  * SystemsCollection derived class for delivering ComputerSystems Collection
1596  * Schema
1597  */
1598 class SystemsCollection : public Node
1599 {
1600   public:
1601     SystemsCollection(CrowApp& app) : Node(app, "/redfish/v1/Systems/")
1602     {
1603         entityPrivileges = {
1604             {boost::beast::http::verb::get, {{"Login"}}},
1605             {boost::beast::http::verb::head, {{"Login"}}},
1606             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1607             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1608             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1609             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1610     }
1611 
1612   private:
1613     void doGet(crow::Response& res, const crow::Request& req,
1614                const std::vector<std::string>& params) override
1615     {
1616         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1617         res.jsonValue["@odata.type"] =
1618             "#ComputerSystemCollection.ComputerSystemCollection";
1619         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1620         res.jsonValue["Name"] = "Computer System Collection";
1621 
1622         crow::connections::systemBus->async_method_call(
1623             [asyncResp](const boost::system::error_code ec,
1624                         const std::variant<std::string>& hostName) {
1625                 nlohmann::json& iface_array =
1626                     asyncResp->res.jsonValue["Members"];
1627                 iface_array = nlohmann::json::array();
1628                 auto& count = asyncResp->res.jsonValue["Members@odata.count"];
1629                 count = 0;
1630                 if (ec)
1631                 {
1632                     iface_array.push_back(
1633                         {{"@odata.id", "/redfish/v1/Systems/system"}});
1634                     count = iface_array.size();
1635                     return;
1636                 }
1637                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
1638                 iface_array.push_back(
1639                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1640                 iface_array.push_back(
1641                     {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1642                 count = iface_array.size();
1643             },
1644             "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi",
1645             "org.freedesktop.DBus.Properties", "Get",
1646             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1647     }
1648 };
1649 
1650 /**
1651  * SystemActionsReset class supports handle POST method for Reset action.
1652  * The class retrieves and sends data directly to D-Bus.
1653  */
1654 class SystemActionsReset : public Node
1655 {
1656   public:
1657     SystemActionsReset(CrowApp& app) :
1658         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1659     {
1660         entityPrivileges = {
1661             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1662     }
1663 
1664   private:
1665     /**
1666      * Function handles POST method request.
1667      * Analyzes POST body message before sends Reset request data to D-Bus.
1668      */
1669     void doPost(crow::Response& res, const crow::Request& req,
1670                 const std::vector<std::string>& params) override
1671     {
1672         auto asyncResp = std::make_shared<AsyncResp>(res);
1673 
1674         std::string resetType;
1675         if (!json_util::readJson(req, res, "ResetType", resetType))
1676         {
1677             return;
1678         }
1679 
1680         // Get the command and host vs. chassis
1681         std::string command;
1682         bool hostCommand;
1683         if (resetType == "On")
1684         {
1685             command = "xyz.openbmc_project.State.Host.Transition.On";
1686             hostCommand = true;
1687         }
1688         else if (resetType == "ForceOff")
1689         {
1690             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1691             hostCommand = false;
1692         }
1693         else if (resetType == "ForceOn")
1694         {
1695             command = "xyz.openbmc_project.State.Host.Transition.On";
1696             hostCommand = true;
1697         }
1698         else if (resetType == "ForceRestart")
1699         {
1700             command =
1701                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1702             hostCommand = true;
1703         }
1704         else if (resetType == "GracefulShutdown")
1705         {
1706             command = "xyz.openbmc_project.State.Host.Transition.Off";
1707             hostCommand = true;
1708         }
1709         else if (resetType == "GracefulRestart")
1710         {
1711             command =
1712                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1713             hostCommand = true;
1714         }
1715         else if (resetType == "PowerCycle")
1716         {
1717             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1718             hostCommand = true;
1719         }
1720         else if (resetType == "Nmi")
1721         {
1722             doNMI(asyncResp);
1723             return;
1724         }
1725         else
1726         {
1727             messages::actionParameterUnknown(res, "Reset", resetType);
1728             return;
1729         }
1730 
1731         if (hostCommand)
1732         {
1733             crow::connections::systemBus->async_method_call(
1734                 [asyncResp, resetType](const boost::system::error_code ec) {
1735                     if (ec)
1736                     {
1737                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1738                         if (ec.value() == boost::asio::error::invalid_argument)
1739                         {
1740                             messages::actionParameterNotSupported(
1741                                 asyncResp->res, resetType, "Reset");
1742                         }
1743                         else
1744                         {
1745                             messages::internalError(asyncResp->res);
1746                         }
1747                         return;
1748                     }
1749                     messages::success(asyncResp->res);
1750                 },
1751                 "xyz.openbmc_project.State.Host",
1752                 "/xyz/openbmc_project/state/host0",
1753                 "org.freedesktop.DBus.Properties", "Set",
1754                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1755                 std::variant<std::string>{command});
1756         }
1757         else
1758         {
1759             crow::connections::systemBus->async_method_call(
1760                 [asyncResp, resetType](const boost::system::error_code ec) {
1761                     if (ec)
1762                     {
1763                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1764                         if (ec.value() == boost::asio::error::invalid_argument)
1765                         {
1766                             messages::actionParameterNotSupported(
1767                                 asyncResp->res, resetType, "Reset");
1768                         }
1769                         else
1770                         {
1771                             messages::internalError(asyncResp->res);
1772                         }
1773                         return;
1774                     }
1775                     messages::success(asyncResp->res);
1776                 },
1777                 "xyz.openbmc_project.State.Chassis",
1778                 "/xyz/openbmc_project/state/chassis0",
1779                 "org.freedesktop.DBus.Properties", "Set",
1780                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1781                 std::variant<std::string>{command});
1782         }
1783     }
1784     /**
1785      * Function transceives data with dbus directly.
1786      */
1787     void doNMI(const std::shared_ptr<AsyncResp>& asyncResp)
1788     {
1789         constexpr char const* serviceName =
1790             "xyz.openbmc_project.Control.Host.NMI";
1791         constexpr char const* objectPath =
1792             "/xyz/openbmc_project/control/host0/nmi";
1793         constexpr char const* interfaceName =
1794             "xyz.openbmc_project.Control.Host.NMI";
1795         constexpr char const* method = "NMI";
1796 
1797         crow::connections::systemBus->async_method_call(
1798             [asyncResp](const boost::system::error_code ec) {
1799                 if (ec)
1800                 {
1801                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1802                     messages::internalError(asyncResp->res);
1803                     return;
1804                 }
1805                 messages::success(asyncResp->res);
1806             },
1807             serviceName, objectPath, interfaceName, method);
1808     }
1809 };
1810 
1811 /**
1812  * Systems derived class for delivering Computer Systems Schema.
1813  */
1814 class Systems : public Node
1815 {
1816   public:
1817     /*
1818      * Default Constructor
1819      */
1820     Systems(CrowApp& app) : Node(app, "/redfish/v1/Systems/system/")
1821     {
1822         entityPrivileges = {
1823             {boost::beast::http::verb::get, {{"Login"}}},
1824             {boost::beast::http::verb::head, {{"Login"}}},
1825             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1826             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1827             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1828             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1829     }
1830 
1831   private:
1832     /**
1833      * Functions triggers appropriate requests on DBus
1834      */
1835     void doGet(crow::Response& res, const crow::Request& req,
1836                const std::vector<std::string>& params) override
1837     {
1838         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_11_0.ComputerSystem";
1839         res.jsonValue["Name"] = "system";
1840         res.jsonValue["Id"] = "system";
1841         res.jsonValue["SystemType"] = "Physical";
1842         res.jsonValue["Description"] = "Computer System";
1843         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1844         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1845         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
1846         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1847         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1848 
1849         res.jsonValue["Processors"] = {
1850             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1851         res.jsonValue["Memory"] = {
1852             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1853         res.jsonValue["Storage"] = {
1854             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1855 
1856         // TODO Need to support ForceRestart.
1857         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1858             {"target",
1859              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1860             {"ResetType@Redfish.AllowableValues",
1861              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1862               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1863 
1864         res.jsonValue["LogServices"] = {
1865             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1866 
1867         res.jsonValue["Bios"] = {
1868             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
1869 
1870         res.jsonValue["Links"]["ManagedBy"] = {
1871             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1872 
1873         res.jsonValue["Status"] = {
1874             {"Health", "OK"},
1875             {"State", "Enabled"},
1876         };
1877         auto asyncResp = std::make_shared<AsyncResp>(res);
1878 
1879         constexpr const std::array<const char*, 4> inventoryForSystems = {
1880             "xyz.openbmc_project.Inventory.Item.Dimm",
1881             "xyz.openbmc_project.Inventory.Item.Cpu",
1882             "xyz.openbmc_project.Inventory.Item.Drive",
1883             "xyz.openbmc_project.Inventory.Item.StorageController"};
1884 
1885         auto health = std::make_shared<HealthPopulate>(asyncResp);
1886         crow::connections::systemBus->async_method_call(
1887             [health](const boost::system::error_code ec,
1888                      std::vector<std::string>& resp) {
1889                 if (ec)
1890                 {
1891                     // no inventory
1892                     return;
1893                 }
1894 
1895                 health->inventory = std::move(resp);
1896             },
1897             "xyz.openbmc_project.ObjectMapper",
1898             "/xyz/openbmc_project/object_mapper",
1899             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1900             int32_t(0), inventoryForSystems);
1901 
1902         health->populate();
1903 
1904         getMainChassisId(asyncResp, [](const std::string& chassisId,
1905                                        std::shared_ptr<AsyncResp> aRsp) {
1906             aRsp->res.jsonValue["Links"]["Chassis"] = {
1907                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1908         });
1909 
1910         getIndicatorLedState(asyncResp);
1911         getComputerSystem(asyncResp, health);
1912         getHostState(asyncResp);
1913         getBootProperties(asyncResp);
1914         getPCIeDeviceList(asyncResp, "PCIeDevices");
1915         getHostWatchdogTimer(asyncResp);
1916         getPowerRestorePolicy(asyncResp);
1917         getAutomaticRetry(asyncResp);
1918 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1919         getProvisioningStatus(asyncResp);
1920 #endif
1921     }
1922 
1923     void doPatch(crow::Response& res, const crow::Request& req,
1924                  const std::vector<std::string>& params) override
1925     {
1926         std::optional<std::string> indicatorLed;
1927         std::optional<nlohmann::json> bootProps;
1928         std::optional<nlohmann::json> wdtTimerProps;
1929         std::optional<std::string> powerRestorePolicy;
1930         auto asyncResp = std::make_shared<AsyncResp>(res);
1931 
1932         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1933                                  bootProps, "WatchdogTimer", wdtTimerProps,
1934                                  "PowerRestorePolicy", powerRestorePolicy))
1935         {
1936             return;
1937         }
1938 
1939         res.result(boost::beast::http::status::no_content);
1940 
1941         if (wdtTimerProps)
1942         {
1943             std::optional<bool> wdtEnable;
1944             std::optional<std::string> wdtTimeOutAction;
1945 
1946             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
1947                                      "FunctionEnabled", wdtEnable,
1948                                      "TimeoutAction", wdtTimeOutAction))
1949             {
1950                 return;
1951             }
1952             setWDTProperties(asyncResp, std::move(wdtEnable),
1953                              std::move(wdtTimeOutAction));
1954         }
1955 
1956         if (bootProps)
1957         {
1958             std::optional<std::string> bootSource;
1959             std::optional<std::string> bootEnable;
1960             std::optional<std::string> automaticRetryConfig;
1961 
1962             if (!json_util::readJson(
1963                     *bootProps, asyncResp->res, "BootSourceOverrideTarget",
1964                     bootSource, "BootSourceOverrideEnabled", bootEnable,
1965                     "AutomaticRetryConfig", automaticRetryConfig))
1966             {
1967                 return;
1968             }
1969             if (bootSource || bootEnable)
1970             {
1971                 setBootSourceProperties(asyncResp, std::move(bootSource),
1972                                         std::move(bootEnable));
1973             }
1974             if (automaticRetryConfig)
1975             {
1976                 setAutomaticRetry(asyncResp, std::move(*automaticRetryConfig));
1977             }
1978         }
1979 
1980         if (indicatorLed)
1981         {
1982             setIndicatorLedState(asyncResp, std::move(*indicatorLed));
1983         }
1984 
1985         if (powerRestorePolicy)
1986         {
1987             setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy));
1988         }
1989     }
1990 };
1991 } // namespace redfish
1992