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 const 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 = false; 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< 1828 std::pair<std::string, dbus::utility::DbusVariantType>>& 1829 propertiesList) { 1830 nlohmann::json& oemPFR = 1831 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1832 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1833 "#OemComputerSystem.OpenBmc"; 1834 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1835 1836 if (ec) 1837 { 1838 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1839 // not an error, don't have to have the interface 1840 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1841 return; 1842 } 1843 1844 const bool* provState = nullptr; 1845 const bool* lockState = nullptr; 1846 for (const std::pair<std::string, dbus::utility::DbusVariantType>& 1847 property : propertiesList) 1848 { 1849 if (property.first == "UfmProvisioned") 1850 { 1851 provState = std::get_if<bool>(&property.second); 1852 } 1853 else if (property.first == "UfmLocked") 1854 { 1855 lockState = std::get_if<bool>(&property.second); 1856 } 1857 } 1858 1859 if ((provState == nullptr) || (lockState == nullptr)) 1860 { 1861 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1862 messages::internalError(aResp->res); 1863 return; 1864 } 1865 1866 if (*provState == true) 1867 { 1868 if (*lockState == true) 1869 { 1870 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1871 } 1872 else 1873 { 1874 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1875 } 1876 } 1877 else 1878 { 1879 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1880 } 1881 }, 1882 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1883 "org.freedesktop.DBus.Properties", "GetAll", 1884 "xyz.openbmc_project.PFR.Attributes"); 1885 } 1886 #endif 1887 1888 /** 1889 * @brief Translate the PowerMode to a response message. 1890 * 1891 * @param[in] aResp Shared pointer for generating response message. 1892 * @param[in] modeValue PowerMode value to be translated 1893 * 1894 * @return None. 1895 */ 1896 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1897 const std::string& modeValue) 1898 { 1899 std::string modeString; 1900 1901 if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 1902 { 1903 aResp->res.jsonValue["PowerMode"] = "Static"; 1904 } 1905 else if ( 1906 modeValue == 1907 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 1908 { 1909 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1910 } 1911 else if (modeValue == 1912 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 1913 { 1914 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1915 } 1916 else if (modeValue == 1917 "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 1918 { 1919 aResp->res.jsonValue["PowerMode"] = "OEM"; 1920 } 1921 else 1922 { 1923 // Any other values would be invalid 1924 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 1925 messages::internalError(aResp->res); 1926 } 1927 } 1928 1929 /** 1930 * @brief Retrieves system power mode 1931 * 1932 * @param[in] aResp Shared pointer for generating response message. 1933 * 1934 * @return None. 1935 */ 1936 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1937 { 1938 BMCWEB_LOG_DEBUG << "Get power mode."; 1939 1940 // Get Power Mode object path: 1941 crow::connections::systemBus->async_method_call( 1942 [aResp]( 1943 const boost::system::error_code ec, 1944 const std::vector<std::pair< 1945 std::string, 1946 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1947 subtree) { 1948 if (ec) 1949 { 1950 BMCWEB_LOG_DEBUG 1951 << "DBUS response error on Power.Mode GetSubTree " << ec; 1952 // This is an optional D-Bus object so just return if 1953 // error occurs 1954 return; 1955 } 1956 if (subtree.empty()) 1957 { 1958 // As noted above, this is an optional interface so just return 1959 // if there is no instance found 1960 return; 1961 } 1962 if (subtree.size() > 1) 1963 { 1964 // More then one PowerMode object is not supported and is an 1965 // error 1966 BMCWEB_LOG_DEBUG 1967 << "Found more than 1 system D-Bus Power.Mode objects: " 1968 << subtree.size(); 1969 messages::internalError(aResp->res); 1970 return; 1971 } 1972 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 1973 { 1974 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 1975 messages::internalError(aResp->res); 1976 return; 1977 } 1978 const std::string& path = subtree[0].first; 1979 const std::string& service = subtree[0].second.begin()->first; 1980 if (service.empty()) 1981 { 1982 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 1983 messages::internalError(aResp->res); 1984 return; 1985 } 1986 // Valid Power Mode object found, now read the current value 1987 sdbusplus::asio::getProperty<std::string>( 1988 *crow::connections::systemBus, service, path, 1989 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 1990 [aResp](const boost::system::error_code ec, 1991 const std::string& pmode) { 1992 if (ec) 1993 { 1994 BMCWEB_LOG_DEBUG 1995 << "DBUS response error on PowerMode Get: " << ec; 1996 messages::internalError(aResp->res); 1997 return; 1998 } 1999 2000 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 2001 {"Static", "MaximumPerformance", "PowerSaving"}; 2002 2003 BMCWEB_LOG_DEBUG << "Current power mode: " << pmode; 2004 translatePowerMode(aResp, pmode); 2005 }); 2006 }, 2007 "xyz.openbmc_project.ObjectMapper", 2008 "/xyz/openbmc_project/object_mapper", 2009 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2010 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2011 } 2012 2013 /** 2014 * @brief Validate the specified mode is valid and return the PowerMode 2015 * name associated with that string 2016 * 2017 * @param[in] aResp Shared pointer for generating response message. 2018 * @param[in] modeString String representing the desired PowerMode 2019 * 2020 * @return PowerMode value or empty string if mode is not valid 2021 */ 2022 inline std::string 2023 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2024 const std::string& modeString) 2025 { 2026 std::string mode; 2027 2028 if (modeString == "Static") 2029 { 2030 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2031 } 2032 else if (modeString == "MaximumPerformance") 2033 { 2034 mode = 2035 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2036 } 2037 else if (modeString == "PowerSaving") 2038 { 2039 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2040 } 2041 else 2042 { 2043 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2044 } 2045 return mode; 2046 } 2047 2048 /** 2049 * @brief Sets system power mode. 2050 * 2051 * @param[in] aResp Shared pointer for generating response message. 2052 * @param[in] pmode System power mode from request. 2053 * 2054 * @return None. 2055 */ 2056 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2057 const std::string& pmode) 2058 { 2059 BMCWEB_LOG_DEBUG << "Set power mode."; 2060 2061 std::string powerMode = validatePowerMode(aResp, pmode); 2062 if (powerMode.empty()) 2063 { 2064 return; 2065 } 2066 2067 // Get Power Mode object path: 2068 crow::connections::systemBus->async_method_call( 2069 [aResp, powerMode]( 2070 const boost::system::error_code ec, 2071 const std::vector<std::pair< 2072 std::string, 2073 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2074 subtree) { 2075 if (ec) 2076 { 2077 BMCWEB_LOG_DEBUG 2078 << "DBUS response error on Power.Mode GetSubTree " << ec; 2079 // This is an optional D-Bus object, but user attempted to patch 2080 messages::internalError(aResp->res); 2081 return; 2082 } 2083 if (subtree.empty()) 2084 { 2085 // This is an optional D-Bus object, but user attempted to patch 2086 messages::resourceNotFound(aResp->res, "ComputerSystem", 2087 "PowerMode"); 2088 return; 2089 } 2090 if (subtree.size() > 1) 2091 { 2092 // More then one PowerMode object is not supported and is an 2093 // error 2094 BMCWEB_LOG_DEBUG 2095 << "Found more than 1 system D-Bus Power.Mode objects: " 2096 << subtree.size(); 2097 messages::internalError(aResp->res); 2098 return; 2099 } 2100 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2101 { 2102 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2103 messages::internalError(aResp->res); 2104 return; 2105 } 2106 const std::string& path = subtree[0].first; 2107 const std::string& service = subtree[0].second.begin()->first; 2108 if (service.empty()) 2109 { 2110 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2111 messages::internalError(aResp->res); 2112 return; 2113 } 2114 2115 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2116 << path; 2117 2118 // Set the Power Mode property 2119 crow::connections::systemBus->async_method_call( 2120 [aResp](const boost::system::error_code ec) { 2121 if (ec) 2122 { 2123 messages::internalError(aResp->res); 2124 return; 2125 } 2126 }, 2127 service, path, "org.freedesktop.DBus.Properties", "Set", 2128 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2129 dbus::utility::DbusVariantType(powerMode)); 2130 }, 2131 "xyz.openbmc_project.ObjectMapper", 2132 "/xyz/openbmc_project/object_mapper", 2133 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2134 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2135 } 2136 2137 /** 2138 * @brief Translates watchdog timeout action DBUS property value to redfish. 2139 * 2140 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2141 * 2142 * @return Returns as a string, the timeout action in Redfish terms. If 2143 * translation cannot be done, returns an empty string. 2144 */ 2145 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2146 { 2147 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2148 { 2149 return "None"; 2150 } 2151 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2152 { 2153 return "ResetSystem"; 2154 } 2155 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2156 { 2157 return "PowerDown"; 2158 } 2159 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2160 { 2161 return "PowerCycle"; 2162 } 2163 2164 return ""; 2165 } 2166 2167 /** 2168 *@brief Translates timeout action from Redfish to DBUS property value. 2169 * 2170 *@param[in] rfAction The timeout action in Redfish. 2171 * 2172 *@return Returns as a string, the time_out action as expected by DBUS. 2173 *If translation cannot be done, returns an empty string. 2174 */ 2175 2176 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2177 { 2178 if (rfAction == "None") 2179 { 2180 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2181 } 2182 if (rfAction == "PowerCycle") 2183 { 2184 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2185 } 2186 if (rfAction == "PowerDown") 2187 { 2188 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2189 } 2190 if (rfAction == "ResetSystem") 2191 { 2192 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2193 } 2194 2195 return ""; 2196 } 2197 2198 /** 2199 * @brief Retrieves host watchdog timer properties over DBUS 2200 * 2201 * @param[in] aResp Shared pointer for completing asynchronous calls. 2202 * 2203 * @return None. 2204 */ 2205 inline void 2206 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2207 { 2208 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2209 crow::connections::systemBus->async_method_call( 2210 [aResp](const boost::system::error_code ec, 2211 const PropertiesType& properties) { 2212 if (ec) 2213 { 2214 // watchdog service is stopped 2215 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2216 return; 2217 } 2218 2219 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2220 2221 nlohmann::json& hostWatchdogTimer = 2222 aResp->res.jsonValue["HostWatchdogTimer"]; 2223 2224 // watchdog service is running/enabled 2225 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2226 2227 for (const auto& property : properties) 2228 { 2229 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2230 if (property.first == "Enabled") 2231 { 2232 const bool* state = std::get_if<bool>(&property.second); 2233 2234 if (!state) 2235 { 2236 messages::internalError(aResp->res); 2237 return; 2238 } 2239 2240 hostWatchdogTimer["FunctionEnabled"] = *state; 2241 } 2242 else if (property.first == "ExpireAction") 2243 { 2244 const std::string* s = 2245 std::get_if<std::string>(&property.second); 2246 if (!s) 2247 { 2248 messages::internalError(aResp->res); 2249 return; 2250 } 2251 2252 std::string action = dbusToRfWatchdogAction(*s); 2253 if (action.empty()) 2254 { 2255 messages::internalError(aResp->res); 2256 return; 2257 } 2258 hostWatchdogTimer["TimeoutAction"] = action; 2259 } 2260 } 2261 }, 2262 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2263 "org.freedesktop.DBus.Properties", "GetAll", 2264 "xyz.openbmc_project.State.Watchdog"); 2265 } 2266 2267 /** 2268 * @brief Sets Host WatchDog Timer properties. 2269 * 2270 * @param[in] aResp Shared pointer for generating response message. 2271 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2272 * RF request. 2273 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2274 * 2275 * @return None. 2276 */ 2277 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2278 const std::optional<bool> wdtEnable, 2279 const std::optional<std::string>& wdtTimeOutAction) 2280 { 2281 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2282 2283 if (wdtTimeOutAction) 2284 { 2285 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2286 // check if TimeOut Action is Valid 2287 if (wdtTimeOutActStr.empty()) 2288 { 2289 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2290 << *wdtTimeOutAction; 2291 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2292 "TimeoutAction"); 2293 return; 2294 } 2295 2296 crow::connections::systemBus->async_method_call( 2297 [aResp](const boost::system::error_code ec) { 2298 if (ec) 2299 { 2300 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2301 messages::internalError(aResp->res); 2302 return; 2303 } 2304 }, 2305 "xyz.openbmc_project.Watchdog", 2306 "/xyz/openbmc_project/watchdog/host0", 2307 "org.freedesktop.DBus.Properties", "Set", 2308 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2309 dbus::utility::DbusVariantType(wdtTimeOutActStr)); 2310 } 2311 2312 if (wdtEnable) 2313 { 2314 crow::connections::systemBus->async_method_call( 2315 [aResp](const boost::system::error_code ec) { 2316 if (ec) 2317 { 2318 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2319 messages::internalError(aResp->res); 2320 return; 2321 } 2322 }, 2323 "xyz.openbmc_project.Watchdog", 2324 "/xyz/openbmc_project/watchdog/host0", 2325 "org.freedesktop.DBus.Properties", "Set", 2326 "xyz.openbmc_project.State.Watchdog", "Enabled", 2327 dbus::utility::DbusVariantType(*wdtEnable)); 2328 } 2329 } 2330 2331 using ipsPropertiesType = 2332 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>; 2333 /** 2334 * @brief Parse the Idle Power Saver properties into json 2335 * 2336 * @param[in] aResp Shared pointer for completing asynchronous calls. 2337 * @param[in] properties IPS property data from DBus. 2338 * 2339 * @return true if successful 2340 */ 2341 inline bool parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2342 ipsPropertiesType& properties) 2343 { 2344 for (const auto& property : properties) 2345 { 2346 if (property.first == "Enabled") 2347 { 2348 const bool* state = std::get_if<bool>(&property.second); 2349 if (!state) 2350 { 2351 return false; 2352 } 2353 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state; 2354 } 2355 else if (property.first == "EnterUtilizationPercent") 2356 { 2357 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2358 if (!util) 2359 { 2360 return false; 2361 } 2362 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2363 } 2364 else if (property.first == "EnterDwellTime") 2365 { 2366 // Convert Dbus time from milliseconds to seconds 2367 const uint64_t* timeMilliseconds = 2368 std::get_if<uint64_t>(&property.second); 2369 if (!timeMilliseconds) 2370 { 2371 return false; 2372 } 2373 const std::chrono::duration<uint64_t, std::milli> ms( 2374 *timeMilliseconds); 2375 aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2376 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2377 .count(); 2378 } 2379 else if (property.first == "ExitUtilizationPercent") 2380 { 2381 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2382 if (!util) 2383 { 2384 return false; 2385 } 2386 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2387 } 2388 else if (property.first == "ExitDwellTime") 2389 { 2390 // Convert Dbus time from milliseconds to seconds 2391 const uint64_t* timeMilliseconds = 2392 std::get_if<uint64_t>(&property.second); 2393 if (!timeMilliseconds) 2394 { 2395 return false; 2396 } 2397 const std::chrono::duration<uint64_t, std::milli> ms( 2398 *timeMilliseconds); 2399 aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2400 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2401 .count(); 2402 } 2403 else 2404 { 2405 BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: " 2406 << property.first; 2407 } 2408 } 2409 2410 return true; 2411 } 2412 2413 /** 2414 * @brief Retrieves host watchdog timer properties over DBUS 2415 * 2416 * @param[in] aResp Shared pointer for completing asynchronous calls. 2417 * 2418 * @return None. 2419 */ 2420 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2421 { 2422 BMCWEB_LOG_DEBUG << "Get idle power saver parameters"; 2423 2424 // Get IdlePowerSaver object path: 2425 crow::connections::systemBus->async_method_call( 2426 [aResp]( 2427 const boost::system::error_code ec, 2428 const std::vector<std::pair< 2429 std::string, 2430 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2431 subtree) { 2432 if (ec) 2433 { 2434 BMCWEB_LOG_DEBUG 2435 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2436 << ec; 2437 messages::internalError(aResp->res); 2438 return; 2439 } 2440 if (subtree.empty()) 2441 { 2442 // This is an optional interface so just return 2443 // if there is no instance found 2444 BMCWEB_LOG_DEBUG << "No instances found"; 2445 return; 2446 } 2447 if (subtree.size() > 1) 2448 { 2449 // More then one PowerIdlePowerSaver object is not supported and 2450 // is an error 2451 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus " 2452 "Power.IdlePowerSaver objects: " 2453 << subtree.size(); 2454 messages::internalError(aResp->res); 2455 return; 2456 } 2457 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2458 { 2459 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2460 messages::internalError(aResp->res); 2461 return; 2462 } 2463 const std::string& path = subtree[0].first; 2464 const std::string& service = subtree[0].second.begin()->first; 2465 if (service.empty()) 2466 { 2467 BMCWEB_LOG_DEBUG 2468 << "Power.IdlePowerSaver service mapper error!"; 2469 messages::internalError(aResp->res); 2470 return; 2471 } 2472 2473 // Valid IdlePowerSaver object found, now read the current values 2474 crow::connections::systemBus->async_method_call( 2475 [aResp](const boost::system::error_code ec, 2476 ipsPropertiesType& properties) { 2477 if (ec) 2478 { 2479 BMCWEB_LOG_ERROR 2480 << "DBUS response error on IdlePowerSaver GetAll: " 2481 << ec; 2482 messages::internalError(aResp->res); 2483 return; 2484 } 2485 2486 if (parseIpsProperties(aResp, properties) == false) 2487 { 2488 messages::internalError(aResp->res); 2489 return; 2490 } 2491 }, 2492 service, path, "org.freedesktop.DBus.Properties", "GetAll", 2493 "xyz.openbmc_project.Control.Power.IdlePowerSaver"); 2494 }, 2495 "xyz.openbmc_project.ObjectMapper", 2496 "/xyz/openbmc_project/object_mapper", 2497 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2498 std::array<const char*, 1>{ 2499 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2500 2501 BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters"; 2502 } 2503 2504 /** 2505 * @brief Sets Idle Power Saver properties. 2506 * 2507 * @param[in] aResp Shared pointer for generating response message. 2508 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2509 * RF request. 2510 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2511 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2512 * before entering idle state. 2513 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2514 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2515 * before exiting idle state 2516 * 2517 * @return None. 2518 */ 2519 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2520 const std::optional<bool> ipsEnable, 2521 const std::optional<uint8_t> ipsEnterUtil, 2522 const std::optional<uint64_t> ipsEnterTime, 2523 const std::optional<uint8_t> ipsExitUtil, 2524 const std::optional<uint64_t> ipsExitTime) 2525 { 2526 BMCWEB_LOG_DEBUG << "Set idle power saver properties"; 2527 2528 // Get IdlePowerSaver object path: 2529 crow::connections::systemBus->async_method_call( 2530 [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2531 ipsExitTime]( 2532 const boost::system::error_code ec, 2533 const std::vector<std::pair< 2534 std::string, 2535 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2536 subtree) { 2537 if (ec) 2538 { 2539 BMCWEB_LOG_DEBUG 2540 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2541 << ec; 2542 messages::internalError(aResp->res); 2543 return; 2544 } 2545 if (subtree.empty()) 2546 { 2547 // This is an optional D-Bus object, but user attempted to patch 2548 messages::resourceNotFound(aResp->res, "ComputerSystem", 2549 "IdlePowerSaver"); 2550 return; 2551 } 2552 if (subtree.size() > 1) 2553 { 2554 // More then one PowerIdlePowerSaver object is not supported and 2555 // is an error 2556 BMCWEB_LOG_DEBUG 2557 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: " 2558 << subtree.size(); 2559 messages::internalError(aResp->res); 2560 return; 2561 } 2562 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2563 { 2564 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2565 messages::internalError(aResp->res); 2566 return; 2567 } 2568 const std::string& path = subtree[0].first; 2569 const std::string& service = subtree[0].second.begin()->first; 2570 if (service.empty()) 2571 { 2572 BMCWEB_LOG_DEBUG 2573 << "Power.IdlePowerSaver service mapper error!"; 2574 messages::internalError(aResp->res); 2575 return; 2576 } 2577 2578 // Valid Power IdlePowerSaver object found, now set any values that 2579 // need to be updated 2580 2581 if (ipsEnable) 2582 { 2583 crow::connections::systemBus->async_method_call( 2584 [aResp](const boost::system::error_code ec) { 2585 if (ec) 2586 { 2587 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2588 messages::internalError(aResp->res); 2589 return; 2590 } 2591 }, 2592 service, path, "org.freedesktop.DBus.Properties", "Set", 2593 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2594 "Enabled", dbus::utility::DbusVariantType(*ipsEnable)); 2595 } 2596 if (ipsEnterUtil) 2597 { 2598 crow::connections::systemBus->async_method_call( 2599 [aResp](const boost::system::error_code ec) { 2600 if (ec) 2601 { 2602 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2603 messages::internalError(aResp->res); 2604 return; 2605 } 2606 }, 2607 service, path, "org.freedesktop.DBus.Properties", "Set", 2608 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2609 "EnterUtilizationPercent", 2610 dbus::utility::DbusVariantType(*ipsEnterUtil)); 2611 } 2612 if (ipsEnterTime) 2613 { 2614 // Convert from seconds into milliseconds for DBus 2615 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2616 crow::connections::systemBus->async_method_call( 2617 [aResp](const boost::system::error_code ec) { 2618 if (ec) 2619 { 2620 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2621 messages::internalError(aResp->res); 2622 return; 2623 } 2624 }, 2625 service, path, "org.freedesktop.DBus.Properties", "Set", 2626 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2627 "EnterDwellTime", 2628 dbus::utility::DbusVariantType(timeMilliseconds)); 2629 } 2630 if (ipsExitUtil) 2631 { 2632 crow::connections::systemBus->async_method_call( 2633 [aResp](const boost::system::error_code ec) { 2634 if (ec) 2635 { 2636 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2637 messages::internalError(aResp->res); 2638 return; 2639 } 2640 }, 2641 service, path, "org.freedesktop.DBus.Properties", "Set", 2642 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2643 "ExitUtilizationPercent", 2644 dbus::utility::DbusVariantType(*ipsExitUtil)); 2645 } 2646 if (ipsExitTime) 2647 { 2648 // Convert from seconds into milliseconds for DBus 2649 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2650 crow::connections::systemBus->async_method_call( 2651 [aResp](const boost::system::error_code ec) { 2652 if (ec) 2653 { 2654 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2655 messages::internalError(aResp->res); 2656 return; 2657 } 2658 }, 2659 service, path, "org.freedesktop.DBus.Properties", "Set", 2660 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2661 "ExitDwellTime", 2662 dbus::utility::DbusVariantType(timeMilliseconds)); 2663 } 2664 }, 2665 "xyz.openbmc_project.ObjectMapper", 2666 "/xyz/openbmc_project/object_mapper", 2667 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2668 std::array<const char*, 1>{ 2669 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2670 2671 BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters"; 2672 } 2673 2674 /** 2675 * SystemsCollection derived class for delivering ComputerSystems Collection 2676 * Schema 2677 */ 2678 inline void requestRoutesSystemsCollection(App& app) 2679 { 2680 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2681 .privileges(redfish::privileges::getComputerSystemCollection) 2682 .methods(boost::beast::http::verb::get)( 2683 [](const crow::Request& /*req*/, 2684 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2685 asyncResp->res.jsonValue["@odata.type"] = 2686 "#ComputerSystemCollection.ComputerSystemCollection"; 2687 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2688 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2689 2690 sdbusplus::asio::getProperty<std::string>( 2691 *crow::connections::systemBus, 2692 "xyz.openbmc_project.Settings", 2693 "/xyz/openbmc_project/network/hypervisor", 2694 "xyz.openbmc_project.Network.SystemConfiguration", 2695 "HostName", 2696 [asyncResp](const boost::system::error_code ec, 2697 const std::string& /*hostName*/) { 2698 nlohmann::json& ifaceArray = 2699 asyncResp->res.jsonValue["Members"]; 2700 ifaceArray = nlohmann::json::array(); 2701 auto& count = 2702 asyncResp->res.jsonValue["Members@odata.count"]; 2703 ifaceArray.push_back( 2704 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2705 count = ifaceArray.size(); 2706 if (!ec) 2707 { 2708 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2709 ifaceArray.push_back( 2710 {{"@odata.id", 2711 "/redfish/v1/Systems/hypervisor"}}); 2712 count = ifaceArray.size(); 2713 } 2714 }); 2715 }); 2716 } 2717 2718 /** 2719 * Function transceives data with dbus directly. 2720 */ 2721 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2722 { 2723 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2724 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2725 constexpr char const* interfaceName = 2726 "xyz.openbmc_project.Control.Host.NMI"; 2727 constexpr char const* method = "NMI"; 2728 2729 crow::connections::systemBus->async_method_call( 2730 [asyncResp](const boost::system::error_code ec) { 2731 if (ec) 2732 { 2733 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2734 messages::internalError(asyncResp->res); 2735 return; 2736 } 2737 messages::success(asyncResp->res); 2738 }, 2739 serviceName, objectPath, interfaceName, method); 2740 } 2741 2742 /** 2743 * SystemActionsReset class supports handle POST method for Reset action. 2744 * The class retrieves and sends data directly to D-Bus. 2745 */ 2746 inline void requestRoutesSystemActionsReset(App& app) 2747 { 2748 /** 2749 * Function handles POST method request. 2750 * Analyzes POST body message before sends Reset request data to D-Bus. 2751 */ 2752 BMCWEB_ROUTE(app, 2753 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2754 .privileges(redfish::privileges::postComputerSystem) 2755 .methods( 2756 boost::beast::http::verb:: 2757 post)([](const crow::Request& req, 2758 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2759 std::string resetType; 2760 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2761 resetType)) 2762 { 2763 return; 2764 } 2765 2766 // Get the command and host vs. chassis 2767 std::string command; 2768 bool hostCommand = true; 2769 if ((resetType == "On") || (resetType == "ForceOn")) 2770 { 2771 command = "xyz.openbmc_project.State.Host.Transition.On"; 2772 hostCommand = true; 2773 } 2774 else if (resetType == "ForceOff") 2775 { 2776 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2777 hostCommand = false; 2778 } 2779 else if (resetType == "ForceRestart") 2780 { 2781 command = 2782 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2783 hostCommand = true; 2784 } 2785 else if (resetType == "GracefulShutdown") 2786 { 2787 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2788 hostCommand = true; 2789 } 2790 else if (resetType == "GracefulRestart") 2791 { 2792 command = 2793 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2794 hostCommand = true; 2795 } 2796 else if (resetType == "PowerCycle") 2797 { 2798 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2799 hostCommand = true; 2800 } 2801 else if (resetType == "Nmi") 2802 { 2803 doNMI(asyncResp); 2804 return; 2805 } 2806 else 2807 { 2808 messages::actionParameterUnknown(asyncResp->res, "Reset", 2809 resetType); 2810 return; 2811 } 2812 2813 if (hostCommand) 2814 { 2815 crow::connections::systemBus->async_method_call( 2816 [asyncResp, resetType](const boost::system::error_code ec) { 2817 if (ec) 2818 { 2819 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2820 if (ec.value() == 2821 boost::asio::error::invalid_argument) 2822 { 2823 messages::actionParameterNotSupported( 2824 asyncResp->res, resetType, "Reset"); 2825 } 2826 else 2827 { 2828 messages::internalError(asyncResp->res); 2829 } 2830 return; 2831 } 2832 messages::success(asyncResp->res); 2833 }, 2834 "xyz.openbmc_project.State.Host", 2835 "/xyz/openbmc_project/state/host0", 2836 "org.freedesktop.DBus.Properties", "Set", 2837 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2838 dbus::utility::DbusVariantType{command}); 2839 } 2840 else 2841 { 2842 crow::connections::systemBus->async_method_call( 2843 [asyncResp, resetType](const boost::system::error_code ec) { 2844 if (ec) 2845 { 2846 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2847 if (ec.value() == 2848 boost::asio::error::invalid_argument) 2849 { 2850 messages::actionParameterNotSupported( 2851 asyncResp->res, resetType, "Reset"); 2852 } 2853 else 2854 { 2855 messages::internalError(asyncResp->res); 2856 } 2857 return; 2858 } 2859 messages::success(asyncResp->res); 2860 }, 2861 "xyz.openbmc_project.State.Chassis", 2862 "/xyz/openbmc_project/state/chassis0", 2863 "org.freedesktop.DBus.Properties", "Set", 2864 "xyz.openbmc_project.State.Chassis", 2865 "RequestedPowerTransition", 2866 dbus::utility::DbusVariantType{command}); 2867 } 2868 }); 2869 } 2870 2871 /** 2872 * Systems derived class for delivering Computer Systems Schema. 2873 */ 2874 inline void requestRoutesSystems(App& app) 2875 { 2876 2877 /** 2878 * Functions triggers appropriate requests on DBus 2879 */ 2880 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2881 .privileges(redfish::privileges::getComputerSystem) 2882 .methods( 2883 boost::beast::http::verb:: 2884 get)([](const crow::Request&, 2885 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2886 asyncResp->res.jsonValue["@odata.type"] = 2887 "#ComputerSystem.v1_16_0.ComputerSystem"; 2888 asyncResp->res.jsonValue["Name"] = "system"; 2889 asyncResp->res.jsonValue["Id"] = "system"; 2890 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2891 asyncResp->res.jsonValue["Description"] = "Computer System"; 2892 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2893 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2894 "Disabled"; 2895 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2896 uint64_t(0); 2897 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2898 "Disabled"; 2899 asyncResp->res.jsonValue["@odata.id"] = 2900 "/redfish/v1/Systems/system"; 2901 2902 asyncResp->res.jsonValue["Processors"] = { 2903 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2904 asyncResp->res.jsonValue["Memory"] = { 2905 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2906 asyncResp->res.jsonValue["Storage"] = { 2907 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2908 2909 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2910 {"target", 2911 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2912 {"@Redfish.ActionInfo", 2913 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2914 2915 asyncResp->res.jsonValue["LogServices"] = { 2916 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2917 2918 asyncResp->res.jsonValue["Bios"] = { 2919 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2920 2921 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2922 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2923 2924 asyncResp->res.jsonValue["Status"] = { 2925 {"Health", "OK"}, 2926 {"State", "Enabled"}, 2927 }; 2928 2929 // Fill in SerialConsole info 2930 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2931 15; 2932 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2933 {"ServiceEnabled", true}, 2934 }; 2935 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2936 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2937 {"ServiceEnabled", true}, 2938 {"Port", 2200}, 2939 // https://github.com/openbmc/docs/blob/master/console.md 2940 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2941 }; 2942 2943 #ifdef BMCWEB_ENABLE_KVM 2944 // Fill in GraphicalConsole info 2945 asyncResp->res.jsonValue["GraphicalConsole"] = { 2946 {"ServiceEnabled", true}, 2947 {"MaxConcurrentSessions", 4}, 2948 {"ConnectTypesSupported", {"KVMIP"}}, 2949 }; 2950 #endif // BMCWEB_ENABLE_KVM 2951 constexpr const std::array<const char*, 4> inventoryForSystems = { 2952 "xyz.openbmc_project.Inventory.Item.Dimm", 2953 "xyz.openbmc_project.Inventory.Item.Cpu", 2954 "xyz.openbmc_project.Inventory.Item.Drive", 2955 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2956 2957 auto health = std::make_shared<HealthPopulate>(asyncResp); 2958 crow::connections::systemBus->async_method_call( 2959 [health](const boost::system::error_code ec, 2960 const std::vector<std::string>& resp) { 2961 if (ec) 2962 { 2963 // no inventory 2964 return; 2965 } 2966 2967 health->inventory = resp; 2968 }, 2969 "xyz.openbmc_project.ObjectMapper", 2970 "/xyz/openbmc_project/object_mapper", 2971 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2972 int32_t(0), inventoryForSystems); 2973 2974 health->populate(); 2975 2976 getMainChassisId( 2977 asyncResp, [](const std::string& chassisId, 2978 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2979 aRsp->res.jsonValue["Links"]["Chassis"] = { 2980 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2981 }); 2982 2983 getLocationIndicatorActive(asyncResp); 2984 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2985 getIndicatorLedState(asyncResp); 2986 getComputerSystem(asyncResp, health); 2987 getHostState(asyncResp); 2988 getBootProperties(asyncResp); 2989 getBootProgress(asyncResp); 2990 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2991 getHostWatchdogTimer(asyncResp); 2992 getPowerRestorePolicy(asyncResp); 2993 getAutomaticRetry(asyncResp); 2994 getLastResetTime(asyncResp); 2995 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2996 getProvisioningStatus(asyncResp); 2997 #endif 2998 getTrustedModuleRequiredToBoot(asyncResp); 2999 getPowerMode(asyncResp); 3000 getIdlePowerSaver(asyncResp); 3001 }); 3002 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 3003 .privileges(redfish::privileges::patchComputerSystem) 3004 .methods(boost::beast::http::verb::patch)( 3005 [](const crow::Request& req, 3006 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3007 std::optional<bool> locationIndicatorActive; 3008 std::optional<std::string> indicatorLed; 3009 std::optional<nlohmann::json> bootProps; 3010 std::optional<nlohmann::json> wdtTimerProps; 3011 std::optional<std::string> assetTag; 3012 std::optional<std::string> powerRestorePolicy; 3013 std::optional<std::string> powerMode; 3014 std::optional<nlohmann::json> ipsProps; 3015 if (!json_util::readJson( 3016 req, asyncResp->res, "IndicatorLED", indicatorLed, 3017 "LocationIndicatorActive", locationIndicatorActive, 3018 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 3019 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 3020 assetTag, "PowerMode", powerMode, "IdlePowerSaver", 3021 ipsProps)) 3022 { 3023 return; 3024 } 3025 3026 asyncResp->res.result(boost::beast::http::status::no_content); 3027 3028 if (assetTag) 3029 { 3030 setAssetTag(asyncResp, *assetTag); 3031 } 3032 3033 if (wdtTimerProps) 3034 { 3035 std::optional<bool> wdtEnable; 3036 std::optional<std::string> wdtTimeOutAction; 3037 3038 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 3039 "FunctionEnabled", wdtEnable, 3040 "TimeoutAction", wdtTimeOutAction)) 3041 { 3042 return; 3043 } 3044 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3045 } 3046 3047 if (bootProps) 3048 { 3049 std::optional<std::string> bootSource; 3050 std::optional<std::string> bootType; 3051 std::optional<std::string> bootEnable; 3052 std::optional<std::string> automaticRetryConfig; 3053 std::optional<bool> trustedModuleRequiredToBoot; 3054 3055 if (!json_util::readJson( 3056 *bootProps, asyncResp->res, 3057 "BootSourceOverrideTarget", bootSource, 3058 "BootSourceOverrideMode", bootType, 3059 "BootSourceOverrideEnabled", bootEnable, 3060 "AutomaticRetryConfig", automaticRetryConfig, 3061 "TrustedModuleRequiredToBoot", 3062 trustedModuleRequiredToBoot)) 3063 { 3064 return; 3065 } 3066 3067 if (bootSource || bootType || bootEnable) 3068 { 3069 setBootProperties(asyncResp, bootSource, bootType, 3070 bootEnable); 3071 } 3072 if (automaticRetryConfig) 3073 { 3074 setAutomaticRetry(asyncResp, *automaticRetryConfig); 3075 } 3076 3077 if (trustedModuleRequiredToBoot) 3078 { 3079 setTrustedModuleRequiredToBoot( 3080 asyncResp, *trustedModuleRequiredToBoot); 3081 } 3082 } 3083 3084 if (locationIndicatorActive) 3085 { 3086 setLocationIndicatorActive(asyncResp, 3087 *locationIndicatorActive); 3088 } 3089 3090 // TODO (Gunnar): Remove IndicatorLED after enough time has 3091 // passed 3092 if (indicatorLed) 3093 { 3094 setIndicatorLedState(asyncResp, *indicatorLed); 3095 asyncResp->res.addHeader( 3096 boost::beast::http::field::warning, 3097 "299 - \"IndicatorLED is deprecated. Use " 3098 "LocationIndicatorActive instead.\""); 3099 } 3100 3101 if (powerRestorePolicy) 3102 { 3103 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3104 } 3105 3106 if (powerMode) 3107 { 3108 setPowerMode(asyncResp, *powerMode); 3109 } 3110 3111 if (ipsProps) 3112 { 3113 std::optional<bool> ipsEnable; 3114 std::optional<uint8_t> ipsEnterUtil; 3115 std::optional<uint64_t> ipsEnterTime; 3116 std::optional<uint8_t> ipsExitUtil; 3117 std::optional<uint64_t> ipsExitTime; 3118 3119 if (!json_util::readJson( 3120 *ipsProps, asyncResp->res, "Enabled", ipsEnable, 3121 "EnterUtilizationPercent", ipsEnterUtil, 3122 "EnterDwellTimeSeconds", ipsEnterTime, 3123 "ExitUtilizationPercent", ipsExitUtil, 3124 "ExitDwellTimeSeconds", ipsExitTime)) 3125 { 3126 return; 3127 } 3128 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, 3129 ipsEnterTime, ipsExitUtil, ipsExitTime); 3130 } 3131 }); 3132 } 3133 3134 /** 3135 * SystemResetActionInfo derived class for delivering Computer Systems 3136 * ResetType AllowableValues using ResetInfo schema. 3137 */ 3138 inline void requestRoutesSystemResetActionInfo(App& app) 3139 { 3140 3141 /** 3142 * Functions triggers appropriate requests on DBus 3143 */ 3144 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 3145 .privileges(redfish::privileges::getActionInfo) 3146 .methods(boost::beast::http::verb::get)( 3147 [](const crow::Request&, 3148 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3149 asyncResp->res.jsonValue = { 3150 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 3151 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 3152 {"Name", "Reset Action Info"}, 3153 {"Id", "ResetActionInfo"}, 3154 {"Parameters", 3155 {{{"Name", "ResetType"}, 3156 {"Required", true}, 3157 {"DataType", "String"}, 3158 {"AllowableValues", 3159 {"On", "ForceOff", "ForceOn", "ForceRestart", 3160 "GracefulRestart", "GracefulShutdown", "PowerCycle", 3161 "Nmi"}}}}}}; 3162 }); 3163 } 3164 } // namespace redfish 3165