1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include "dbus_singleton.hpp" 19 #include "health.hpp" 20 #include "led.hpp" 21 #include "pcie.hpp" 22 #include "redfish_util.hpp" 23 24 #include <app.hpp> 25 #include <boost/container/flat_map.hpp> 26 #include <dbus_utility.hpp> 27 #include <registries/privilege_registry.hpp> 28 #include <sdbusplus/asio/property.hpp> 29 #include <utils/fw_utils.hpp> 30 #include <utils/json_utils.hpp> 31 32 #include <variant> 33 34 namespace redfish 35 { 36 37 /** 38 * @brief Updates the Functional State of DIMMs 39 * 40 * @param[in] aResp Shared pointer for completing asynchronous calls 41 * @param[in] dimmState Dimm's Functional state, true/false 42 * 43 * @return None. 44 */ 45 inline void 46 updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 47 bool isDimmFunctional) 48 { 49 BMCWEB_LOG_DEBUG << "Dimm Functional: " << isDimmFunctional; 50 51 // Set it as Enabled if at least one DIMM is functional 52 // Update STATE only if previous State was DISABLED and current Dimm is 53 // ENABLED. 54 nlohmann::json& prevMemSummary = 55 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 56 if (prevMemSummary == "Disabled") 57 { 58 if (isDimmFunctional == true) 59 { 60 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 61 "Enabled"; 62 } 63 } 64 } 65 66 /* 67 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 68 * 69 * @param[in] aResp Shared pointer for completing asynchronous calls 70 * @param[in] cpuPresenceState CPU present or not 71 * 72 * @return None. 73 */ 74 inline void 75 modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 76 bool isCpuPresent) 77 { 78 BMCWEB_LOG_DEBUG << "Cpu Present: " << isCpuPresent; 79 80 if (isCpuPresent == true) 81 { 82 nlohmann::json& procCount = 83 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 84 auto procCountPtr = 85 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 86 if (procCountPtr != nullptr) 87 { 88 // shouldn't be possible to be nullptr 89 *procCountPtr += 1; 90 } 91 } 92 } 93 94 /* 95 * @brief Update "ProcessorSummary" "Status" "State" based on 96 * CPU Functional State 97 * 98 * @param[in] aResp Shared pointer for completing asynchronous calls 99 * @param[in] cpuFunctionalState is CPU functional true/false 100 * 101 * @return None. 102 */ 103 inline void 104 modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 105 bool isCpuFunctional) 106 { 107 BMCWEB_LOG_DEBUG << "Cpu Functional: " << isCpuFunctional; 108 109 nlohmann::json& prevProcState = 110 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 111 112 // Set it as Enabled if at least one CPU is functional 113 // Update STATE only if previous State was Non_Functional and current CPU is 114 // Functional. 115 if (prevProcState == "Disabled") 116 { 117 if (isCpuFunctional == true) 118 { 119 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 120 "Enabled"; 121 } 122 } 123 } 124 125 inline void getProcessorProperties( 126 const std::shared_ptr<bmcweb::AsyncResp>& aResp, const std::string& service, 127 const std::string& path, 128 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>& 129 properties) 130 { 131 132 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties."; 133 134 auto getCpuPresenceState = [aResp](const boost::system::error_code ec3, 135 const bool cpuPresenceCheck) { 136 if (ec3) 137 { 138 BMCWEB_LOG_ERROR << "DBUS response error " << ec3; 139 return; 140 } 141 modifyCpuPresenceState(aResp, cpuPresenceCheck); 142 }; 143 144 auto getCpuFunctionalState = [aResp](const boost::system::error_code ec3, 145 const bool cpuFunctionalCheck) { 146 if (ec3) 147 { 148 BMCWEB_LOG_ERROR << "DBUS response error " << ec3; 149 return; 150 } 151 modifyCpuFunctionalState(aResp, cpuFunctionalCheck); 152 }; 153 154 // Get the Presence of CPU 155 sdbusplus::asio::getProperty<bool>( 156 *crow::connections::systemBus, service, path, 157 "xyz.openbmc_project.Inventory.Item", "Present", 158 std::move(getCpuPresenceState)); 159 160 // Get the Functional State 161 sdbusplus::asio::getProperty<bool>( 162 *crow::connections::systemBus, service, path, 163 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 164 std::move(getCpuFunctionalState)); 165 166 for (const auto& property : properties) 167 { 168 169 // TODO: Get Model 170 171 // Get CoreCount 172 if (property.first == "CoreCount") 173 { 174 175 // Get CPU CoreCount and add it to the total 176 const uint16_t* coreCountVal = 177 std::get_if<uint16_t>(&property.second); 178 179 if (!coreCountVal) 180 { 181 messages::internalError(aResp->res); 182 return; 183 } 184 185 nlohmann::json& coreCount = 186 aResp->res.jsonValue["ProcessorSummary"]["CoreCount"]; 187 uint64_t* coreCountPtr = coreCount.get_ptr<uint64_t*>(); 188 189 if (coreCountPtr == nullptr) 190 { 191 coreCount = 0; 192 } 193 else 194 { 195 *coreCountPtr += *coreCountVal; 196 } 197 } 198 } 199 } 200 201 /* 202 * @brief Get ProcessorSummary fields 203 * 204 * @param[in] aResp Shared pointer for completing asynchronous calls 205 * @param[in] service dbus service for Cpu Information 206 * @param[in] path dbus path for Cpu 207 * 208 * @return None. 209 */ 210 inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 211 const std::string& service, 212 const std::string& path) 213 { 214 215 crow::connections::systemBus->async_method_call( 216 [aResp, service, 217 path](const boost::system::error_code ec2, 218 const std::vector<std::pair< 219 std::string, dbus::utility::DbusVariantType>>& properties) { 220 if (ec2) 221 { 222 BMCWEB_LOG_ERROR << "DBUS response error " << ec2; 223 messages::internalError(aResp->res); 224 return; 225 } 226 getProcessorProperties(aResp, service, path, properties); 227 }, 228 service, path, "org.freedesktop.DBus.Properties", "GetAll", 229 "xyz.openbmc_project.Inventory.Item.Cpu"); 230 } 231 232 /* 233 * @brief Retrieves computer system properties over dbus 234 * 235 * @param[in] aResp Shared pointer for completing asynchronous calls 236 * @param[in] systemHealth Shared HealthPopulate pointer 237 * 238 * @return None. 239 */ 240 inline void 241 getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 242 const std::shared_ptr<HealthPopulate>& systemHealth) 243 { 244 BMCWEB_LOG_DEBUG << "Get available system components."; 245 246 crow::connections::systemBus->async_method_call( 247 [aResp, systemHealth]( 248 const boost::system::error_code ec, 249 const std::vector<std::pair< 250 std::string, 251 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 252 subtree) { 253 if (ec) 254 { 255 BMCWEB_LOG_DEBUG << "DBUS response error"; 256 messages::internalError(aResp->res); 257 return; 258 } 259 // Iterate over all retrieved ObjectPaths. 260 for (const std::pair<std::string, 261 std::vector<std::pair< 262 std::string, std::vector<std::string>>>>& 263 object : subtree) 264 { 265 const std::string& path = object.first; 266 BMCWEB_LOG_DEBUG << "Got path: " << path; 267 const std::vector< 268 std::pair<std::string, std::vector<std::string>>>& 269 connectionNames = object.second; 270 if (connectionNames.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 == true) 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 { 1579 BMCWEB_LOG_DEBUG 1580 << "Invalid property value for BootSourceOverrideTarget: " 1581 << *bootSource; 1582 messages::propertyValueNotInList(aResp->res, *bootSource, 1583 "BootSourceTargetOverride"); 1584 return; 1585 } 1586 1587 // Act on validated parameters 1588 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1589 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1590 1591 crow::connections::systemBus->async_method_call( 1592 [aResp](const boost::system::error_code ec) { 1593 if (ec) 1594 { 1595 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1596 messages::internalError(aResp->res); 1597 return; 1598 } 1599 BMCWEB_LOG_DEBUG << "Boot source update done."; 1600 }, 1601 "xyz.openbmc_project.Settings", 1602 "/xyz/openbmc_project/control/host0/boot", 1603 "org.freedesktop.DBus.Properties", "Set", 1604 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1605 dbus::utility::DbusVariantType(bootSourceStr)); 1606 1607 crow::connections::systemBus->async_method_call( 1608 [aResp](const boost::system::error_code ec) { 1609 if (ec) 1610 { 1611 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1612 messages::internalError(aResp->res); 1613 return; 1614 } 1615 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1616 }, 1617 "xyz.openbmc_project.Settings", 1618 "/xyz/openbmc_project/control/host0/boot", 1619 "org.freedesktop.DBus.Properties", "Set", 1620 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1621 dbus::utility::DbusVariantType(bootModeStr)); 1622 } 1623 1624 /** 1625 * @brief Sets Boot source override properties. 1626 * 1627 * @param[in] aResp Shared pointer for generating response message. 1628 * @param[in] bootSource The boot source from incoming RF request. 1629 * @param[in] bootType The boot type from incoming RF request. 1630 * @param[in] bootEnable The boot override enable from incoming RF request. 1631 * 1632 * @return Integer error code. 1633 */ 1634 1635 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1636 const std::optional<std::string>& bootSource, 1637 const std::optional<std::string>& bootType, 1638 const std::optional<std::string>& bootEnable) 1639 { 1640 BMCWEB_LOG_DEBUG << "Set boot information."; 1641 1642 setBootModeOrSource(aResp, bootSource); 1643 setBootType(aResp, bootType); 1644 setBootEnable(aResp, bootEnable); 1645 } 1646 1647 /** 1648 * @brief Sets AssetTag 1649 * 1650 * @param[in] aResp Shared pointer for generating response message. 1651 * @param[in] assetTag "AssetTag" from request. 1652 * 1653 * @return None. 1654 */ 1655 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1656 const std::string& assetTag) 1657 { 1658 crow::connections::systemBus->async_method_call( 1659 [aResp, assetTag]( 1660 const boost::system::error_code ec, 1661 const std::vector<std::pair< 1662 std::string, 1663 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1664 subtree) { 1665 if (ec) 1666 { 1667 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1668 messages::internalError(aResp->res); 1669 return; 1670 } 1671 if (subtree.empty()) 1672 { 1673 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1674 messages::internalError(aResp->res); 1675 return; 1676 } 1677 // Assume only 1 system D-Bus object 1678 // Throw an error if there is more than 1 1679 if (subtree.size() > 1) 1680 { 1681 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1682 messages::internalError(aResp->res); 1683 return; 1684 } 1685 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1686 { 1687 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1688 messages::internalError(aResp->res); 1689 return; 1690 } 1691 1692 const std::string& path = subtree[0].first; 1693 const std::string& service = subtree[0].second.begin()->first; 1694 1695 if (service.empty()) 1696 { 1697 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1698 messages::internalError(aResp->res); 1699 return; 1700 } 1701 1702 crow::connections::systemBus->async_method_call( 1703 [aResp](const boost::system::error_code ec2) { 1704 if (ec2) 1705 { 1706 BMCWEB_LOG_DEBUG 1707 << "D-Bus response error on AssetTag Set " << ec2; 1708 messages::internalError(aResp->res); 1709 return; 1710 } 1711 }, 1712 service, path, "org.freedesktop.DBus.Properties", "Set", 1713 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1714 dbus::utility::DbusVariantType(assetTag)); 1715 }, 1716 "xyz.openbmc_project.ObjectMapper", 1717 "/xyz/openbmc_project/object_mapper", 1718 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1719 "/xyz/openbmc_project/inventory", int32_t(0), 1720 std::array<const char*, 1>{ 1721 "xyz.openbmc_project.Inventory.Item.System"}); 1722 } 1723 1724 /** 1725 * @brief Sets automaticRetry (Auto Reboot) 1726 * 1727 * @param[in] aResp Shared pointer for generating response message. 1728 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1729 * 1730 * @return None. 1731 */ 1732 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1733 const std::string& automaticRetryConfig) 1734 { 1735 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1736 1737 // OpenBMC only supports "Disabled" and "RetryAttempts". 1738 bool autoRebootEnabled = false; 1739 1740 if (automaticRetryConfig == "Disabled") 1741 { 1742 autoRebootEnabled = false; 1743 } 1744 else if (automaticRetryConfig == "RetryAttempts") 1745 { 1746 autoRebootEnabled = true; 1747 } 1748 else 1749 { 1750 BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: " 1751 << automaticRetryConfig; 1752 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1753 "AutomaticRetryConfig"); 1754 return; 1755 } 1756 1757 crow::connections::systemBus->async_method_call( 1758 [aResp](const boost::system::error_code ec) { 1759 if (ec) 1760 { 1761 messages::internalError(aResp->res); 1762 return; 1763 } 1764 }, 1765 "xyz.openbmc_project.Settings", 1766 "/xyz/openbmc_project/control/host0/auto_reboot", 1767 "org.freedesktop.DBus.Properties", "Set", 1768 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1769 dbus::utility::DbusVariantType(autoRebootEnabled)); 1770 } 1771 1772 /** 1773 * @brief Sets power restore policy properties. 1774 * 1775 * @param[in] aResp Shared pointer for generating response message. 1776 * @param[in] policy power restore policy properties from request. 1777 * 1778 * @return None. 1779 */ 1780 inline void 1781 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1782 const std::string& policy) 1783 { 1784 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1785 1786 const boost::container::flat_map<std::string, std::string> policyMaps = { 1787 {"AlwaysOn", 1788 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"}, 1789 {"AlwaysOff", 1790 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"}, 1791 {"LastState", 1792 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}}; 1793 1794 std::string powerRestorPolicy; 1795 1796 auto policyMapsIt = policyMaps.find(policy); 1797 if (policyMapsIt == policyMaps.end()) 1798 { 1799 messages::propertyValueNotInList(aResp->res, policy, 1800 "PowerRestorePolicy"); 1801 return; 1802 } 1803 1804 powerRestorPolicy = policyMapsIt->second; 1805 1806 crow::connections::systemBus->async_method_call( 1807 [aResp](const boost::system::error_code ec) { 1808 if (ec) 1809 { 1810 messages::internalError(aResp->res); 1811 return; 1812 } 1813 }, 1814 "xyz.openbmc_project.Settings", 1815 "/xyz/openbmc_project/control/host0/power_restore_policy", 1816 "org.freedesktop.DBus.Properties", "Set", 1817 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1818 dbus::utility::DbusVariantType(powerRestorPolicy)); 1819 } 1820 1821 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1822 /** 1823 * @brief Retrieves provisioning status 1824 * 1825 * @param[in] aResp Shared pointer for completing asynchronous calls. 1826 * 1827 * @return None. 1828 */ 1829 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1830 { 1831 BMCWEB_LOG_DEBUG << "Get OEM information."; 1832 crow::connections::systemBus->async_method_call( 1833 [aResp](const boost::system::error_code ec, 1834 const std::vector< 1835 std::pair<std::string, dbus::utility::DbusVariantType>>& 1836 propertiesList) { 1837 nlohmann::json& oemPFR = 1838 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1839 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1840 "#OemComputerSystem.OpenBmc"; 1841 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1842 1843 if (ec) 1844 { 1845 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1846 // not an error, don't have to have the interface 1847 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1848 return; 1849 } 1850 1851 const bool* provState = nullptr; 1852 const bool* lockState = nullptr; 1853 for (const std::pair<std::string, dbus::utility::DbusVariantType>& 1854 property : propertiesList) 1855 { 1856 if (property.first == "UfmProvisioned") 1857 { 1858 provState = std::get_if<bool>(&property.second); 1859 } 1860 else if (property.first == "UfmLocked") 1861 { 1862 lockState = std::get_if<bool>(&property.second); 1863 } 1864 } 1865 1866 if ((provState == nullptr) || (lockState == nullptr)) 1867 { 1868 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1869 messages::internalError(aResp->res); 1870 return; 1871 } 1872 1873 if (*provState == true) 1874 { 1875 if (*lockState == true) 1876 { 1877 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1878 } 1879 else 1880 { 1881 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1882 } 1883 } 1884 else 1885 { 1886 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1887 } 1888 }, 1889 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1890 "org.freedesktop.DBus.Properties", "GetAll", 1891 "xyz.openbmc_project.PFR.Attributes"); 1892 } 1893 #endif 1894 1895 /** 1896 * @brief Translate the PowerMode to a response message. 1897 * 1898 * @param[in] aResp Shared pointer for generating response message. 1899 * @param[in] modeValue PowerMode value to be translated 1900 * 1901 * @return None. 1902 */ 1903 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1904 const std::string& modeValue) 1905 { 1906 std::string modeString; 1907 1908 if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 1909 { 1910 aResp->res.jsonValue["PowerMode"] = "Static"; 1911 } 1912 else if ( 1913 modeValue == 1914 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 1915 { 1916 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1917 } 1918 else if (modeValue == 1919 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 1920 { 1921 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1922 } 1923 else if (modeValue == 1924 "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 1925 { 1926 aResp->res.jsonValue["PowerMode"] = "OEM"; 1927 } 1928 else 1929 { 1930 // Any other values would be invalid 1931 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 1932 messages::internalError(aResp->res); 1933 } 1934 } 1935 1936 /** 1937 * @brief Retrieves system power mode 1938 * 1939 * @param[in] aResp Shared pointer for generating response message. 1940 * 1941 * @return None. 1942 */ 1943 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1944 { 1945 BMCWEB_LOG_DEBUG << "Get power mode."; 1946 1947 // Get Power Mode object path: 1948 crow::connections::systemBus->async_method_call( 1949 [aResp]( 1950 const boost::system::error_code ec, 1951 const std::vector<std::pair< 1952 std::string, 1953 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1954 subtree) { 1955 if (ec) 1956 { 1957 BMCWEB_LOG_DEBUG 1958 << "DBUS response error on Power.Mode GetSubTree " << ec; 1959 // This is an optional D-Bus object so just return if 1960 // error occurs 1961 return; 1962 } 1963 if (subtree.empty()) 1964 { 1965 // As noted above, this is an optional interface so just return 1966 // if there is no instance found 1967 return; 1968 } 1969 if (subtree.size() > 1) 1970 { 1971 // More then one PowerMode object is not supported and is an 1972 // error 1973 BMCWEB_LOG_DEBUG 1974 << "Found more than 1 system D-Bus Power.Mode objects: " 1975 << subtree.size(); 1976 messages::internalError(aResp->res); 1977 return; 1978 } 1979 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 1980 { 1981 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 1982 messages::internalError(aResp->res); 1983 return; 1984 } 1985 const std::string& path = subtree[0].first; 1986 const std::string& service = subtree[0].second.begin()->first; 1987 if (service.empty()) 1988 { 1989 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 1990 messages::internalError(aResp->res); 1991 return; 1992 } 1993 // Valid Power Mode object found, now read the current value 1994 sdbusplus::asio::getProperty<std::string>( 1995 *crow::connections::systemBus, service, path, 1996 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 1997 [aResp](const boost::system::error_code ec, 1998 const std::string& pmode) { 1999 if (ec) 2000 { 2001 BMCWEB_LOG_DEBUG 2002 << "DBUS response error on PowerMode Get: " << ec; 2003 messages::internalError(aResp->res); 2004 return; 2005 } 2006 2007 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 2008 {"Static", "MaximumPerformance", "PowerSaving"}; 2009 2010 BMCWEB_LOG_DEBUG << "Current power mode: " << pmode; 2011 translatePowerMode(aResp, pmode); 2012 }); 2013 }, 2014 "xyz.openbmc_project.ObjectMapper", 2015 "/xyz/openbmc_project/object_mapper", 2016 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2017 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2018 } 2019 2020 /** 2021 * @brief Validate the specified mode is valid and return the PowerMode 2022 * name associated with that string 2023 * 2024 * @param[in] aResp Shared pointer for generating response message. 2025 * @param[in] modeString String representing the desired PowerMode 2026 * 2027 * @return PowerMode value or empty string if mode is not valid 2028 */ 2029 inline std::string 2030 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2031 const std::string& modeString) 2032 { 2033 std::string mode; 2034 2035 if (modeString == "Static") 2036 { 2037 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2038 } 2039 else if (modeString == "MaximumPerformance") 2040 { 2041 mode = 2042 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2043 } 2044 else if (modeString == "PowerSaving") 2045 { 2046 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2047 } 2048 else 2049 { 2050 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2051 } 2052 return mode; 2053 } 2054 2055 /** 2056 * @brief Sets system power mode. 2057 * 2058 * @param[in] aResp Shared pointer for generating response message. 2059 * @param[in] pmode System power mode from request. 2060 * 2061 * @return None. 2062 */ 2063 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2064 const std::string& pmode) 2065 { 2066 BMCWEB_LOG_DEBUG << "Set power mode."; 2067 2068 std::string powerMode = validatePowerMode(aResp, pmode); 2069 if (powerMode.empty()) 2070 { 2071 return; 2072 } 2073 2074 // Get Power Mode object path: 2075 crow::connections::systemBus->async_method_call( 2076 [aResp, powerMode]( 2077 const boost::system::error_code ec, 2078 const std::vector<std::pair< 2079 std::string, 2080 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2081 subtree) { 2082 if (ec) 2083 { 2084 BMCWEB_LOG_DEBUG 2085 << "DBUS response error on Power.Mode GetSubTree " << ec; 2086 // This is an optional D-Bus object, but user attempted to patch 2087 messages::internalError(aResp->res); 2088 return; 2089 } 2090 if (subtree.empty()) 2091 { 2092 // This is an optional D-Bus object, but user attempted to patch 2093 messages::resourceNotFound(aResp->res, "ComputerSystem", 2094 "PowerMode"); 2095 return; 2096 } 2097 if (subtree.size() > 1) 2098 { 2099 // More then one PowerMode object is not supported and is an 2100 // error 2101 BMCWEB_LOG_DEBUG 2102 << "Found more than 1 system D-Bus Power.Mode objects: " 2103 << subtree.size(); 2104 messages::internalError(aResp->res); 2105 return; 2106 } 2107 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2108 { 2109 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2110 messages::internalError(aResp->res); 2111 return; 2112 } 2113 const std::string& path = subtree[0].first; 2114 const std::string& service = subtree[0].second.begin()->first; 2115 if (service.empty()) 2116 { 2117 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2118 messages::internalError(aResp->res); 2119 return; 2120 } 2121 2122 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2123 << path; 2124 2125 // Set the Power Mode property 2126 crow::connections::systemBus->async_method_call( 2127 [aResp](const boost::system::error_code ec) { 2128 if (ec) 2129 { 2130 messages::internalError(aResp->res); 2131 return; 2132 } 2133 }, 2134 service, path, "org.freedesktop.DBus.Properties", "Set", 2135 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2136 dbus::utility::DbusVariantType(powerMode)); 2137 }, 2138 "xyz.openbmc_project.ObjectMapper", 2139 "/xyz/openbmc_project/object_mapper", 2140 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2141 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2142 } 2143 2144 /** 2145 * @brief Translates watchdog timeout action DBUS property value to redfish. 2146 * 2147 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2148 * 2149 * @return Returns as a string, the timeout action in Redfish terms. If 2150 * translation cannot be done, returns an empty string. 2151 */ 2152 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2153 { 2154 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2155 { 2156 return "None"; 2157 } 2158 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2159 { 2160 return "ResetSystem"; 2161 } 2162 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2163 { 2164 return "PowerDown"; 2165 } 2166 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2167 { 2168 return "PowerCycle"; 2169 } 2170 2171 return ""; 2172 } 2173 2174 /** 2175 *@brief Translates timeout action from Redfish to DBUS property value. 2176 * 2177 *@param[in] rfAction The timeout action in Redfish. 2178 * 2179 *@return Returns as a string, the time_out action as expected by DBUS. 2180 *If translation cannot be done, returns an empty string. 2181 */ 2182 2183 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2184 { 2185 if (rfAction == "None") 2186 { 2187 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2188 } 2189 if (rfAction == "PowerCycle") 2190 { 2191 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2192 } 2193 if (rfAction == "PowerDown") 2194 { 2195 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2196 } 2197 if (rfAction == "ResetSystem") 2198 { 2199 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2200 } 2201 2202 return ""; 2203 } 2204 2205 /** 2206 * @brief Retrieves host watchdog timer properties over DBUS 2207 * 2208 * @param[in] aResp Shared pointer for completing asynchronous calls. 2209 * 2210 * @return None. 2211 */ 2212 inline void 2213 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2214 { 2215 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2216 crow::connections::systemBus->async_method_call( 2217 [aResp](const boost::system::error_code ec, 2218 const PropertiesType& properties) { 2219 if (ec) 2220 { 2221 // watchdog service is stopped 2222 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2223 return; 2224 } 2225 2226 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2227 2228 nlohmann::json& hostWatchdogTimer = 2229 aResp->res.jsonValue["HostWatchdogTimer"]; 2230 2231 // watchdog service is running/enabled 2232 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2233 2234 for (const auto& property : properties) 2235 { 2236 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2237 if (property.first == "Enabled") 2238 { 2239 const bool* state = std::get_if<bool>(&property.second); 2240 2241 if (!state) 2242 { 2243 messages::internalError(aResp->res); 2244 return; 2245 } 2246 2247 hostWatchdogTimer["FunctionEnabled"] = *state; 2248 } 2249 else if (property.first == "ExpireAction") 2250 { 2251 const std::string* s = 2252 std::get_if<std::string>(&property.second); 2253 if (!s) 2254 { 2255 messages::internalError(aResp->res); 2256 return; 2257 } 2258 2259 std::string action = dbusToRfWatchdogAction(*s); 2260 if (action.empty()) 2261 { 2262 messages::internalError(aResp->res); 2263 return; 2264 } 2265 hostWatchdogTimer["TimeoutAction"] = action; 2266 } 2267 } 2268 }, 2269 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2270 "org.freedesktop.DBus.Properties", "GetAll", 2271 "xyz.openbmc_project.State.Watchdog"); 2272 } 2273 2274 /** 2275 * @brief Sets Host WatchDog Timer properties. 2276 * 2277 * @param[in] aResp Shared pointer for generating response message. 2278 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2279 * RF request. 2280 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2281 * 2282 * @return None. 2283 */ 2284 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2285 const std::optional<bool> wdtEnable, 2286 const std::optional<std::string>& wdtTimeOutAction) 2287 { 2288 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2289 2290 if (wdtTimeOutAction) 2291 { 2292 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2293 // check if TimeOut Action is Valid 2294 if (wdtTimeOutActStr.empty()) 2295 { 2296 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2297 << *wdtTimeOutAction; 2298 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2299 "TimeoutAction"); 2300 return; 2301 } 2302 2303 crow::connections::systemBus->async_method_call( 2304 [aResp](const boost::system::error_code ec) { 2305 if (ec) 2306 { 2307 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2308 messages::internalError(aResp->res); 2309 return; 2310 } 2311 }, 2312 "xyz.openbmc_project.Watchdog", 2313 "/xyz/openbmc_project/watchdog/host0", 2314 "org.freedesktop.DBus.Properties", "Set", 2315 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2316 dbus::utility::DbusVariantType(wdtTimeOutActStr)); 2317 } 2318 2319 if (wdtEnable) 2320 { 2321 crow::connections::systemBus->async_method_call( 2322 [aResp](const boost::system::error_code ec) { 2323 if (ec) 2324 { 2325 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2326 messages::internalError(aResp->res); 2327 return; 2328 } 2329 }, 2330 "xyz.openbmc_project.Watchdog", 2331 "/xyz/openbmc_project/watchdog/host0", 2332 "org.freedesktop.DBus.Properties", "Set", 2333 "xyz.openbmc_project.State.Watchdog", "Enabled", 2334 dbus::utility::DbusVariantType(*wdtEnable)); 2335 } 2336 } 2337 2338 using ipsPropertiesType = 2339 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>; 2340 /** 2341 * @brief Parse the Idle Power Saver properties into json 2342 * 2343 * @param[in] aResp Shared pointer for completing asynchronous calls. 2344 * @param[in] properties IPS property data from DBus. 2345 * 2346 * @return true if successful 2347 */ 2348 inline bool parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2349 ipsPropertiesType& properties) 2350 { 2351 for (const auto& property : properties) 2352 { 2353 if (property.first == "Enabled") 2354 { 2355 const bool* state = std::get_if<bool>(&property.second); 2356 if (!state) 2357 { 2358 return false; 2359 } 2360 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state; 2361 } 2362 else if (property.first == "EnterUtilizationPercent") 2363 { 2364 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2365 if (!util) 2366 { 2367 return false; 2368 } 2369 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2370 } 2371 else if (property.first == "EnterDwellTime") 2372 { 2373 // Convert Dbus time from milliseconds to seconds 2374 const uint64_t* timeMilliseconds = 2375 std::get_if<uint64_t>(&property.second); 2376 if (!timeMilliseconds) 2377 { 2378 return false; 2379 } 2380 const std::chrono::duration<uint64_t, std::milli> ms( 2381 *timeMilliseconds); 2382 aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2383 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2384 .count(); 2385 } 2386 else if (property.first == "ExitUtilizationPercent") 2387 { 2388 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2389 if (!util) 2390 { 2391 return false; 2392 } 2393 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2394 } 2395 else if (property.first == "ExitDwellTime") 2396 { 2397 // Convert Dbus time from milliseconds to seconds 2398 const uint64_t* timeMilliseconds = 2399 std::get_if<uint64_t>(&property.second); 2400 if (!timeMilliseconds) 2401 { 2402 return false; 2403 } 2404 const std::chrono::duration<uint64_t, std::milli> ms( 2405 *timeMilliseconds); 2406 aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2407 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2408 .count(); 2409 } 2410 else 2411 { 2412 BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: " 2413 << property.first; 2414 } 2415 } 2416 2417 return true; 2418 } 2419 2420 /** 2421 * @brief Retrieves host watchdog timer properties over DBUS 2422 * 2423 * @param[in] aResp Shared pointer for completing asynchronous calls. 2424 * 2425 * @return None. 2426 */ 2427 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2428 { 2429 BMCWEB_LOG_DEBUG << "Get idle power saver parameters"; 2430 2431 // Get IdlePowerSaver object path: 2432 crow::connections::systemBus->async_method_call( 2433 [aResp]( 2434 const boost::system::error_code ec, 2435 const std::vector<std::pair< 2436 std::string, 2437 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2438 subtree) { 2439 if (ec) 2440 { 2441 BMCWEB_LOG_DEBUG 2442 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2443 << ec; 2444 messages::internalError(aResp->res); 2445 return; 2446 } 2447 if (subtree.empty()) 2448 { 2449 // This is an optional interface so just return 2450 // if there is no instance found 2451 BMCWEB_LOG_DEBUG << "No instances found"; 2452 return; 2453 } 2454 if (subtree.size() > 1) 2455 { 2456 // More then one PowerIdlePowerSaver object is not supported and 2457 // is an error 2458 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus " 2459 "Power.IdlePowerSaver objects: " 2460 << subtree.size(); 2461 messages::internalError(aResp->res); 2462 return; 2463 } 2464 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2465 { 2466 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2467 messages::internalError(aResp->res); 2468 return; 2469 } 2470 const std::string& path = subtree[0].first; 2471 const std::string& service = subtree[0].second.begin()->first; 2472 if (service.empty()) 2473 { 2474 BMCWEB_LOG_DEBUG 2475 << "Power.IdlePowerSaver service mapper error!"; 2476 messages::internalError(aResp->res); 2477 return; 2478 } 2479 2480 // Valid IdlePowerSaver object found, now read the current values 2481 crow::connections::systemBus->async_method_call( 2482 [aResp](const boost::system::error_code ec, 2483 ipsPropertiesType& properties) { 2484 if (ec) 2485 { 2486 BMCWEB_LOG_ERROR 2487 << "DBUS response error on IdlePowerSaver GetAll: " 2488 << ec; 2489 messages::internalError(aResp->res); 2490 return; 2491 } 2492 2493 if (parseIpsProperties(aResp, properties) == false) 2494 { 2495 messages::internalError(aResp->res); 2496 return; 2497 } 2498 }, 2499 service, path, "org.freedesktop.DBus.Properties", "GetAll", 2500 "xyz.openbmc_project.Control.Power.IdlePowerSaver"); 2501 }, 2502 "xyz.openbmc_project.ObjectMapper", 2503 "/xyz/openbmc_project/object_mapper", 2504 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2505 std::array<const char*, 1>{ 2506 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2507 2508 BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters"; 2509 } 2510 2511 /** 2512 * @brief Sets Idle Power Saver properties. 2513 * 2514 * @param[in] aResp Shared pointer for generating response message. 2515 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2516 * RF request. 2517 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2518 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2519 * before entering idle state. 2520 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2521 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2522 * before exiting idle state 2523 * 2524 * @return None. 2525 */ 2526 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2527 const std::optional<bool> ipsEnable, 2528 const std::optional<uint8_t> ipsEnterUtil, 2529 const std::optional<uint64_t> ipsEnterTime, 2530 const std::optional<uint8_t> ipsExitUtil, 2531 const std::optional<uint64_t> ipsExitTime) 2532 { 2533 BMCWEB_LOG_DEBUG << "Set idle power saver properties"; 2534 2535 // Get IdlePowerSaver object path: 2536 crow::connections::systemBus->async_method_call( 2537 [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2538 ipsExitTime]( 2539 const boost::system::error_code ec, 2540 const std::vector<std::pair< 2541 std::string, 2542 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2543 subtree) { 2544 if (ec) 2545 { 2546 BMCWEB_LOG_DEBUG 2547 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2548 << ec; 2549 messages::internalError(aResp->res); 2550 return; 2551 } 2552 if (subtree.empty()) 2553 { 2554 // This is an optional D-Bus object, but user attempted to patch 2555 messages::resourceNotFound(aResp->res, "ComputerSystem", 2556 "IdlePowerSaver"); 2557 return; 2558 } 2559 if (subtree.size() > 1) 2560 { 2561 // More then one PowerIdlePowerSaver object is not supported and 2562 // is an error 2563 BMCWEB_LOG_DEBUG 2564 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: " 2565 << subtree.size(); 2566 messages::internalError(aResp->res); 2567 return; 2568 } 2569 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2570 { 2571 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2572 messages::internalError(aResp->res); 2573 return; 2574 } 2575 const std::string& path = subtree[0].first; 2576 const std::string& service = subtree[0].second.begin()->first; 2577 if (service.empty()) 2578 { 2579 BMCWEB_LOG_DEBUG 2580 << "Power.IdlePowerSaver service mapper error!"; 2581 messages::internalError(aResp->res); 2582 return; 2583 } 2584 2585 // Valid Power IdlePowerSaver object found, now set any values that 2586 // need to be updated 2587 2588 if (ipsEnable) 2589 { 2590 crow::connections::systemBus->async_method_call( 2591 [aResp](const boost::system::error_code ec) { 2592 if (ec) 2593 { 2594 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2595 messages::internalError(aResp->res); 2596 return; 2597 } 2598 }, 2599 service, path, "org.freedesktop.DBus.Properties", "Set", 2600 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2601 "Enabled", dbus::utility::DbusVariantType(*ipsEnable)); 2602 } 2603 if (ipsEnterUtil) 2604 { 2605 crow::connections::systemBus->async_method_call( 2606 [aResp](const boost::system::error_code ec) { 2607 if (ec) 2608 { 2609 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2610 messages::internalError(aResp->res); 2611 return; 2612 } 2613 }, 2614 service, path, "org.freedesktop.DBus.Properties", "Set", 2615 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2616 "EnterUtilizationPercent", 2617 dbus::utility::DbusVariantType(*ipsEnterUtil)); 2618 } 2619 if (ipsEnterTime) 2620 { 2621 // Convert from seconds into milliseconds for DBus 2622 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2623 crow::connections::systemBus->async_method_call( 2624 [aResp](const boost::system::error_code ec) { 2625 if (ec) 2626 { 2627 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2628 messages::internalError(aResp->res); 2629 return; 2630 } 2631 }, 2632 service, path, "org.freedesktop.DBus.Properties", "Set", 2633 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2634 "EnterDwellTime", 2635 dbus::utility::DbusVariantType(timeMilliseconds)); 2636 } 2637 if (ipsExitUtil) 2638 { 2639 crow::connections::systemBus->async_method_call( 2640 [aResp](const boost::system::error_code ec) { 2641 if (ec) 2642 { 2643 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2644 messages::internalError(aResp->res); 2645 return; 2646 } 2647 }, 2648 service, path, "org.freedesktop.DBus.Properties", "Set", 2649 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2650 "ExitUtilizationPercent", 2651 dbus::utility::DbusVariantType(*ipsExitUtil)); 2652 } 2653 if (ipsExitTime) 2654 { 2655 // Convert from seconds into milliseconds for DBus 2656 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2657 crow::connections::systemBus->async_method_call( 2658 [aResp](const boost::system::error_code ec) { 2659 if (ec) 2660 { 2661 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2662 messages::internalError(aResp->res); 2663 return; 2664 } 2665 }, 2666 service, path, "org.freedesktop.DBus.Properties", "Set", 2667 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2668 "ExitDwellTime", 2669 dbus::utility::DbusVariantType(timeMilliseconds)); 2670 } 2671 }, 2672 "xyz.openbmc_project.ObjectMapper", 2673 "/xyz/openbmc_project/object_mapper", 2674 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2675 std::array<const char*, 1>{ 2676 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2677 2678 BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters"; 2679 } 2680 2681 /** 2682 * SystemsCollection derived class for delivering ComputerSystems Collection 2683 * Schema 2684 */ 2685 inline void requestRoutesSystemsCollection(App& app) 2686 { 2687 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2688 .privileges(redfish::privileges::getComputerSystemCollection) 2689 .methods(boost::beast::http::verb::get)( 2690 [](const crow::Request& /*req*/, 2691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2692 asyncResp->res.jsonValue["@odata.type"] = 2693 "#ComputerSystemCollection.ComputerSystemCollection"; 2694 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2695 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2696 2697 sdbusplus::asio::getProperty<std::string>( 2698 *crow::connections::systemBus, 2699 "xyz.openbmc_project.Settings", 2700 "/xyz/openbmc_project/network/hypervisor", 2701 "xyz.openbmc_project.Network.SystemConfiguration", 2702 "HostName", 2703 [asyncResp](const boost::system::error_code ec, 2704 const std::string& /*hostName*/) { 2705 nlohmann::json& ifaceArray = 2706 asyncResp->res.jsonValue["Members"]; 2707 ifaceArray = nlohmann::json::array(); 2708 auto& count = 2709 asyncResp->res.jsonValue["Members@odata.count"]; 2710 ifaceArray.push_back( 2711 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2712 count = ifaceArray.size(); 2713 if (!ec) 2714 { 2715 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2716 ifaceArray.push_back( 2717 {{"@odata.id", 2718 "/redfish/v1/Systems/hypervisor"}}); 2719 count = ifaceArray.size(); 2720 } 2721 }); 2722 }); 2723 } 2724 2725 /** 2726 * Function transceives data with dbus directly. 2727 */ 2728 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2729 { 2730 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2731 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2732 constexpr char const* interfaceName = 2733 "xyz.openbmc_project.Control.Host.NMI"; 2734 constexpr char const* method = "NMI"; 2735 2736 crow::connections::systemBus->async_method_call( 2737 [asyncResp](const boost::system::error_code ec) { 2738 if (ec) 2739 { 2740 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2741 messages::internalError(asyncResp->res); 2742 return; 2743 } 2744 messages::success(asyncResp->res); 2745 }, 2746 serviceName, objectPath, interfaceName, method); 2747 } 2748 2749 /** 2750 * SystemActionsReset class supports handle POST method for Reset action. 2751 * The class retrieves and sends data directly to D-Bus. 2752 */ 2753 inline void requestRoutesSystemActionsReset(App& app) 2754 { 2755 /** 2756 * Function handles POST method request. 2757 * Analyzes POST body message before sends Reset request data to D-Bus. 2758 */ 2759 BMCWEB_ROUTE(app, 2760 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2761 .privileges(redfish::privileges::postComputerSystem) 2762 .methods( 2763 boost::beast::http::verb:: 2764 post)([](const crow::Request& req, 2765 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2766 std::string resetType; 2767 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2768 resetType)) 2769 { 2770 return; 2771 } 2772 2773 // Get the command and host vs. chassis 2774 std::string command; 2775 bool hostCommand = true; 2776 if ((resetType == "On") || (resetType == "ForceOn")) 2777 { 2778 command = "xyz.openbmc_project.State.Host.Transition.On"; 2779 hostCommand = true; 2780 } 2781 else if (resetType == "ForceOff") 2782 { 2783 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2784 hostCommand = false; 2785 } 2786 else if (resetType == "ForceRestart") 2787 { 2788 command = 2789 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2790 hostCommand = true; 2791 } 2792 else if (resetType == "GracefulShutdown") 2793 { 2794 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2795 hostCommand = true; 2796 } 2797 else if (resetType == "GracefulRestart") 2798 { 2799 command = 2800 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2801 hostCommand = true; 2802 } 2803 else if (resetType == "PowerCycle") 2804 { 2805 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2806 hostCommand = true; 2807 } 2808 else if (resetType == "Nmi") 2809 { 2810 doNMI(asyncResp); 2811 return; 2812 } 2813 else 2814 { 2815 messages::actionParameterUnknown(asyncResp->res, "Reset", 2816 resetType); 2817 return; 2818 } 2819 2820 if (hostCommand) 2821 { 2822 crow::connections::systemBus->async_method_call( 2823 [asyncResp, resetType](const boost::system::error_code ec) { 2824 if (ec) 2825 { 2826 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2827 if (ec.value() == 2828 boost::asio::error::invalid_argument) 2829 { 2830 messages::actionParameterNotSupported( 2831 asyncResp->res, resetType, "Reset"); 2832 } 2833 else 2834 { 2835 messages::internalError(asyncResp->res); 2836 } 2837 return; 2838 } 2839 messages::success(asyncResp->res); 2840 }, 2841 "xyz.openbmc_project.State.Host", 2842 "/xyz/openbmc_project/state/host0", 2843 "org.freedesktop.DBus.Properties", "Set", 2844 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2845 dbus::utility::DbusVariantType{command}); 2846 } 2847 else 2848 { 2849 crow::connections::systemBus->async_method_call( 2850 [asyncResp, resetType](const boost::system::error_code ec) { 2851 if (ec) 2852 { 2853 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2854 if (ec.value() == 2855 boost::asio::error::invalid_argument) 2856 { 2857 messages::actionParameterNotSupported( 2858 asyncResp->res, resetType, "Reset"); 2859 } 2860 else 2861 { 2862 messages::internalError(asyncResp->res); 2863 } 2864 return; 2865 } 2866 messages::success(asyncResp->res); 2867 }, 2868 "xyz.openbmc_project.State.Chassis", 2869 "/xyz/openbmc_project/state/chassis0", 2870 "org.freedesktop.DBus.Properties", "Set", 2871 "xyz.openbmc_project.State.Chassis", 2872 "RequestedPowerTransition", 2873 dbus::utility::DbusVariantType{command}); 2874 } 2875 }); 2876 } 2877 2878 /** 2879 * Systems derived class for delivering Computer Systems Schema. 2880 */ 2881 inline void requestRoutesSystems(App& app) 2882 { 2883 2884 /** 2885 * Functions triggers appropriate requests on DBus 2886 */ 2887 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2888 .privileges(redfish::privileges::getComputerSystem) 2889 .methods( 2890 boost::beast::http::verb:: 2891 get)([](const crow::Request&, 2892 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2893 asyncResp->res.jsonValue["@odata.type"] = 2894 "#ComputerSystem.v1_16_0.ComputerSystem"; 2895 asyncResp->res.jsonValue["Name"] = "system"; 2896 asyncResp->res.jsonValue["Id"] = "system"; 2897 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2898 asyncResp->res.jsonValue["Description"] = "Computer System"; 2899 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2900 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2901 "Disabled"; 2902 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2903 uint64_t(0); 2904 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2905 "Disabled"; 2906 asyncResp->res.jsonValue["@odata.id"] = 2907 "/redfish/v1/Systems/system"; 2908 2909 asyncResp->res.jsonValue["Processors"] = { 2910 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2911 asyncResp->res.jsonValue["Memory"] = { 2912 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2913 asyncResp->res.jsonValue["Storage"] = { 2914 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2915 2916 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2917 {"target", 2918 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2919 {"@Redfish.ActionInfo", 2920 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2921 2922 asyncResp->res.jsonValue["LogServices"] = { 2923 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2924 2925 asyncResp->res.jsonValue["Bios"] = { 2926 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2927 2928 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2929 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2930 2931 asyncResp->res.jsonValue["Status"] = { 2932 {"Health", "OK"}, 2933 {"State", "Enabled"}, 2934 }; 2935 2936 // Fill in SerialConsole info 2937 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2938 15; 2939 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2940 {"ServiceEnabled", true}, 2941 }; 2942 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2943 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2944 {"ServiceEnabled", true}, 2945 {"Port", 2200}, 2946 // https://github.com/openbmc/docs/blob/master/console.md 2947 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2948 }; 2949 2950 #ifdef BMCWEB_ENABLE_KVM 2951 // Fill in GraphicalConsole info 2952 asyncResp->res.jsonValue["GraphicalConsole"] = { 2953 {"ServiceEnabled", true}, 2954 {"MaxConcurrentSessions", 4}, 2955 {"ConnectTypesSupported", {"KVMIP"}}, 2956 }; 2957 #endif // BMCWEB_ENABLE_KVM 2958 constexpr const std::array<const char*, 4> inventoryForSystems = { 2959 "xyz.openbmc_project.Inventory.Item.Dimm", 2960 "xyz.openbmc_project.Inventory.Item.Cpu", 2961 "xyz.openbmc_project.Inventory.Item.Drive", 2962 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2963 2964 auto health = std::make_shared<HealthPopulate>(asyncResp); 2965 crow::connections::systemBus->async_method_call( 2966 [health](const boost::system::error_code ec, 2967 const std::vector<std::string>& resp) { 2968 if (ec) 2969 { 2970 // no inventory 2971 return; 2972 } 2973 2974 health->inventory = resp; 2975 }, 2976 "xyz.openbmc_project.ObjectMapper", 2977 "/xyz/openbmc_project/object_mapper", 2978 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2979 int32_t(0), inventoryForSystems); 2980 2981 health->populate(); 2982 2983 getMainChassisId( 2984 asyncResp, [](const std::string& chassisId, 2985 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2986 aRsp->res.jsonValue["Links"]["Chassis"] = { 2987 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2988 }); 2989 2990 getLocationIndicatorActive(asyncResp); 2991 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2992 getIndicatorLedState(asyncResp); 2993 getComputerSystem(asyncResp, health); 2994 getHostState(asyncResp); 2995 getBootProperties(asyncResp); 2996 getBootProgress(asyncResp); 2997 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2998 getHostWatchdogTimer(asyncResp); 2999 getPowerRestorePolicy(asyncResp); 3000 getAutomaticRetry(asyncResp); 3001 getLastResetTime(asyncResp); 3002 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 3003 getProvisioningStatus(asyncResp); 3004 #endif 3005 getTrustedModuleRequiredToBoot(asyncResp); 3006 getPowerMode(asyncResp); 3007 getIdlePowerSaver(asyncResp); 3008 }); 3009 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 3010 .privileges(redfish::privileges::patchComputerSystem) 3011 .methods(boost::beast::http::verb::patch)( 3012 [](const crow::Request& req, 3013 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3014 std::optional<bool> locationIndicatorActive; 3015 std::optional<std::string> indicatorLed; 3016 std::optional<nlohmann::json> bootProps; 3017 std::optional<nlohmann::json> wdtTimerProps; 3018 std::optional<std::string> assetTag; 3019 std::optional<std::string> powerRestorePolicy; 3020 std::optional<std::string> powerMode; 3021 std::optional<nlohmann::json> ipsProps; 3022 if (!json_util::readJson( 3023 req, asyncResp->res, "IndicatorLED", indicatorLed, 3024 "LocationIndicatorActive", locationIndicatorActive, 3025 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 3026 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 3027 assetTag, "PowerMode", powerMode, "IdlePowerSaver", 3028 ipsProps)) 3029 { 3030 return; 3031 } 3032 3033 asyncResp->res.result(boost::beast::http::status::no_content); 3034 3035 if (assetTag) 3036 { 3037 setAssetTag(asyncResp, *assetTag); 3038 } 3039 3040 if (wdtTimerProps) 3041 { 3042 std::optional<bool> wdtEnable; 3043 std::optional<std::string> wdtTimeOutAction; 3044 3045 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 3046 "FunctionEnabled", wdtEnable, 3047 "TimeoutAction", wdtTimeOutAction)) 3048 { 3049 return; 3050 } 3051 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3052 } 3053 3054 if (bootProps) 3055 { 3056 std::optional<std::string> bootSource; 3057 std::optional<std::string> bootType; 3058 std::optional<std::string> bootEnable; 3059 std::optional<std::string> automaticRetryConfig; 3060 std::optional<bool> trustedModuleRequiredToBoot; 3061 3062 if (!json_util::readJson( 3063 *bootProps, asyncResp->res, 3064 "BootSourceOverrideTarget", bootSource, 3065 "BootSourceOverrideMode", bootType, 3066 "BootSourceOverrideEnabled", bootEnable, 3067 "AutomaticRetryConfig", automaticRetryConfig, 3068 "TrustedModuleRequiredToBoot", 3069 trustedModuleRequiredToBoot)) 3070 { 3071 return; 3072 } 3073 3074 if (bootSource || bootType || bootEnable) 3075 { 3076 setBootProperties(asyncResp, bootSource, bootType, 3077 bootEnable); 3078 } 3079 if (automaticRetryConfig) 3080 { 3081 setAutomaticRetry(asyncResp, *automaticRetryConfig); 3082 } 3083 3084 if (trustedModuleRequiredToBoot) 3085 { 3086 setTrustedModuleRequiredToBoot( 3087 asyncResp, *trustedModuleRequiredToBoot); 3088 } 3089 } 3090 3091 if (locationIndicatorActive) 3092 { 3093 setLocationIndicatorActive(asyncResp, 3094 *locationIndicatorActive); 3095 } 3096 3097 // TODO (Gunnar): Remove IndicatorLED after enough time has 3098 // passed 3099 if (indicatorLed) 3100 { 3101 setIndicatorLedState(asyncResp, *indicatorLed); 3102 asyncResp->res.addHeader( 3103 boost::beast::http::field::warning, 3104 "299 - \"IndicatorLED is deprecated. Use " 3105 "LocationIndicatorActive instead.\""); 3106 } 3107 3108 if (powerRestorePolicy) 3109 { 3110 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3111 } 3112 3113 if (powerMode) 3114 { 3115 setPowerMode(asyncResp, *powerMode); 3116 } 3117 3118 if (ipsProps) 3119 { 3120 std::optional<bool> ipsEnable; 3121 std::optional<uint8_t> ipsEnterUtil; 3122 std::optional<uint64_t> ipsEnterTime; 3123 std::optional<uint8_t> ipsExitUtil; 3124 std::optional<uint64_t> ipsExitTime; 3125 3126 if (!json_util::readJson( 3127 *ipsProps, asyncResp->res, "Enabled", ipsEnable, 3128 "EnterUtilizationPercent", ipsEnterUtil, 3129 "EnterDwellTimeSeconds", ipsEnterTime, 3130 "ExitUtilizationPercent", ipsExitUtil, 3131 "ExitDwellTimeSeconds", ipsExitTime)) 3132 { 3133 return; 3134 } 3135 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, 3136 ipsEnterTime, ipsExitUtil, ipsExitTime); 3137 } 3138 }); 3139 } 3140 3141 /** 3142 * SystemResetActionInfo derived class for delivering Computer Systems 3143 * ResetType AllowableValues using ResetInfo schema. 3144 */ 3145 inline void requestRoutesSystemResetActionInfo(App& app) 3146 { 3147 3148 /** 3149 * Functions triggers appropriate requests on DBus 3150 */ 3151 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 3152 .privileges(redfish::privileges::getActionInfo) 3153 .methods(boost::beast::http::verb::get)( 3154 [](const crow::Request&, 3155 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3156 asyncResp->res.jsonValue = { 3157 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 3158 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 3159 {"Name", "Reset Action Info"}, 3160 {"Id", "ResetActionInfo"}, 3161 {"Parameters", 3162 {{{"Name", "ResetType"}, 3163 {"Required", true}, 3164 {"DataType", "String"}, 3165 {"AllowableValues", 3166 {"On", "ForceOff", "ForceOn", "ForceRestart", 3167 "GracefulRestart", "GracefulShutdown", "PowerCycle", 3168 "Nmi"}}}}}}; 3169 }); 3170 } 3171 } // namespace redfish 3172