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