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