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