1 /** 2 * Copyright © 2019 IBM 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 #include "config.h" 17 18 #include "data_interface.hpp" 19 20 #include "util.hpp" 21 22 #include <fmt/format.h> 23 24 #include <phosphor-logging/log.hpp> 25 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp> 26 27 #include <fstream> 28 #include <iterator> 29 30 // Use a timeout of 10s for D-Bus calls so if there are 31 // timeouts the callers of the PEL creation method won't 32 // also timeout. 33 constexpr auto dbusTimeout = 10000000; 34 35 namespace openpower 36 { 37 namespace pels 38 { 39 40 namespace service_name 41 { 42 constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; 43 constexpr auto vpdManager = "com.ibm.VPD.Manager"; 44 constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager"; 45 constexpr auto logSetting = "xyz.openbmc_project.Settings"; 46 constexpr auto hwIsolation = "org.open_power.HardwareIsolation"; 47 constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager"; 48 constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw"; 49 } // namespace service_name 50 51 namespace object_path 52 { 53 constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper"; 54 constexpr auto systemInv = "/xyz/openbmc_project/inventory/system"; 55 constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis"; 56 constexpr auto motherBoardInv = 57 "/xyz/openbmc_project/inventory/system/chassis/motherboard"; 58 constexpr auto baseInv = "/xyz/openbmc_project/inventory"; 59 constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0"; 60 constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0"; 61 constexpr auto hostState = "/xyz/openbmc_project/state/host0"; 62 constexpr auto pldm = "/xyz/openbmc_project/pldm"; 63 constexpr auto enableHostPELs = 64 "/xyz/openbmc_project/logging/send_event_logs_to_host"; 65 constexpr auto vpdManager = "/com/ibm/VPD/Manager"; 66 constexpr auto logSetting = "/xyz/openbmc_project/logging/settings"; 67 constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation"; 68 constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager"; 69 constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0"; 70 } // namespace object_path 71 72 namespace interface 73 { 74 constexpr auto dbusProperty = "org.freedesktop.DBus.Properties"; 75 constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; 76 constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset"; 77 constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress"; 78 constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester"; 79 constexpr auto enable = "xyz.openbmc_project.Object.Enable"; 80 constexpr auto bmcState = "xyz.openbmc_project.State.BMC"; 81 constexpr auto chassisState = "xyz.openbmc_project.State.Chassis"; 82 constexpr auto hostState = "xyz.openbmc_project.State.Host"; 83 constexpr auto invMotherboard = 84 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"; 85 constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI"; 86 constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP"; 87 constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode"; 88 constexpr auto compatible = 89 "xyz.openbmc_project.Configuration.IBMCompatibleSystem"; 90 constexpr auto vpdManager = "com.ibm.VPD.Manager"; 91 constexpr auto ledGroup = "xyz.openbmc_project.Led.Group"; 92 constexpr auto operationalStatus = 93 "xyz.openbmc_project.State.Decorator.OperationalStatus"; 94 constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings"; 95 constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions"; 96 constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry"; 97 constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress"; 98 constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create"; 99 constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry"; 100 constexpr auto association = "xyz.openbmc_project.Association"; 101 constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager"; 102 constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw"; 103 } // namespace interface 104 105 using namespace sdbusplus::xyz::openbmc_project::State::Boot::server; 106 using namespace phosphor::logging; 107 108 std::pair<std::string, std::string> 109 DataInterfaceBase::extractConnectorFromLocCode( 110 const std::string& locationCode) 111 { 112 auto base = locationCode; 113 std::string connector{}; 114 115 auto pos = base.find("-T"); 116 if (pos != std::string::npos) 117 { 118 connector = base.substr(pos); 119 base = base.substr(0, pos); 120 } 121 122 return {base, connector}; 123 } 124 125 DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus) 126 { 127 readBMCFWVersion(); 128 readServerFWVersion(); 129 readBMCFWVersionID(); 130 131 // Watch the BootProgress property 132 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>( 133 bus, object_path::hostState, interface::bootProgress, "BootProgress", 134 *this, [this](const auto& value) { 135 this->_bootState = std::get<std::string>(value); 136 auto status = Progress::convertProgressStagesFromString( 137 std::get<std::string>(value)); 138 139 if ((status == Progress::ProgressStages::SystemInitComplete) || 140 (status == Progress::ProgressStages::OSRunning)) 141 { 142 setHostUp(true); 143 } 144 else 145 { 146 setHostUp(false); 147 } 148 })); 149 150 // Watch the host PEL enable property 151 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>( 152 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this, 153 [this](const auto& value) { 154 if (std::get<bool>(value) != this->_sendPELsToHost) 155 { 156 log<level::INFO>( 157 fmt::format("The send PELs to host setting changed to {}", 158 std::get<bool>(value)) 159 .c_str()); 160 } 161 this->_sendPELsToHost = std::get<bool>(value); 162 })); 163 164 // Watch the BMCState property 165 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>( 166 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState", 167 *this, [this](const auto& value) { 168 this->_bmcState = std::get<std::string>(value); 169 })); 170 171 // Watch the chassis current and requested power state properties 172 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>( 173 bus, object_path::chassisState, interface::chassisState, *this, 174 [this](const auto& properties) { 175 auto state = properties.find("CurrentPowerState"); 176 if (state != properties.end()) 177 { 178 this->_chassisState = std::get<std::string>(state->second); 179 } 180 181 auto trans = properties.find("RequestedPowerTransition"); 182 if (trans != properties.end()) 183 { 184 this->_chassisTransition = std::get<std::string>(trans->second); 185 } 186 })); 187 188 // Watch the CurrentHostState property 189 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>( 190 bus, object_path::hostState, interface::hostState, "CurrentHostState", 191 *this, [this](const auto& value) { 192 this->_hostState = std::get<std::string>(value); 193 })); 194 195 // Watch the BaseBIOSTable property for the hmc managed attribute 196 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>( 197 bus, object_path::biosConfigMgr, interface::biosConfigMgr, 198 "BaseBIOSTable", service_name::biosConfigMgr, *this, 199 [this](const auto& value) { 200 const auto& attributes = std::get<BiosAttributes>(value); 201 202 auto it = attributes.find("pvm_hmc_managed"); 203 if (it != attributes.end()) 204 { 205 const auto& currentValVariant = std::get<5>(it->second); 206 auto currentVal = std::get_if<std::string>(¤tValVariant); 207 if (currentVal) 208 { 209 this->_hmcManaged = (*currentVal == "Enabled") ? true : false; 210 } 211 } 212 })); 213 } 214 215 DBusPropertyMap 216 DataInterface::getAllProperties(const std::string& service, 217 const std::string& objectPath, 218 const std::string& interface) const 219 { 220 DBusPropertyMap properties; 221 222 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), 223 interface::dbusProperty, "GetAll"); 224 method.append(interface); 225 auto reply = _bus.call(method, dbusTimeout); 226 227 reply.read(properties); 228 229 return properties; 230 } 231 232 void DataInterface::getProperty(const std::string& service, 233 const std::string& objectPath, 234 const std::string& interface, 235 const std::string& property, 236 DBusValue& value) const 237 { 238 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), 239 interface::dbusProperty, "Get"); 240 method.append(interface, property); 241 auto reply = _bus.call(method, dbusTimeout); 242 243 reply.read(value); 244 } 245 246 DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const 247 { 248 auto method = _bus.new_method_call( 249 service_name::objectMapper, object_path::objectMapper, 250 interface::objectMapper, "GetSubTreePaths"); 251 252 method.append(std::string{"/"}, 0, interfaces); 253 254 auto reply = _bus.call(method, dbusTimeout); 255 256 DBusPathList paths; 257 reply.read(paths); 258 259 return paths; 260 } 261 262 DBusService DataInterface::getService(const std::string& objectPath, 263 const std::string& interface) const 264 { 265 auto method = _bus.new_method_call(service_name::objectMapper, 266 object_path::objectMapper, 267 interface::objectMapper, "GetObject"); 268 269 method.append(objectPath, std::vector<std::string>({interface})); 270 271 auto reply = _bus.call(method, dbusTimeout); 272 273 std::map<DBusService, DBusInterfaceList> response; 274 reply.read(response); 275 276 if (!response.empty()) 277 { 278 return response.begin()->first; 279 } 280 281 return std::string{}; 282 } 283 284 void DataInterface::readBMCFWVersion() 285 { 286 _bmcFWVersion = 287 phosphor::logging::util::getOSReleaseValue("VERSION").value_or(""); 288 } 289 290 void DataInterface::readServerFWVersion() 291 { 292 auto value = 293 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or(""); 294 if ((value != "") && (value.find_last_of(')') != std::string::npos)) 295 { 296 std::size_t pos = value.find_first_of('(') + 1; 297 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos); 298 } 299 } 300 301 void DataInterface::readBMCFWVersionID() 302 { 303 _bmcFWVersionID = 304 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or(""); 305 } 306 307 std::string DataInterface::getMachineTypeModel() const 308 { 309 std::string model; 310 try 311 { 312 auto service = getService(object_path::systemInv, interface::invAsset); 313 if (!service.empty()) 314 { 315 DBusValue value; 316 getProperty(service, object_path::systemInv, interface::invAsset, 317 "Model", value); 318 319 model = std::get<std::string>(value); 320 } 321 } 322 catch (const std::exception& e) 323 { 324 log<level::WARNING>(fmt::format("Failed reading Model property from " 325 "Interface: {} exception: {}", 326 interface::invAsset, e.what()) 327 .c_str()); 328 } 329 330 return model; 331 } 332 333 std::string DataInterface::getMachineSerialNumber() const 334 { 335 std::string sn; 336 try 337 { 338 auto service = getService(object_path::systemInv, interface::invAsset); 339 if (!service.empty()) 340 { 341 DBusValue value; 342 getProperty(service, object_path::systemInv, interface::invAsset, 343 "SerialNumber", value); 344 345 sn = std::get<std::string>(value); 346 } 347 } 348 catch (const std::exception& e) 349 { 350 log<level::WARNING>( 351 fmt::format("Failed reading SerialNumber property from " 352 "Interface: {} exception: {}", 353 interface::invAsset, e.what()) 354 .c_str()); 355 } 356 357 return sn; 358 } 359 360 std::string DataInterface::getMotherboardCCIN() const 361 { 362 std::string ccin; 363 364 try 365 { 366 auto service = getService(object_path::motherBoardInv, 367 interface::viniRecordVPD); 368 if (!service.empty()) 369 { 370 DBusValue value; 371 getProperty(service, object_path::motherBoardInv, 372 interface::viniRecordVPD, "CC", value); 373 374 auto cc = std::get<std::vector<uint8_t>>(value); 375 ccin = std::string{cc.begin(), cc.end()}; 376 } 377 } 378 catch (const std::exception& e) 379 { 380 log<level::WARNING>( 381 fmt::format("Failed reading Motherboard CCIN property from " 382 "Interface: {} exception: {}", 383 interface::viniRecordVPD, e.what()) 384 .c_str()); 385 } 386 387 return ccin; 388 } 389 390 std::vector<uint8_t> DataInterface::getSystemIMKeyword() const 391 { 392 std::vector<uint8_t> systemIM; 393 394 try 395 { 396 auto service = getService(object_path::motherBoardInv, 397 interface::vsbpRecordVPD); 398 if (!service.empty()) 399 { 400 DBusValue value; 401 getProperty(service, object_path::motherBoardInv, 402 interface::vsbpRecordVPD, "IM", value); 403 404 systemIM = std::get<std::vector<uint8_t>>(value); 405 } 406 } 407 catch (const std::exception& e) 408 { 409 log<level::WARNING>( 410 fmt::format("Failed reading System IM property from " 411 "Interface: {} exception: {}", 412 interface::vsbpRecordVPD, e.what()) 413 .c_str()); 414 } 415 416 return systemIM; 417 } 418 419 void DataInterface::getHWCalloutFields(const std::string& inventoryPath, 420 std::string& fruPartNumber, 421 std::string& ccin, 422 std::string& serialNumber) const 423 { 424 // For now, attempt to get all of the properties directly on the path 425 // passed in. In the future, may need to make use of an algorithm 426 // to figure out which inventory objects actually hold these 427 // interfaces in the case of non FRUs, or possibly another service 428 // will provide this info. Any missing interfaces will result 429 // in exceptions being thrown. 430 431 auto service = getService(inventoryPath, interface::viniRecordVPD); 432 433 auto properties = getAllProperties(service, inventoryPath, 434 interface::viniRecordVPD); 435 436 auto value = std::get<std::vector<uint8_t>>(properties["FN"]); 437 fruPartNumber = std::string{value.begin(), value.end()}; 438 439 value = std::get<std::vector<uint8_t>>(properties["CC"]); 440 ccin = std::string{value.begin(), value.end()}; 441 442 value = std::get<std::vector<uint8_t>>(properties["SN"]); 443 serialNumber = std::string{value.begin(), value.end()}; 444 } 445 446 std::string 447 DataInterface::getLocationCode(const std::string& inventoryPath) const 448 { 449 auto service = getService(inventoryPath, interface::locCode); 450 451 DBusValue locCode; 452 getProperty(service, inventoryPath, interface::locCode, "LocationCode", 453 locCode); 454 455 return std::get<std::string>(locCode); 456 } 457 458 std::string 459 DataInterface::addLocationCodePrefix(const std::string& locationCode) 460 { 461 static const std::string locationCodePrefix{"Ufcs-"}; 462 463 // Technically there are 2 location code prefixes, Ufcs and Umts, so 464 // if it already starts with a U then don't need to do anything. 465 if (locationCode.front() != 'U') 466 { 467 return locationCodePrefix + locationCode; 468 } 469 470 return locationCode; 471 } 472 473 std::string DataInterface::expandLocationCode(const std::string& locationCode, 474 uint16_t /*node*/) const 475 { 476 // Location codes for connectors are the location code of the FRU they are 477 // on, plus a '-Tx' segment. Remove this last segment before expanding it 478 // and then add it back in afterwards. This way, the connector doesn't have 479 // to be in the model just so that it can be expanded. 480 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode); 481 482 auto method = 483 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager, 484 interface::vpdManager, "GetExpandedLocationCode"); 485 486 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0)); 487 488 auto reply = _bus.call(method, dbusTimeout); 489 490 std::string expandedLocationCode; 491 reply.read(expandedLocationCode); 492 493 if (!connectorLoc.empty()) 494 { 495 expandedLocationCode += connectorLoc; 496 } 497 498 return expandedLocationCode; 499 } 500 501 std::vector<std::string> 502 DataInterface::getInventoryFromLocCode(const std::string& locationCode, 503 uint16_t node, bool expanded) const 504 { 505 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode" 506 : "GetFRUsByUnexpandedLocationCode"; 507 508 // Remove the connector segment, if present, so that this method call 509 // returns an inventory path that getHWCalloutFields() can be used with. 510 // (The serial number, etc, aren't stored on the connector in the 511 // inventory, and may not even be modeled.) 512 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode); 513 514 auto method = 515 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager, 516 interface::vpdManager, methodName.c_str()); 517 518 if (expanded) 519 { 520 method.append(baseLoc); 521 } 522 else 523 { 524 method.append(addLocationCodePrefix(baseLoc), node); 525 } 526 527 auto reply = _bus.call(method, dbusTimeout); 528 529 std::vector<sdbusplus::message::object_path> entries; 530 reply.read(entries); 531 532 std::vector<std::string> paths; 533 534 // Note: The D-Bus method will fail if nothing found. 535 std::for_each(entries.begin(), entries.end(), 536 [&paths](const auto& path) { paths.push_back(path); }); 537 538 return paths; 539 } 540 541 void DataInterface::assertLEDGroup(const std::string& ledGroup, 542 bool value) const 543 { 544 DBusValue variant = value; 545 auto method = _bus.new_method_call(service_name::ledGroupManager, 546 ledGroup.c_str(), 547 interface::dbusProperty, "Set"); 548 method.append(interface::ledGroup, "Asserted", variant); 549 _bus.call(method, dbusTimeout); 550 } 551 552 void DataInterface::setFunctional(const std::string& objectPath, 553 bool value) const 554 { 555 DBusValue variant = value; 556 auto service = getService(objectPath, interface::operationalStatus); 557 558 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), 559 interface::dbusProperty, "Set"); 560 561 method.append(interface::operationalStatus, "Functional", variant); 562 _bus.call(method, dbusTimeout); 563 } 564 565 using AssociationTuple = std::tuple<std::string, std::string, std::string>; 566 using AssociationsProperty = std::vector<AssociationTuple>; 567 568 void DataInterface::setCriticalAssociation(const std::string& objectPath) const 569 { 570 DBusValue getAssociationValue; 571 572 auto service = getService(objectPath, interface::associationDef); 573 574 getProperty(service, objectPath, interface::associationDef, "Associations", 575 getAssociationValue); 576 577 auto association = std::get<AssociationsProperty>(getAssociationValue); 578 579 AssociationTuple critAssociation{ 580 "health_rollup", "critical", 581 "/xyz/openbmc_project/inventory/system/chassis"}; 582 583 if (std::find(association.begin(), association.end(), critAssociation) == 584 association.end()) 585 { 586 association.push_back(critAssociation); 587 DBusValue setAssociationValue = association; 588 589 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), 590 interface::dbusProperty, "Set"); 591 592 method.append(interface::associationDef, "Associations", 593 setAssociationValue); 594 _bus.call(method, dbusTimeout); 595 } 596 } 597 598 std::vector<std::string> DataInterface::getSystemNames() const 599 { 600 DBusSubTree subtree; 601 DBusValue names; 602 603 auto method = _bus.new_method_call(service_name::objectMapper, 604 object_path::objectMapper, 605 interface::objectMapper, "GetSubTree"); 606 method.append(std::string{"/"}, 0, 607 std::vector<std::string>{interface::compatible}); 608 auto reply = _bus.call(method, dbusTimeout); 609 610 reply.read(subtree); 611 if (subtree.empty()) 612 { 613 throw std::runtime_error("Compatible interface not on D-Bus"); 614 } 615 616 const auto& object = *(subtree.begin()); 617 const auto& path = object.first; 618 const auto& service = object.second.begin()->first; 619 620 getProperty(service, path, interface::compatible, "Names", names); 621 622 return std::get<std::vector<std::string>>(names); 623 } 624 625 bool DataInterface::getQuiesceOnError() const 626 { 627 bool ret = false; 628 629 try 630 { 631 auto service = getService(object_path::logSetting, 632 interface::logSetting); 633 if (!service.empty()) 634 { 635 DBusValue value; 636 getProperty(service, object_path::logSetting, interface::logSetting, 637 "QuiesceOnHwError", value); 638 639 ret = std::get<bool>(value); 640 } 641 } 642 catch (const std::exception& e) 643 { 644 log<level::WARNING>( 645 fmt::format("Failed reading QuiesceOnHwError property from " 646 "Interface: {} exception: {}", 647 interface::logSetting, e.what()) 648 .c_str()); 649 } 650 651 return ret; 652 } 653 654 std::vector<bool> 655 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const 656 { 657 DBusSubTree subtree; 658 std::vector<bool> result(type.size(), false); 659 660 // Query GetSubTree for the availability of dump interface 661 auto method = _bus.new_method_call(service_name::objectMapper, 662 object_path::objectMapper, 663 interface::objectMapper, "GetSubTree"); 664 method.append(std::string{"/"}, 0, 665 std::vector<std::string>{interface::dumpEntry}); 666 auto reply = _bus.call(method, dbusTimeout); 667 668 reply.read(subtree); 669 670 if (subtree.empty()) 671 { 672 return result; 673 } 674 675 std::vector<bool>::iterator itDumpStatus = result.begin(); 676 uint8_t count = 0; 677 for (const auto& [path, serviceInfo] : subtree) 678 { 679 const auto& service = serviceInfo.begin()->first; 680 // Check for dump type on the object path 681 for (const auto& it : type) 682 { 683 if (path.find(it) != std::string::npos) 684 { 685 DBusValue value, progress; 686 687 // If dump type status is already available go for next path 688 if (*itDumpStatus) 689 { 690 break; 691 } 692 693 // Check for valid dump to be available if following 694 // conditions are met for the dump entry path - 695 // Offloaded == false and Status == Completed 696 getProperty(service, path, interface::dumpEntry, "Offloaded", 697 value); 698 getProperty(service, path, interface::dumpProgress, "Status", 699 progress); 700 auto offload = std::get<bool>(value); 701 auto status = std::get<std::string>(progress); 702 if (!offload && (status.find("Completed") != std::string::npos)) 703 { 704 *itDumpStatus = true; 705 count++; 706 if (count >= type.size()) 707 { 708 return result; 709 } 710 break; 711 } 712 } 713 ++itDumpStatus; 714 } 715 itDumpStatus = result.begin(); 716 } 717 718 return result; 719 } 720 721 void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath, 722 const std::string& type, 723 const std::string& logPath) const 724 { 725 try 726 { 727 auto method = _bus.new_method_call( 728 service_name::hwIsolation, object_path::hwIsolation, 729 interface::hwIsolationCreate, "CreateWithEntityPath"); 730 method.append(binPath, type, sdbusplus::message::object_path(logPath)); 731 // Note: hw isolation "CreateWithEntityPath" got dependency on logging 732 // api's. Making d-bus call no reply type to avoid cyclic dependency. 733 // Added minimal timeout to catch initial failures. 734 // Need to revisit this design later to avoid cyclic dependency. 735 constexpr auto hwIsolationTimeout = 100000; // in micro seconds 736 _bus.call_noreply(method, hwIsolationTimeout); 737 } 738 739 catch (const sdbusplus::exception_t& e) 740 { 741 std::string errName = e.name(); 742 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency 743 // mentioned above. Ignoring the error. 744 if (errName != SD_BUS_ERROR_TIMEOUT) 745 { 746 log<level::ERR>( 747 fmt::format("GUARD D-Bus call exception" 748 "OBJPATH={}, INTERFACE={}, EXCEPTION={}", 749 object_path::hwIsolation, 750 interface::hwIsolationCreate, e.what()) 751 .c_str()); 752 } 753 } 754 } 755 756 void DataInterface::createProgressSRC( 757 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const 758 { 759 DBusValue variant = std::make_tuple(priSRC, srcStruct); 760 761 auto method = _bus.new_method_call(service_name::bootRawProgress, 762 object_path::bootRawProgress, 763 interface::dbusProperty, "Set"); 764 765 method.append(interface::bootRawProgress, "Value", variant); 766 767 _bus.call(method, dbusTimeout); 768 } 769 770 std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const 771 { 772 std::vector<std::string> association = {"xyz.openbmc_project.Association"}; 773 std::string hwErrorLog = "/isolated_hw_errorlog"; 774 std::string errorLog = "/error_log"; 775 DBusPathList paths; 776 std::vector<uint32_t> ids; 777 778 // Get all latest mapper associations 779 paths = getPaths(association); 780 for (auto& path : paths) 781 { 782 // Look for object path with hardware isolation entry if any 783 size_t pos = path.find(hwErrorLog); 784 if (pos != std::string::npos) 785 { 786 // Get the object path 787 std::string ph = path; 788 ph.erase(pos, hwErrorLog.length()); 789 auto service = getService(ph, interface::hwIsolationEntry); 790 if (!service.empty()) 791 { 792 bool status; 793 DBusValue value; 794 795 // Read the Resolved property from object path 796 getProperty(service, ph, interface::hwIsolationEntry, 797 "Resolved", value); 798 799 status = std::get<bool>(value); 800 801 // If the entry isn't resolved 802 if (!status) 803 { 804 auto assocService = getService(path, 805 interface::association); 806 if (!assocService.empty()) 807 { 808 DBusValue endpoints; 809 810 // Read Endpoints property 811 getProperty(assocService, path, interface::association, 812 "endpoints", endpoints); 813 814 auto logPath = 815 std::get<std::vector<std::string>>(endpoints); 816 if (!logPath.empty()) 817 { 818 // Get OpenBMC event log Id 819 uint32_t id = stoi(logPath[0].substr( 820 logPath[0].find_last_of('/') + 1)); 821 ids.push_back(id); 822 } 823 } 824 } 825 } 826 } 827 828 // Look for object path with error_log entry if any 829 pos = path.find(errorLog); 830 if (pos != std::string::npos) 831 { 832 auto service = getService(path, interface::association); 833 if (!service.empty()) 834 { 835 DBusValue value; 836 837 // Read Endpoints property 838 getProperty(service, path, interface::association, "endpoints", 839 value); 840 841 auto logPath = std::get<std::vector<std::string>>(value); 842 if (!logPath.empty()) 843 { 844 // Get OpenBMC event log Id 845 uint32_t id = stoi( 846 logPath[0].substr(logPath[0].find_last_of('/') + 1)); 847 ids.push_back(id); 848 } 849 } 850 } 851 } 852 853 if (ids.size() > 1) 854 { 855 // remove duplicates to have only unique ids 856 std::sort(ids.begin(), ids.end()); 857 ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); 858 } 859 return ids; 860 } 861 862 std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const 863 { 864 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>; 865 866 DBusValue value; 867 getProperty(service_name::bootRawProgress, object_path::bootRawProgress, 868 interface::bootRawProgress, "Value", value); 869 870 const auto& rawProgress = std::get<RawProgressProperty>(value); 871 return std::get<1>(rawProgress); 872 } 873 874 } // namespace pels 875 } // namespace openpower 876