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