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 uint64_t lastResetTimeStamp = *lastResetTimePtr / 1000; 1175 1176 // Convert to ISO 8601 standard 1177 aResp->res.jsonValue["LastResetTime"] = 1178 crow::utility::getDateTimeUint(lastResetTimeStamp); 1179 }, 1180 "xyz.openbmc_project.State.Chassis", 1181 "/xyz/openbmc_project/state/chassis0", 1182 "org.freedesktop.DBus.Properties", "Get", 1183 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 1184 } 1185 1186 /** 1187 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1188 * 1189 * @param[in] aResp Shared pointer for generating response message. 1190 * 1191 * @return None. 1192 */ 1193 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1194 { 1195 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1196 1197 crow::connections::systemBus->async_method_call( 1198 [aResp](const boost::system::error_code ec, 1199 std::variant<bool>& autoRebootEnabled) { 1200 if (ec) 1201 { 1202 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1203 return; 1204 } 1205 1206 const bool* autoRebootEnabledPtr = 1207 std::get_if<bool>(&autoRebootEnabled); 1208 1209 if (!autoRebootEnabledPtr) 1210 { 1211 messages::internalError(aResp->res); 1212 return; 1213 } 1214 1215 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1216 if (*autoRebootEnabledPtr == true) 1217 { 1218 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1219 "RetryAttempts"; 1220 // If AutomaticRetry (AutoReboot) is enabled see how many 1221 // attempts are left 1222 crow::connections::systemBus->async_method_call( 1223 [aResp](const boost::system::error_code ec2, 1224 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1225 if (ec2) 1226 { 1227 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1228 return; 1229 } 1230 1231 const uint32_t* autoRebootAttemptsLeftPtr = 1232 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1233 1234 if (!autoRebootAttemptsLeftPtr) 1235 { 1236 messages::internalError(aResp->res); 1237 return; 1238 } 1239 1240 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1241 << *autoRebootAttemptsLeftPtr; 1242 1243 aResp->res 1244 .jsonValue["Boot"] 1245 ["RemainingAutomaticRetryAttempts"] = 1246 *autoRebootAttemptsLeftPtr; 1247 }, 1248 "xyz.openbmc_project.State.Host", 1249 "/xyz/openbmc_project/state/host0", 1250 "org.freedesktop.DBus.Properties", "Get", 1251 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1252 "AttemptsLeft"); 1253 } 1254 else 1255 { 1256 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1257 "Disabled"; 1258 } 1259 1260 // Not on D-Bus. Hardcoded here: 1261 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1262 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1263 1264 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1265 // and RetryAttempts. OpenBMC only supports Disabled and 1266 // RetryAttempts. 1267 aResp->res 1268 .jsonValue["Boot"] 1269 ["AutomaticRetryConfig@Redfish.AllowableValues"] = { 1270 "Disabled", "RetryAttempts"}; 1271 }, 1272 "xyz.openbmc_project.Settings", 1273 "/xyz/openbmc_project/control/host0/auto_reboot", 1274 "org.freedesktop.DBus.Properties", "Get", 1275 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1276 } 1277 1278 /** 1279 * @brief Retrieves power restore policy over DBUS. 1280 * 1281 * @param[in] aResp Shared pointer for generating response message. 1282 * 1283 * @return None. 1284 */ 1285 inline void 1286 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1287 { 1288 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1289 1290 crow::connections::systemBus->async_method_call( 1291 [aResp](const boost::system::error_code ec, 1292 std::variant<std::string>& policy) { 1293 if (ec) 1294 { 1295 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1296 return; 1297 } 1298 1299 const boost::container::flat_map<std::string, std::string> policyMaps = { 1300 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn", 1301 "AlwaysOn"}, 1302 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff", 1303 "AlwaysOff"}, 1304 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore", 1305 "LastState"}}; 1306 1307 const std::string* policyPtr = std::get_if<std::string>(&policy); 1308 1309 if (!policyPtr) 1310 { 1311 messages::internalError(aResp->res); 1312 return; 1313 } 1314 1315 auto policyMapsIt = policyMaps.find(*policyPtr); 1316 if (policyMapsIt == policyMaps.end()) 1317 { 1318 messages::internalError(aResp->res); 1319 return; 1320 } 1321 1322 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1323 }, 1324 "xyz.openbmc_project.Settings", 1325 "/xyz/openbmc_project/control/host0/power_restore_policy", 1326 "org.freedesktop.DBus.Properties", "Get", 1327 "xyz.openbmc_project.Control.Power.RestorePolicy", 1328 "PowerRestorePolicy"); 1329 } 1330 1331 /** 1332 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1333 * TPM is required for booting the host. 1334 * 1335 * @param[in] aResp Shared pointer for generating response message. 1336 * 1337 * @return None. 1338 */ 1339 inline void getTrustedModuleRequiredToBoot( 1340 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1341 { 1342 BMCWEB_LOG_DEBUG << "Get TPM required to boot."; 1343 1344 crow::connections::systemBus->async_method_call( 1345 [aResp]( 1346 const boost::system::error_code ec, 1347 std::vector<std::pair< 1348 std::string, 1349 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1350 subtree) { 1351 if (ec) 1352 { 1353 BMCWEB_LOG_DEBUG 1354 << "DBUS response error on TPM.Policy GetSubTree" << ec; 1355 // This is an optional D-Bus object so just return if 1356 // error occurs 1357 return; 1358 } 1359 if (subtree.size() == 0) 1360 { 1361 // As noted above, this is an optional interface so just return 1362 // if there is no instance found 1363 return; 1364 } 1365 1366 /* When there is more than one TPMEnable object... */ 1367 if (subtree.size() > 1) 1368 { 1369 BMCWEB_LOG_DEBUG 1370 << "DBUS response has more than 1 TPM Enable object:" 1371 << subtree.size(); 1372 // Throw an internal Error and return 1373 messages::internalError(aResp->res); 1374 return; 1375 } 1376 1377 // Make sure the Dbus response map has a service and objectPath 1378 // field 1379 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1380 { 1381 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1382 messages::internalError(aResp->res); 1383 return; 1384 } 1385 1386 const std::string& path = subtree[0].first; 1387 const std::string& serv = subtree[0].second.begin()->first; 1388 1389 // Valid TPM Enable object found, now reading the current value 1390 crow::connections::systemBus->async_method_call( 1391 [aResp](const boost::system::error_code ec, 1392 std::variant<bool>& tpmRequired) { 1393 if (ec) 1394 { 1395 BMCWEB_LOG_DEBUG 1396 << "D-BUS response error on TPM.Policy Get" << ec; 1397 messages::internalError(aResp->res); 1398 return; 1399 } 1400 1401 const bool* tpmRequiredVal = 1402 std::get_if<bool>(&tpmRequired); 1403 1404 if (!tpmRequiredVal) 1405 { 1406 messages::internalError(aResp->res); 1407 return; 1408 } 1409 1410 if (*tpmRequiredVal == true) 1411 { 1412 aResp->res 1413 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1414 "Required"; 1415 } 1416 else 1417 { 1418 aResp->res 1419 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1420 "Disabled"; 1421 } 1422 }, 1423 serv, path, "org.freedesktop.DBus.Properties", "Get", 1424 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable"); 1425 }, 1426 "xyz.openbmc_project.ObjectMapper", 1427 "/xyz/openbmc_project/object_mapper", 1428 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1429 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1430 } 1431 1432 /** 1433 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1434 * TPM is required for booting the host. 1435 * 1436 * @param[in] aResp Shared pointer for generating response message. 1437 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1438 * 1439 * @return None. 1440 */ 1441 inline void setTrustedModuleRequiredToBoot( 1442 const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired) 1443 { 1444 BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot."; 1445 1446 crow::connections::systemBus->async_method_call( 1447 [aResp, tpmRequired]( 1448 const boost::system::error_code ec, 1449 std::vector<std::pair< 1450 std::string, 1451 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1452 subtree) { 1453 if (ec) 1454 { 1455 BMCWEB_LOG_DEBUG 1456 << "DBUS response error on TPM.Policy GetSubTree" << ec; 1457 messages::internalError(aResp->res); 1458 return; 1459 } 1460 if (subtree.size() == 0) 1461 { 1462 messages::propertyValueNotInList(aResp->res, "ComputerSystem", 1463 "TrustedModuleRequiredToBoot"); 1464 return; 1465 } 1466 1467 /* When there is more than one TPMEnable object... */ 1468 if (subtree.size() > 1) 1469 { 1470 BMCWEB_LOG_DEBUG 1471 << "DBUS response has more than 1 TPM Enable object:" 1472 << subtree.size(); 1473 // Throw an internal Error and return 1474 messages::internalError(aResp->res); 1475 return; 1476 } 1477 1478 // Make sure the Dbus response map has a service and objectPath 1479 // field 1480 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1481 { 1482 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1483 messages::internalError(aResp->res); 1484 return; 1485 } 1486 1487 const std::string& path = subtree[0].first; 1488 const std::string& serv = subtree[0].second.begin()->first; 1489 1490 if (serv.empty()) 1491 { 1492 BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!"; 1493 messages::internalError(aResp->res); 1494 return; 1495 } 1496 1497 // Valid TPM Enable object found, now setting the value 1498 crow::connections::systemBus->async_method_call( 1499 [aResp](const boost::system::error_code ec) { 1500 if (ec) 1501 { 1502 BMCWEB_LOG_DEBUG 1503 << "DBUS response error: Set TrustedModuleRequiredToBoot" 1504 << ec; 1505 messages::internalError(aResp->res); 1506 return; 1507 } 1508 BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done."; 1509 }, 1510 serv, path, "org.freedesktop.DBus.Properties", "Set", 1511 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1512 std::variant<bool>(tpmRequired)); 1513 }, 1514 "xyz.openbmc_project.ObjectMapper", 1515 "/xyz/openbmc_project/object_mapper", 1516 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1517 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1518 } 1519 1520 /** 1521 * @brief Sets boot properties into DBUS object(s). 1522 * 1523 * @param[in] aResp Shared pointer for generating response message. 1524 * @param[in] bootType The boot type to set. 1525 * @return Integer error code. 1526 */ 1527 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1528 const std::optional<std::string>& bootType) 1529 { 1530 std::string bootTypeStr; 1531 1532 if (!bootType) 1533 { 1534 return; 1535 } 1536 1537 // Source target specified 1538 BMCWEB_LOG_DEBUG << "Boot type: " << *bootType; 1539 // Figure out which DBUS interface and property to use 1540 if (*bootType == "Legacy") 1541 { 1542 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1543 } 1544 else if (*bootType == "UEFI") 1545 { 1546 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1547 } 1548 else 1549 { 1550 BMCWEB_LOG_DEBUG << "Invalid property value for " 1551 "BootSourceOverrideMode: " 1552 << *bootType; 1553 messages::propertyValueNotInList(aResp->res, *bootType, 1554 "BootSourceOverrideMode"); 1555 return; 1556 } 1557 1558 // Act on validated parameters 1559 BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr; 1560 1561 crow::connections::systemBus->async_method_call( 1562 [aResp](const boost::system::error_code ec) { 1563 if (ec) 1564 { 1565 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1566 if (ec.value() == boost::asio::error::host_unreachable) 1567 { 1568 messages::resourceNotFound(aResp->res, "Set", "BootType"); 1569 return; 1570 } 1571 messages::internalError(aResp->res); 1572 return; 1573 } 1574 BMCWEB_LOG_DEBUG << "Boot type update done."; 1575 }, 1576 "xyz.openbmc_project.Settings", 1577 "/xyz/openbmc_project/control/host0/boot", 1578 "org.freedesktop.DBus.Properties", "Set", 1579 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1580 std::variant<std::string>(bootTypeStr)); 1581 } 1582 1583 /** 1584 * @brief Sets boot properties into DBUS object(s). 1585 * 1586 * @param[in] aResp Shared pointer for generating response message. 1587 * @param[in] bootType The boot type to set. 1588 * @return Integer error code. 1589 */ 1590 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1591 const std::optional<std::string>& bootEnable) 1592 { 1593 if (!bootEnable) 1594 { 1595 return; 1596 } 1597 // Source target specified 1598 BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable; 1599 1600 bool bootOverrideEnable = false; 1601 bool bootOverridePersistent = false; 1602 // Figure out which DBUS interface and property to use 1603 if (*bootEnable == "Disabled") 1604 { 1605 bootOverrideEnable = false; 1606 } 1607 else if (*bootEnable == "Once") 1608 { 1609 bootOverrideEnable = true; 1610 bootOverridePersistent = false; 1611 } 1612 else if (*bootEnable == "Continuous") 1613 { 1614 bootOverrideEnable = true; 1615 bootOverridePersistent = true; 1616 } 1617 else 1618 { 1619 BMCWEB_LOG_DEBUG 1620 << "Invalid property value for BootSourceOverrideEnabled: " 1621 << *bootEnable; 1622 messages::propertyValueNotInList(aResp->res, *bootEnable, 1623 "BootSourceOverrideEnabled"); 1624 return; 1625 } 1626 1627 // Act on validated parameters 1628 BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable; 1629 1630 crow::connections::systemBus->async_method_call( 1631 [aResp](const boost::system::error_code ec) { 1632 if (ec) 1633 { 1634 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1635 messages::internalError(aResp->res); 1636 return; 1637 } 1638 BMCWEB_LOG_DEBUG << "Boot override enable update done."; 1639 }, 1640 "xyz.openbmc_project.Settings", 1641 "/xyz/openbmc_project/control/host0/boot", 1642 "org.freedesktop.DBus.Properties", "Set", 1643 "xyz.openbmc_project.Object.Enable", "Enabled", 1644 std::variant<bool>(bootOverrideEnable)); 1645 1646 if (!bootOverrideEnable) 1647 { 1648 return; 1649 } 1650 1651 // In case boot override is enabled we need to set correct value for the 1652 // 'one_time' enable DBus interface 1653 BMCWEB_LOG_DEBUG << "DBUS boot override persistent: " 1654 << bootOverridePersistent; 1655 1656 crow::connections::systemBus->async_method_call( 1657 [aResp](const boost::system::error_code ec) { 1658 if (ec) 1659 { 1660 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1661 messages::internalError(aResp->res); 1662 return; 1663 } 1664 BMCWEB_LOG_DEBUG << "Boot one_time update done."; 1665 }, 1666 "xyz.openbmc_project.Settings", 1667 "/xyz/openbmc_project/control/host0/boot/one_time", 1668 "org.freedesktop.DBus.Properties", "Set", 1669 "xyz.openbmc_project.Object.Enable", "Enabled", 1670 std::variant<bool>(!bootOverridePersistent)); 1671 } 1672 1673 /** 1674 * @brief Sets boot properties into DBUS object(s). 1675 * 1676 * @param[in] aResp Shared pointer for generating response message. 1677 * @param[in] bootSource The boot source to set. 1678 * 1679 * @return Integer error code. 1680 */ 1681 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1682 const std::optional<std::string>& bootSource) 1683 { 1684 std::string bootSourceStr; 1685 std::string bootModeStr; 1686 1687 if (!bootSource) 1688 { 1689 return; 1690 } 1691 1692 // Source target specified 1693 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1694 // Figure out which DBUS interface and property to use 1695 if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr)) 1696 { 1697 BMCWEB_LOG_DEBUG 1698 << "Invalid property value for BootSourceOverrideTarget: " 1699 << *bootSource; 1700 messages::propertyValueNotInList(aResp->res, *bootSource, 1701 "BootSourceTargetOverride"); 1702 return; 1703 } 1704 1705 // Act on validated parameters 1706 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1707 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1708 1709 crow::connections::systemBus->async_method_call( 1710 [aResp](const boost::system::error_code ec) { 1711 if (ec) 1712 { 1713 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1714 messages::internalError(aResp->res); 1715 return; 1716 } 1717 BMCWEB_LOG_DEBUG << "Boot source update done."; 1718 }, 1719 "xyz.openbmc_project.Settings", 1720 "/xyz/openbmc_project/control/host0/boot", 1721 "org.freedesktop.DBus.Properties", "Set", 1722 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1723 std::variant<std::string>(bootSourceStr)); 1724 1725 crow::connections::systemBus->async_method_call( 1726 [aResp](const boost::system::error_code ec) { 1727 if (ec) 1728 { 1729 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1730 messages::internalError(aResp->res); 1731 return; 1732 } 1733 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1734 }, 1735 "xyz.openbmc_project.Settings", 1736 "/xyz/openbmc_project/control/host0/boot", 1737 "org.freedesktop.DBus.Properties", "Set", 1738 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1739 std::variant<std::string>(bootModeStr)); 1740 } 1741 1742 /** 1743 * @brief Sets Boot source override properties. 1744 * 1745 * @param[in] aResp Shared pointer for generating response message. 1746 * @param[in] bootSource The boot source from incoming RF request. 1747 * @param[in] bootType The boot type from incoming RF request. 1748 * @param[in] bootEnable The boot override enable from incoming RF request. 1749 * 1750 * @return Integer error code. 1751 */ 1752 1753 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1754 const std::optional<std::string>& bootSource, 1755 const std::optional<std::string>& bootType, 1756 const std::optional<std::string>& bootEnable) 1757 { 1758 BMCWEB_LOG_DEBUG << "Set boot information."; 1759 1760 setBootModeOrSource(aResp, bootSource); 1761 setBootType(aResp, bootType); 1762 setBootEnable(aResp, bootEnable); 1763 } 1764 1765 /** 1766 * @brief Sets AssetTag 1767 * 1768 * @param[in] aResp Shared pointer for generating response message. 1769 * @param[in] assetTag "AssetTag" from request. 1770 * 1771 * @return None. 1772 */ 1773 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1774 const std::string& assetTag) 1775 { 1776 crow::connections::systemBus->async_method_call( 1777 [aResp, assetTag]( 1778 const boost::system::error_code ec, 1779 const std::vector<std::pair< 1780 std::string, 1781 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1782 subtree) { 1783 if (ec) 1784 { 1785 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1786 messages::internalError(aResp->res); 1787 return; 1788 } 1789 if (subtree.size() == 0) 1790 { 1791 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1792 messages::internalError(aResp->res); 1793 return; 1794 } 1795 // Assume only 1 system D-Bus object 1796 // Throw an error if there is more than 1 1797 if (subtree.size() > 1) 1798 { 1799 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1800 messages::internalError(aResp->res); 1801 return; 1802 } 1803 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1804 { 1805 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1806 messages::internalError(aResp->res); 1807 return; 1808 } 1809 1810 const std::string& path = subtree[0].first; 1811 const std::string& service = subtree[0].second.begin()->first; 1812 1813 if (service.empty()) 1814 { 1815 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1816 messages::internalError(aResp->res); 1817 return; 1818 } 1819 1820 crow::connections::systemBus->async_method_call( 1821 [aResp](const boost::system::error_code ec2) { 1822 if (ec2) 1823 { 1824 BMCWEB_LOG_DEBUG 1825 << "D-Bus response error on AssetTag Set " << ec2; 1826 messages::internalError(aResp->res); 1827 return; 1828 } 1829 }, 1830 service, path, "org.freedesktop.DBus.Properties", "Set", 1831 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1832 std::variant<std::string>(assetTag)); 1833 }, 1834 "xyz.openbmc_project.ObjectMapper", 1835 "/xyz/openbmc_project/object_mapper", 1836 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1837 "/xyz/openbmc_project/inventory", int32_t(0), 1838 std::array<const char*, 1>{ 1839 "xyz.openbmc_project.Inventory.Item.System"}); 1840 } 1841 1842 /** 1843 * @brief Sets automaticRetry (Auto Reboot) 1844 * 1845 * @param[in] aResp Shared pointer for generating response message. 1846 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1847 * 1848 * @return None. 1849 */ 1850 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1851 const std::string& automaticRetryConfig) 1852 { 1853 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1854 1855 // OpenBMC only supports "Disabled" and "RetryAttempts". 1856 bool autoRebootEnabled; 1857 1858 if (automaticRetryConfig == "Disabled") 1859 { 1860 autoRebootEnabled = false; 1861 } 1862 else if (automaticRetryConfig == "RetryAttempts") 1863 { 1864 autoRebootEnabled = true; 1865 } 1866 else 1867 { 1868 BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: " 1869 << automaticRetryConfig; 1870 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1871 "AutomaticRetryConfig"); 1872 return; 1873 } 1874 1875 crow::connections::systemBus->async_method_call( 1876 [aResp](const boost::system::error_code ec) { 1877 if (ec) 1878 { 1879 messages::internalError(aResp->res); 1880 return; 1881 } 1882 }, 1883 "xyz.openbmc_project.Settings", 1884 "/xyz/openbmc_project/control/host0/auto_reboot", 1885 "org.freedesktop.DBus.Properties", "Set", 1886 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1887 std::variant<bool>(autoRebootEnabled)); 1888 } 1889 1890 /** 1891 * @brief Sets power restore policy properties. 1892 * 1893 * @param[in] aResp Shared pointer for generating response message. 1894 * @param[in] policy power restore policy properties from request. 1895 * 1896 * @return None. 1897 */ 1898 inline void 1899 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1900 const std::string& policy) 1901 { 1902 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1903 1904 const boost::container::flat_map<std::string, std::string> policyMaps = { 1905 {"AlwaysOn", 1906 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"}, 1907 {"AlwaysOff", 1908 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"}, 1909 {"LastState", 1910 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}}; 1911 1912 std::string powerRestorPolicy; 1913 1914 auto policyMapsIt = policyMaps.find(policy); 1915 if (policyMapsIt == policyMaps.end()) 1916 { 1917 messages::propertyValueNotInList(aResp->res, policy, 1918 "PowerRestorePolicy"); 1919 return; 1920 } 1921 1922 powerRestorPolicy = policyMapsIt->second; 1923 1924 crow::connections::systemBus->async_method_call( 1925 [aResp](const boost::system::error_code ec) { 1926 if (ec) 1927 { 1928 messages::internalError(aResp->res); 1929 return; 1930 } 1931 }, 1932 "xyz.openbmc_project.Settings", 1933 "/xyz/openbmc_project/control/host0/power_restore_policy", 1934 "org.freedesktop.DBus.Properties", "Set", 1935 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1936 std::variant<std::string>(powerRestorPolicy)); 1937 } 1938 1939 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1940 /** 1941 * @brief Retrieves provisioning status 1942 * 1943 * @param[in] aResp Shared pointer for completing asynchronous calls. 1944 * 1945 * @return None. 1946 */ 1947 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1948 { 1949 BMCWEB_LOG_DEBUG << "Get OEM information."; 1950 crow::connections::systemBus->async_method_call( 1951 [aResp](const boost::system::error_code ec, 1952 const std::vector<std::pair<std::string, VariantType>>& 1953 propertiesList) { 1954 nlohmann::json& oemPFR = 1955 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1956 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1957 "#OemComputerSystem.OpenBmc"; 1958 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1959 1960 if (ec) 1961 { 1962 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1963 // not an error, don't have to have the interface 1964 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1965 return; 1966 } 1967 1968 const bool* provState = nullptr; 1969 const bool* lockState = nullptr; 1970 for (const std::pair<std::string, VariantType>& property : 1971 propertiesList) 1972 { 1973 if (property.first == "UfmProvisioned") 1974 { 1975 provState = std::get_if<bool>(&property.second); 1976 } 1977 else if (property.first == "UfmLocked") 1978 { 1979 lockState = std::get_if<bool>(&property.second); 1980 } 1981 } 1982 1983 if ((provState == nullptr) || (lockState == nullptr)) 1984 { 1985 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1986 messages::internalError(aResp->res); 1987 return; 1988 } 1989 1990 if (*provState == true) 1991 { 1992 if (*lockState == true) 1993 { 1994 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1995 } 1996 else 1997 { 1998 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1999 } 2000 } 2001 else 2002 { 2003 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 2004 } 2005 }, 2006 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 2007 "org.freedesktop.DBus.Properties", "GetAll", 2008 "xyz.openbmc_project.PFR.Attributes"); 2009 } 2010 #endif 2011 2012 /** 2013 * @brief Translate the PowerMode to a response message. 2014 * 2015 * @param[in] aResp Shared pointer for generating response message. 2016 * @param[in] modeValue PowerMode value to be translated 2017 * 2018 * @return None. 2019 */ 2020 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2021 const std::string& modeValue) 2022 { 2023 std::string modeString; 2024 2025 if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 2026 { 2027 aResp->res.jsonValue["PowerMode"] = "Static"; 2028 } 2029 else if ( 2030 modeValue == 2031 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 2032 { 2033 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 2034 } 2035 else if (modeValue == 2036 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 2037 { 2038 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 2039 } 2040 else if (modeValue == 2041 "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 2042 { 2043 aResp->res.jsonValue["PowerMode"] = "OEM"; 2044 } 2045 else 2046 { 2047 // Any other values would be invalid 2048 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 2049 messages::internalError(aResp->res); 2050 } 2051 } 2052 2053 /** 2054 * @brief Retrieves system power mode 2055 * 2056 * @param[in] aResp Shared pointer for generating response message. 2057 * 2058 * @return None. 2059 */ 2060 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2061 { 2062 BMCWEB_LOG_DEBUG << "Get power mode."; 2063 2064 // Get Power Mode object path: 2065 crow::connections::systemBus->async_method_call( 2066 [aResp]( 2067 const boost::system::error_code ec, 2068 const std::vector<std::pair< 2069 std::string, 2070 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2071 subtree) { 2072 if (ec) 2073 { 2074 BMCWEB_LOG_DEBUG 2075 << "DBUS response error on Power.Mode GetSubTree " << ec; 2076 // This is an optional D-Bus object so just return if 2077 // error occurs 2078 return; 2079 } 2080 if (subtree.empty()) 2081 { 2082 // As noted above, this is an optional interface so just return 2083 // if there is no instance found 2084 return; 2085 } 2086 if (subtree.size() > 1) 2087 { 2088 // More then one PowerMode object is not supported and is an 2089 // error 2090 BMCWEB_LOG_DEBUG 2091 << "Found more than 1 system D-Bus Power.Mode objects: " 2092 << subtree.size(); 2093 messages::internalError(aResp->res); 2094 return; 2095 } 2096 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2097 { 2098 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2099 messages::internalError(aResp->res); 2100 return; 2101 } 2102 const std::string& path = subtree[0].first; 2103 const std::string& service = subtree[0].second.begin()->first; 2104 if (service.empty()) 2105 { 2106 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2107 messages::internalError(aResp->res); 2108 return; 2109 } 2110 // Valid Power Mode object found, now read the current value 2111 crow::connections::systemBus->async_method_call( 2112 [aResp](const boost::system::error_code ec, 2113 const std::variant<std::string>& pmode) { 2114 if (ec) 2115 { 2116 BMCWEB_LOG_DEBUG 2117 << "DBUS response error on PowerMode Get: " << ec; 2118 messages::internalError(aResp->res); 2119 return; 2120 } 2121 2122 const std::string* s = std::get_if<std::string>(&pmode); 2123 if (s == nullptr) 2124 { 2125 BMCWEB_LOG_DEBUG << "Unable to get PowerMode value"; 2126 messages::internalError(aResp->res); 2127 return; 2128 } 2129 2130 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 2131 {"Static", "MaximumPerformance", "PowerSaving"}; 2132 2133 BMCWEB_LOG_DEBUG << "Current power mode: " << *s; 2134 translatePowerMode(aResp, *s); 2135 }, 2136 service, path, "org.freedesktop.DBus.Properties", "Get", 2137 "xyz.openbmc_project.Control.Power.Mode", "PowerMode"); 2138 }, 2139 "xyz.openbmc_project.ObjectMapper", 2140 "/xyz/openbmc_project/object_mapper", 2141 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2142 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2143 } 2144 2145 /** 2146 * @brief Validate the specified mode is valid and return the PowerMode 2147 * name associated with that string 2148 * 2149 * @param[in] aResp Shared pointer for generating response message. 2150 * @param[in] modeString String representing the desired PowerMode 2151 * 2152 * @return PowerMode value or empty string if mode is not valid 2153 */ 2154 inline std::string 2155 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2156 const std::string& modeString) 2157 { 2158 std::string mode; 2159 2160 if (modeString == "Static") 2161 { 2162 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2163 } 2164 else if (modeString == "MaximumPerformance") 2165 { 2166 mode = 2167 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2168 } 2169 else if (modeString == "PowerSaving") 2170 { 2171 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2172 } 2173 else 2174 { 2175 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2176 } 2177 return mode; 2178 } 2179 2180 /** 2181 * @brief Sets system power mode. 2182 * 2183 * @param[in] aResp Shared pointer for generating response message. 2184 * @param[in] pmode System power mode from request. 2185 * 2186 * @return None. 2187 */ 2188 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2189 const std::string& pmode) 2190 { 2191 BMCWEB_LOG_DEBUG << "Set power mode."; 2192 2193 std::string powerMode = validatePowerMode(aResp, pmode); 2194 if (powerMode.empty()) 2195 { 2196 return; 2197 } 2198 2199 // Get Power Mode object path: 2200 crow::connections::systemBus->async_method_call( 2201 [aResp, powerMode]( 2202 const boost::system::error_code ec, 2203 const std::vector<std::pair< 2204 std::string, 2205 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2206 subtree) { 2207 if (ec) 2208 { 2209 BMCWEB_LOG_DEBUG 2210 << "DBUS response error on Power.Mode GetSubTree " << ec; 2211 // This is an optional D-Bus object, but user attempted to patch 2212 messages::internalError(aResp->res); 2213 return; 2214 } 2215 if (subtree.empty()) 2216 { 2217 // This is an optional D-Bus object, but user attempted to patch 2218 messages::resourceNotFound(aResp->res, "ComputerSystem", 2219 "PowerMode"); 2220 return; 2221 } 2222 if (subtree.size() > 1) 2223 { 2224 // More then one PowerMode object is not supported and is an 2225 // error 2226 BMCWEB_LOG_DEBUG 2227 << "Found more than 1 system D-Bus Power.Mode objects: " 2228 << subtree.size(); 2229 messages::internalError(aResp->res); 2230 return; 2231 } 2232 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2233 { 2234 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2235 messages::internalError(aResp->res); 2236 return; 2237 } 2238 const std::string& path = subtree[0].first; 2239 const std::string& service = subtree[0].second.begin()->first; 2240 if (service.empty()) 2241 { 2242 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2243 messages::internalError(aResp->res); 2244 return; 2245 } 2246 2247 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2248 << path; 2249 2250 // Set the Power Mode property 2251 crow::connections::systemBus->async_method_call( 2252 [aResp](const boost::system::error_code ec) { 2253 if (ec) 2254 { 2255 messages::internalError(aResp->res); 2256 return; 2257 } 2258 }, 2259 service, path, "org.freedesktop.DBus.Properties", "Set", 2260 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2261 std::variant<std::string>(powerMode)); 2262 }, 2263 "xyz.openbmc_project.ObjectMapper", 2264 "/xyz/openbmc_project/object_mapper", 2265 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2266 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2267 } 2268 2269 /** 2270 * @brief Translates watchdog timeout action DBUS property value to redfish. 2271 * 2272 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2273 * 2274 * @return Returns as a string, the timeout action in Redfish terms. If 2275 * translation cannot be done, returns an empty string. 2276 */ 2277 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2278 { 2279 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2280 { 2281 return "None"; 2282 } 2283 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2284 { 2285 return "ResetSystem"; 2286 } 2287 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2288 { 2289 return "PowerDown"; 2290 } 2291 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2292 { 2293 return "PowerCycle"; 2294 } 2295 2296 return ""; 2297 } 2298 2299 /** 2300 *@brief Translates timeout action from Redfish to DBUS property value. 2301 * 2302 *@param[in] rfAction The timeout action in Redfish. 2303 * 2304 *@return Returns as a string, the time_out action as expected by DBUS. 2305 *If translation cannot be done, returns an empty string. 2306 */ 2307 2308 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2309 { 2310 if (rfAction == "None") 2311 { 2312 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2313 } 2314 if (rfAction == "PowerCycle") 2315 { 2316 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2317 } 2318 if (rfAction == "PowerDown") 2319 { 2320 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2321 } 2322 if (rfAction == "ResetSystem") 2323 { 2324 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2325 } 2326 2327 return ""; 2328 } 2329 2330 /** 2331 * @brief Retrieves host watchdog timer properties over DBUS 2332 * 2333 * @param[in] aResp Shared pointer for completing asynchronous calls. 2334 * 2335 * @return None. 2336 */ 2337 inline void 2338 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2339 { 2340 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2341 crow::connections::systemBus->async_method_call( 2342 [aResp](const boost::system::error_code ec, 2343 PropertiesType& properties) { 2344 if (ec) 2345 { 2346 // watchdog service is stopped 2347 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2348 return; 2349 } 2350 2351 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2352 2353 nlohmann::json& hostWatchdogTimer = 2354 aResp->res.jsonValue["HostWatchdogTimer"]; 2355 2356 // watchdog service is running/enabled 2357 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2358 2359 for (const auto& property : properties) 2360 { 2361 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2362 if (property.first == "Enabled") 2363 { 2364 const bool* state = std::get_if<bool>(&property.second); 2365 2366 if (!state) 2367 { 2368 messages::internalError(aResp->res); 2369 return; 2370 } 2371 2372 hostWatchdogTimer["FunctionEnabled"] = *state; 2373 } 2374 else if (property.first == "ExpireAction") 2375 { 2376 const std::string* s = 2377 std::get_if<std::string>(&property.second); 2378 if (!s) 2379 { 2380 messages::internalError(aResp->res); 2381 return; 2382 } 2383 2384 std::string action = dbusToRfWatchdogAction(*s); 2385 if (action.empty()) 2386 { 2387 messages::internalError(aResp->res); 2388 return; 2389 } 2390 hostWatchdogTimer["TimeoutAction"] = action; 2391 } 2392 } 2393 }, 2394 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2395 "org.freedesktop.DBus.Properties", "GetAll", 2396 "xyz.openbmc_project.State.Watchdog"); 2397 } 2398 2399 /** 2400 * @brief Sets Host WatchDog Timer properties. 2401 * 2402 * @param[in] aResp Shared pointer for generating response message. 2403 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2404 * RF request. 2405 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2406 * 2407 * @return None. 2408 */ 2409 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2410 const std::optional<bool> wdtEnable, 2411 const std::optional<std::string>& wdtTimeOutAction) 2412 { 2413 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2414 2415 if (wdtTimeOutAction) 2416 { 2417 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2418 // check if TimeOut Action is Valid 2419 if (wdtTimeOutActStr.empty()) 2420 { 2421 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2422 << *wdtTimeOutAction; 2423 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2424 "TimeoutAction"); 2425 return; 2426 } 2427 2428 crow::connections::systemBus->async_method_call( 2429 [aResp](const boost::system::error_code ec) { 2430 if (ec) 2431 { 2432 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2433 messages::internalError(aResp->res); 2434 return; 2435 } 2436 }, 2437 "xyz.openbmc_project.Watchdog", 2438 "/xyz/openbmc_project/watchdog/host0", 2439 "org.freedesktop.DBus.Properties", "Set", 2440 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2441 std::variant<std::string>(wdtTimeOutActStr)); 2442 } 2443 2444 if (wdtEnable) 2445 { 2446 crow::connections::systemBus->async_method_call( 2447 [aResp](const boost::system::error_code ec) { 2448 if (ec) 2449 { 2450 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2451 messages::internalError(aResp->res); 2452 return; 2453 } 2454 }, 2455 "xyz.openbmc_project.Watchdog", 2456 "/xyz/openbmc_project/watchdog/host0", 2457 "org.freedesktop.DBus.Properties", "Set", 2458 "xyz.openbmc_project.State.Watchdog", "Enabled", 2459 std::variant<bool>(*wdtEnable)); 2460 } 2461 } 2462 2463 using ipsPropertiesType = 2464 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>; 2465 /** 2466 * @brief Parse the Idle Power Saver properties into json 2467 * 2468 * @param[in] aResp Shared pointer for completing asynchronous calls. 2469 * @param[in] properties IPS property data from DBus. 2470 * 2471 * @return true if successful 2472 */ 2473 inline bool parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2474 ipsPropertiesType& properties) 2475 { 2476 for (const auto& property : properties) 2477 { 2478 if (property.first == "Enabled") 2479 { 2480 const bool* state = std::get_if<bool>(&property.second); 2481 if (!state) 2482 { 2483 return false; 2484 } 2485 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state; 2486 } 2487 else if (property.first == "EnterUtilizationPercent") 2488 { 2489 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2490 if (!util) 2491 { 2492 return false; 2493 } 2494 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2495 } 2496 else if (property.first == "EnterDwellTime") 2497 { 2498 // Convert Dbus time from milliseconds to seconds 2499 const uint64_t* timeMilliseconds = 2500 std::get_if<uint64_t>(&property.second); 2501 if (!timeMilliseconds) 2502 { 2503 return false; 2504 } 2505 const std::chrono::duration<uint64_t, std::milli> ms( 2506 *timeMilliseconds); 2507 aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2508 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2509 .count(); 2510 } 2511 else if (property.first == "ExitUtilizationPercent") 2512 { 2513 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2514 if (!util) 2515 { 2516 return false; 2517 } 2518 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2519 } 2520 else if (property.first == "ExitDwellTime") 2521 { 2522 // Convert Dbus time from milliseconds to seconds 2523 const uint64_t* timeMilliseconds = 2524 std::get_if<uint64_t>(&property.second); 2525 if (!timeMilliseconds) 2526 { 2527 return false; 2528 } 2529 const std::chrono::duration<uint64_t, std::milli> ms( 2530 *timeMilliseconds); 2531 aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2532 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2533 .count(); 2534 } 2535 else 2536 { 2537 BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: " 2538 << property.first; 2539 } 2540 } 2541 2542 return true; 2543 } 2544 2545 /** 2546 * @brief Retrieves host watchdog timer properties over DBUS 2547 * 2548 * @param[in] aResp Shared pointer for completing asynchronous calls. 2549 * 2550 * @return None. 2551 */ 2552 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2553 { 2554 BMCWEB_LOG_DEBUG << "Get idle power saver parameters"; 2555 2556 // Get IdlePowerSaver object path: 2557 crow::connections::systemBus->async_method_call( 2558 [aResp]( 2559 const boost::system::error_code ec, 2560 const std::vector<std::pair< 2561 std::string, 2562 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2563 subtree) { 2564 if (ec) 2565 { 2566 BMCWEB_LOG_DEBUG 2567 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2568 << ec; 2569 messages::internalError(aResp->res); 2570 return; 2571 } 2572 if (subtree.empty()) 2573 { 2574 // This is an optional interface so just return 2575 // if there is no instance found 2576 BMCWEB_LOG_DEBUG << "No instances found"; 2577 return; 2578 } 2579 if (subtree.size() > 1) 2580 { 2581 // More then one PowerIdlePowerSaver object is not supported and 2582 // is an error 2583 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus " 2584 "Power.IdlePowerSaver objects: " 2585 << subtree.size(); 2586 messages::internalError(aResp->res); 2587 return; 2588 } 2589 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2590 { 2591 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2592 messages::internalError(aResp->res); 2593 return; 2594 } 2595 const std::string& path = subtree[0].first; 2596 const std::string& service = subtree[0].second.begin()->first; 2597 if (service.empty()) 2598 { 2599 BMCWEB_LOG_DEBUG 2600 << "Power.IdlePowerSaver service mapper error!"; 2601 messages::internalError(aResp->res); 2602 return; 2603 } 2604 2605 // Valid IdlePowerSaver object found, now read the current values 2606 crow::connections::systemBus->async_method_call( 2607 [aResp](const boost::system::error_code ec, 2608 ipsPropertiesType& properties) { 2609 if (ec) 2610 { 2611 BMCWEB_LOG_ERROR 2612 << "DBUS response error on IdlePowerSaver GetAll: " 2613 << ec; 2614 messages::internalError(aResp->res); 2615 return; 2616 } 2617 2618 if (parseIpsProperties(aResp, properties) == false) 2619 { 2620 messages::internalError(aResp->res); 2621 return; 2622 } 2623 }, 2624 service, path, "org.freedesktop.DBus.Properties", "GetAll", 2625 "xyz.openbmc_project.Control.Power.IdlePowerSaver"); 2626 }, 2627 "xyz.openbmc_project.ObjectMapper", 2628 "/xyz/openbmc_project/object_mapper", 2629 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2630 std::array<const char*, 1>{ 2631 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2632 2633 BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters"; 2634 } 2635 2636 /** 2637 * @brief Sets Idle Power Saver properties. 2638 * 2639 * @param[in] aResp Shared pointer for generating response message. 2640 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2641 * RF request. 2642 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2643 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2644 * before entering idle state. 2645 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2646 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2647 * before exiting idle state 2648 * 2649 * @return None. 2650 */ 2651 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2652 const std::optional<bool> ipsEnable, 2653 const std::optional<uint8_t> ipsEnterUtil, 2654 const std::optional<uint64_t> ipsEnterTime, 2655 const std::optional<uint8_t> ipsExitUtil, 2656 const std::optional<uint64_t> ipsExitTime) 2657 { 2658 BMCWEB_LOG_DEBUG << "Set idle power saver properties"; 2659 2660 // Get IdlePowerSaver object path: 2661 crow::connections::systemBus->async_method_call( 2662 [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2663 ipsExitTime]( 2664 const boost::system::error_code ec, 2665 const std::vector<std::pair< 2666 std::string, 2667 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2668 subtree) { 2669 if (ec) 2670 { 2671 BMCWEB_LOG_DEBUG 2672 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2673 << ec; 2674 messages::internalError(aResp->res); 2675 return; 2676 } 2677 if (subtree.empty()) 2678 { 2679 // This is an optional D-Bus object, but user attempted to patch 2680 messages::resourceNotFound(aResp->res, "ComputerSystem", 2681 "IdlePowerSaver"); 2682 return; 2683 } 2684 if (subtree.size() > 1) 2685 { 2686 // More then one PowerIdlePowerSaver object is not supported and 2687 // is an error 2688 BMCWEB_LOG_DEBUG 2689 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: " 2690 << subtree.size(); 2691 messages::internalError(aResp->res); 2692 return; 2693 } 2694 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2695 { 2696 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2697 messages::internalError(aResp->res); 2698 return; 2699 } 2700 const std::string& path = subtree[0].first; 2701 const std::string& service = subtree[0].second.begin()->first; 2702 if (service.empty()) 2703 { 2704 BMCWEB_LOG_DEBUG 2705 << "Power.IdlePowerSaver service mapper error!"; 2706 messages::internalError(aResp->res); 2707 return; 2708 } 2709 2710 // Valid Power IdlePowerSaver object found, now set any values that 2711 // need to be updated 2712 2713 if (ipsEnable) 2714 { 2715 crow::connections::systemBus->async_method_call( 2716 [aResp](const boost::system::error_code ec) { 2717 if (ec) 2718 { 2719 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2720 messages::internalError(aResp->res); 2721 return; 2722 } 2723 }, 2724 service, path, "org.freedesktop.DBus.Properties", "Set", 2725 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2726 "Enabled", std::variant<bool>(*ipsEnable)); 2727 } 2728 if (ipsEnterUtil) 2729 { 2730 crow::connections::systemBus->async_method_call( 2731 [aResp](const boost::system::error_code ec) { 2732 if (ec) 2733 { 2734 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2735 messages::internalError(aResp->res); 2736 return; 2737 } 2738 }, 2739 service, path, "org.freedesktop.DBus.Properties", "Set", 2740 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2741 "EnterUtilizationPercent", 2742 std::variant<uint8_t>(*ipsEnterUtil)); 2743 } 2744 if (ipsEnterTime) 2745 { 2746 // Convert from seconds into milliseconds for DBus 2747 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2748 crow::connections::systemBus->async_method_call( 2749 [aResp](const boost::system::error_code ec) { 2750 if (ec) 2751 { 2752 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2753 messages::internalError(aResp->res); 2754 return; 2755 } 2756 }, 2757 service, path, "org.freedesktop.DBus.Properties", "Set", 2758 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2759 "EnterDwellTime", std::variant<uint64_t>(timeMilliseconds)); 2760 } 2761 if (ipsExitUtil) 2762 { 2763 crow::connections::systemBus->async_method_call( 2764 [aResp](const boost::system::error_code ec) { 2765 if (ec) 2766 { 2767 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2768 messages::internalError(aResp->res); 2769 return; 2770 } 2771 }, 2772 service, path, "org.freedesktop.DBus.Properties", "Set", 2773 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2774 "ExitUtilizationPercent", 2775 std::variant<uint8_t>(*ipsExitUtil)); 2776 } 2777 if (ipsExitTime) 2778 { 2779 // Convert from seconds into milliseconds for DBus 2780 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2781 crow::connections::systemBus->async_method_call( 2782 [aResp](const boost::system::error_code ec) { 2783 if (ec) 2784 { 2785 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2786 messages::internalError(aResp->res); 2787 return; 2788 } 2789 }, 2790 service, path, "org.freedesktop.DBus.Properties", "Set", 2791 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2792 "ExitDwellTime", std::variant<uint64_t>(timeMilliseconds)); 2793 } 2794 }, 2795 "xyz.openbmc_project.ObjectMapper", 2796 "/xyz/openbmc_project/object_mapper", 2797 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2798 std::array<const char*, 1>{ 2799 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2800 2801 BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters"; 2802 } 2803 2804 /** 2805 * SystemsCollection derived class for delivering ComputerSystems Collection 2806 * Schema 2807 */ 2808 inline void requestRoutesSystemsCollection(App& app) 2809 { 2810 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2811 .privileges(redfish::privileges::getComputerSystemCollection) 2812 .methods(boost::beast::http::verb::get)( 2813 [](const crow::Request& /*req*/, 2814 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2815 asyncResp->res.jsonValue["@odata.type"] = 2816 "#ComputerSystemCollection.ComputerSystemCollection"; 2817 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2818 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2819 2820 crow::connections::systemBus->async_method_call( 2821 [asyncResp](const boost::system::error_code ec, 2822 const std::variant<std::string>& /*hostName*/) { 2823 nlohmann::json& ifaceArray = 2824 asyncResp->res.jsonValue["Members"]; 2825 ifaceArray = nlohmann::json::array(); 2826 auto& count = 2827 asyncResp->res.jsonValue["Members@odata.count"]; 2828 ifaceArray.push_back( 2829 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2830 count = ifaceArray.size(); 2831 if (!ec) 2832 { 2833 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2834 ifaceArray.push_back( 2835 {{"@odata.id", 2836 "/redfish/v1/Systems/hypervisor"}}); 2837 count = ifaceArray.size(); 2838 } 2839 }, 2840 "xyz.openbmc_project.Settings", 2841 "/xyz/openbmc_project/network/hypervisor", 2842 "org.freedesktop.DBus.Properties", "Get", 2843 "xyz.openbmc_project.Network.SystemConfiguration", 2844 "HostName"); 2845 }); 2846 } 2847 2848 /** 2849 * Function transceives data with dbus directly. 2850 */ 2851 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2852 { 2853 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2854 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2855 constexpr char const* interfaceName = 2856 "xyz.openbmc_project.Control.Host.NMI"; 2857 constexpr char const* method = "NMI"; 2858 2859 crow::connections::systemBus->async_method_call( 2860 [asyncResp](const boost::system::error_code ec) { 2861 if (ec) 2862 { 2863 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2864 messages::internalError(asyncResp->res); 2865 return; 2866 } 2867 messages::success(asyncResp->res); 2868 }, 2869 serviceName, objectPath, interfaceName, method); 2870 } 2871 2872 /** 2873 * SystemActionsReset class supports handle POST method for Reset action. 2874 * The class retrieves and sends data directly to D-Bus. 2875 */ 2876 inline void requestRoutesSystemActionsReset(App& app) 2877 { 2878 /** 2879 * Function handles POST method request. 2880 * Analyzes POST body message before sends Reset request data to D-Bus. 2881 */ 2882 BMCWEB_ROUTE(app, 2883 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2884 .privileges(redfish::privileges::postComputerSystem) 2885 .methods( 2886 boost::beast::http::verb:: 2887 post)([](const crow::Request& req, 2888 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2889 std::string resetType; 2890 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2891 resetType)) 2892 { 2893 return; 2894 } 2895 2896 // Get the command and host vs. chassis 2897 std::string command; 2898 bool hostCommand; 2899 if ((resetType == "On") || (resetType == "ForceOn")) 2900 { 2901 command = "xyz.openbmc_project.State.Host.Transition.On"; 2902 hostCommand = true; 2903 } 2904 else if (resetType == "ForceOff") 2905 { 2906 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2907 hostCommand = false; 2908 } 2909 else if (resetType == "ForceRestart") 2910 { 2911 command = 2912 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2913 hostCommand = true; 2914 } 2915 else if (resetType == "GracefulShutdown") 2916 { 2917 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2918 hostCommand = true; 2919 } 2920 else if (resetType == "GracefulRestart") 2921 { 2922 command = 2923 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2924 hostCommand = true; 2925 } 2926 else if (resetType == "PowerCycle") 2927 { 2928 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2929 hostCommand = true; 2930 } 2931 else if (resetType == "Nmi") 2932 { 2933 doNMI(asyncResp); 2934 return; 2935 } 2936 else 2937 { 2938 messages::actionParameterUnknown(asyncResp->res, "Reset", 2939 resetType); 2940 return; 2941 } 2942 2943 if (hostCommand) 2944 { 2945 crow::connections::systemBus->async_method_call( 2946 [asyncResp, resetType](const boost::system::error_code ec) { 2947 if (ec) 2948 { 2949 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2950 if (ec.value() == 2951 boost::asio::error::invalid_argument) 2952 { 2953 messages::actionParameterNotSupported( 2954 asyncResp->res, resetType, "Reset"); 2955 } 2956 else 2957 { 2958 messages::internalError(asyncResp->res); 2959 } 2960 return; 2961 } 2962 messages::success(asyncResp->res); 2963 }, 2964 "xyz.openbmc_project.State.Host", 2965 "/xyz/openbmc_project/state/host0", 2966 "org.freedesktop.DBus.Properties", "Set", 2967 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2968 std::variant<std::string>{command}); 2969 } 2970 else 2971 { 2972 crow::connections::systemBus->async_method_call( 2973 [asyncResp, resetType](const boost::system::error_code ec) { 2974 if (ec) 2975 { 2976 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2977 if (ec.value() == 2978 boost::asio::error::invalid_argument) 2979 { 2980 messages::actionParameterNotSupported( 2981 asyncResp->res, resetType, "Reset"); 2982 } 2983 else 2984 { 2985 messages::internalError(asyncResp->res); 2986 } 2987 return; 2988 } 2989 messages::success(asyncResp->res); 2990 }, 2991 "xyz.openbmc_project.State.Chassis", 2992 "/xyz/openbmc_project/state/chassis0", 2993 "org.freedesktop.DBus.Properties", "Set", 2994 "xyz.openbmc_project.State.Chassis", 2995 "RequestedPowerTransition", 2996 std::variant<std::string>{command}); 2997 } 2998 }); 2999 } 3000 3001 /** 3002 * Systems derived class for delivering Computer Systems Schema. 3003 */ 3004 inline void requestRoutesSystems(App& app) 3005 { 3006 3007 /** 3008 * Functions triggers appropriate requests on DBus 3009 */ 3010 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 3011 .privileges(redfish::privileges::getComputerSystem) 3012 .methods( 3013 boost::beast::http::verb:: 3014 get)([](const crow::Request&, 3015 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3016 asyncResp->res.jsonValue["@odata.type"] = 3017 "#ComputerSystem.v1_16_0.ComputerSystem"; 3018 asyncResp->res.jsonValue["Name"] = "system"; 3019 asyncResp->res.jsonValue["Id"] = "system"; 3020 asyncResp->res.jsonValue["SystemType"] = "Physical"; 3021 asyncResp->res.jsonValue["Description"] = "Computer System"; 3022 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 3023 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 3024 "Disabled"; 3025 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 3026 uint64_t(0); 3027 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 3028 "Disabled"; 3029 asyncResp->res.jsonValue["@odata.id"] = 3030 "/redfish/v1/Systems/system"; 3031 3032 asyncResp->res.jsonValue["Processors"] = { 3033 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 3034 asyncResp->res.jsonValue["Memory"] = { 3035 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 3036 asyncResp->res.jsonValue["Storage"] = { 3037 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 3038 3039 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 3040 {"target", 3041 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 3042 {"@Redfish.ActionInfo", 3043 "/redfish/v1/Systems/system/ResetActionInfo"}}; 3044 3045 asyncResp->res.jsonValue["LogServices"] = { 3046 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 3047 3048 asyncResp->res.jsonValue["Bios"] = { 3049 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 3050 3051 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 3052 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 3053 3054 asyncResp->res.jsonValue["Status"] = { 3055 {"Health", "OK"}, 3056 {"State", "Enabled"}, 3057 }; 3058 3059 // Fill in SerialConsole info 3060 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 3061 15; 3062 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 3063 {"ServiceEnabled", true}, 3064 }; 3065 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 3066 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 3067 {"ServiceEnabled", true}, 3068 {"Port", 2200}, 3069 // https://github.com/openbmc/docs/blob/master/console.md 3070 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 3071 }; 3072 3073 #ifdef BMCWEB_ENABLE_KVM 3074 // Fill in GraphicalConsole info 3075 asyncResp->res.jsonValue["GraphicalConsole"] = { 3076 {"ServiceEnabled", true}, 3077 {"MaxConcurrentSessions", 4}, 3078 {"ConnectTypesSupported", {"KVMIP"}}, 3079 }; 3080 #endif // BMCWEB_ENABLE_KVM 3081 constexpr const std::array<const char*, 4> inventoryForSystems = { 3082 "xyz.openbmc_project.Inventory.Item.Dimm", 3083 "xyz.openbmc_project.Inventory.Item.Cpu", 3084 "xyz.openbmc_project.Inventory.Item.Drive", 3085 "xyz.openbmc_project.Inventory.Item.StorageController"}; 3086 3087 auto health = std::make_shared<HealthPopulate>(asyncResp); 3088 crow::connections::systemBus->async_method_call( 3089 [health](const boost::system::error_code ec, 3090 std::vector<std::string>& resp) { 3091 if (ec) 3092 { 3093 // no inventory 3094 return; 3095 } 3096 3097 health->inventory = std::move(resp); 3098 }, 3099 "xyz.openbmc_project.ObjectMapper", 3100 "/xyz/openbmc_project/object_mapper", 3101 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 3102 int32_t(0), inventoryForSystems); 3103 3104 health->populate(); 3105 3106 getMainChassisId( 3107 asyncResp, [](const std::string& chassisId, 3108 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 3109 aRsp->res.jsonValue["Links"]["Chassis"] = { 3110 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 3111 }); 3112 3113 getLocationIndicatorActive(asyncResp); 3114 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 3115 getIndicatorLedState(asyncResp); 3116 getComputerSystem(asyncResp, health); 3117 getHostState(asyncResp); 3118 getBootProperties(asyncResp); 3119 getBootProgress(asyncResp); 3120 getPCIeDeviceList(asyncResp, "PCIeDevices"); 3121 getHostWatchdogTimer(asyncResp); 3122 getPowerRestorePolicy(asyncResp); 3123 getAutomaticRetry(asyncResp); 3124 getLastResetTime(asyncResp); 3125 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 3126 getProvisioningStatus(asyncResp); 3127 #endif 3128 getTrustedModuleRequiredToBoot(asyncResp); 3129 getPowerMode(asyncResp); 3130 getIdlePowerSaver(asyncResp); 3131 }); 3132 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 3133 .privileges(redfish::privileges::patchComputerSystem) 3134 .methods(boost::beast::http::verb::patch)( 3135 [](const crow::Request& req, 3136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3137 std::optional<bool> locationIndicatorActive; 3138 std::optional<std::string> indicatorLed; 3139 std::optional<nlohmann::json> bootProps; 3140 std::optional<nlohmann::json> wdtTimerProps; 3141 std::optional<std::string> assetTag; 3142 std::optional<std::string> powerRestorePolicy; 3143 std::optional<std::string> powerMode; 3144 std::optional<nlohmann::json> ipsProps; 3145 if (!json_util::readJson( 3146 req, asyncResp->res, "IndicatorLED", indicatorLed, 3147 "LocationIndicatorActive", locationIndicatorActive, 3148 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 3149 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 3150 assetTag, "PowerMode", powerMode, "IdlePowerSaver", 3151 ipsProps)) 3152 { 3153 return; 3154 } 3155 3156 asyncResp->res.result(boost::beast::http::status::no_content); 3157 3158 if (assetTag) 3159 { 3160 setAssetTag(asyncResp, *assetTag); 3161 } 3162 3163 if (wdtTimerProps) 3164 { 3165 std::optional<bool> wdtEnable; 3166 std::optional<std::string> wdtTimeOutAction; 3167 3168 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 3169 "FunctionEnabled", wdtEnable, 3170 "TimeoutAction", wdtTimeOutAction)) 3171 { 3172 return; 3173 } 3174 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3175 } 3176 3177 if (bootProps) 3178 { 3179 std::optional<std::string> bootSource; 3180 std::optional<std::string> bootType; 3181 std::optional<std::string> bootEnable; 3182 std::optional<std::string> automaticRetryConfig; 3183 std::optional<bool> trustedModuleRequiredToBoot; 3184 3185 if (!json_util::readJson( 3186 *bootProps, asyncResp->res, 3187 "BootSourceOverrideTarget", bootSource, 3188 "BootSourceOverrideMode", bootType, 3189 "BootSourceOverrideEnabled", bootEnable, 3190 "AutomaticRetryConfig", automaticRetryConfig, 3191 "TrustedModuleRequiredToBoot", 3192 trustedModuleRequiredToBoot)) 3193 { 3194 return; 3195 } 3196 3197 if (bootSource || bootType || bootEnable) 3198 { 3199 setBootProperties(asyncResp, bootSource, bootType, 3200 bootEnable); 3201 } 3202 if (automaticRetryConfig) 3203 { 3204 setAutomaticRetry(asyncResp, *automaticRetryConfig); 3205 } 3206 3207 if (trustedModuleRequiredToBoot) 3208 { 3209 setTrustedModuleRequiredToBoot( 3210 asyncResp, *trustedModuleRequiredToBoot); 3211 } 3212 } 3213 3214 if (locationIndicatorActive) 3215 { 3216 setLocationIndicatorActive(asyncResp, 3217 *locationIndicatorActive); 3218 } 3219 3220 // TODO (Gunnar): Remove IndicatorLED after enough time has 3221 // passed 3222 if (indicatorLed) 3223 { 3224 setIndicatorLedState(asyncResp, *indicatorLed); 3225 asyncResp->res.addHeader( 3226 boost::beast::http::field::warning, 3227 "299 - \"IndicatorLED is deprecated. Use " 3228 "LocationIndicatorActive instead.\""); 3229 } 3230 3231 if (powerRestorePolicy) 3232 { 3233 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3234 } 3235 3236 if (powerMode) 3237 { 3238 setPowerMode(asyncResp, *powerMode); 3239 } 3240 3241 if (ipsProps) 3242 { 3243 std::optional<bool> ipsEnable; 3244 std::optional<uint8_t> ipsEnterUtil; 3245 std::optional<uint64_t> ipsEnterTime; 3246 std::optional<uint8_t> ipsExitUtil; 3247 std::optional<uint64_t> ipsExitTime; 3248 3249 if (!json_util::readJson( 3250 *ipsProps, asyncResp->res, "Enabled", ipsEnable, 3251 "EnterUtilizationPercent", ipsEnterUtil, 3252 "EnterDwellTimeSeconds", ipsEnterTime, 3253 "ExitUtilizationPercent", ipsExitUtil, 3254 "ExitDwellTimeSeconds", ipsExitTime)) 3255 { 3256 return; 3257 } 3258 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, 3259 ipsEnterTime, ipsExitUtil, ipsExitTime); 3260 } 3261 }); 3262 } 3263 3264 /** 3265 * SystemResetActionInfo derived class for delivering Computer Systems 3266 * ResetType AllowableValues using ResetInfo schema. 3267 */ 3268 inline void requestRoutesSystemResetActionInfo(App& app) 3269 { 3270 3271 /** 3272 * Functions triggers appropriate requests on DBus 3273 */ 3274 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 3275 .privileges(redfish::privileges::getActionInfo) 3276 .methods(boost::beast::http::verb::get)( 3277 [](const crow::Request&, 3278 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3279 asyncResp->res.jsonValue = { 3280 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 3281 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 3282 {"Name", "Reset Action Info"}, 3283 {"Id", "ResetActionInfo"}, 3284 {"Parameters", 3285 {{{"Name", "ResetType"}, 3286 {"Required", true}, 3287 {"DataType", "String"}, 3288 {"AllowableValues", 3289 {"On", "ForceOff", "ForceOn", "ForceRestart", 3290 "GracefulRestart", "GracefulShutdown", "PowerCycle", 3291 "Nmi"}}}}}}; 3292 }); 3293 } 3294 } // namespace redfish 3295