1 #include "config.h" 2 3 #include "bios_handler.hpp" 4 5 #include "constants.hpp" 6 #include "logger.hpp" 7 8 #include <sdbusplus/bus/match.hpp> 9 #include <utility/common_utility.hpp> 10 #include <utility/dbus_utility.hpp> 11 12 #include <string> 13 14 namespace vpd 15 { 16 // Template declaration to define APIs. 17 template class BiosHandler<IbmBiosHandler>; 18 19 template <typename T> 20 void BiosHandler<T>::checkAndListenPldmService() noexcept 21 { 22 try 23 { 24 // Setup a call back match on NameOwnerChanged to determine when PLDM is 25 // up. 26 static std::shared_ptr<sdbusplus::bus::match_t> l_nameOwnerMatch = 27 std::make_shared<sdbusplus::bus::match_t>( 28 *m_asioConn, 29 sdbusplus::bus::match::rules::nameOwnerChanged( 30 constants::pldmServiceName), 31 [this](sdbusplus::message_t& l_msg) { 32 if (l_msg.is_method_error()) 33 { 34 logging::logMessage( 35 "Error in reading PLDM name owner changed signal."); 36 return; 37 } 38 39 std::string l_name; 40 std::string l_newOwner; 41 std::string l_oldOwner; 42 43 l_msg.read(l_name, l_oldOwner, l_newOwner); 44 45 if (!l_newOwner.empty() && 46 (l_name.compare(constants::pldmServiceName) == 47 constants::STR_CMP_SUCCESS)) 48 { 49 m_specificBiosHandler->backUpOrRestoreBiosAttributes(); 50 51 // Start listener now that we have done the restore. 52 listenBiosAttributes(); 53 54 // We don't need the match anymore 55 l_nameOwnerMatch.reset(); 56 } 57 }); 58 59 // Based on PLDM service status reset owner match registered above and 60 // trigger BIOS attribute sync. 61 if (dbusUtility::isServiceRunning(constants::pldmServiceName)) 62 { 63 l_nameOwnerMatch.reset(); 64 m_specificBiosHandler->backUpOrRestoreBiosAttributes(); 65 66 // Start listener now that we have done the restore. 67 listenBiosAttributes(); 68 } 69 } 70 catch (const std::exception& l_ex) 71 { 72 logging::logMessage( 73 "Failed to register callback for PLDM servce. Error: " + 74 std::string(l_ex.what())); 75 } 76 } 77 78 template <typename T> 79 void BiosHandler<T>::listenBiosAttributes() 80 { 81 static std::shared_ptr<sdbusplus::bus::match_t> l_biosMatch = 82 std::make_shared<sdbusplus::bus::match_t>( 83 *m_asioConn, 84 sdbusplus::bus::match::rules::propertiesChanged( 85 constants::biosConfigMgrObjPath, 86 constants::biosConfigMgrInterface), 87 [this](sdbusplus::message_t& l_msg) { 88 m_specificBiosHandler->biosAttributesCallback(l_msg); 89 }); 90 } 91 92 void IbmBiosHandler::biosAttributesCallback(sdbusplus::message_t& i_msg) 93 { 94 if (i_msg.is_method_error()) 95 { 96 logging::logMessage("Error in reading BIOS attribute signal. "); 97 return; 98 } 99 100 std::string l_objPath; 101 types::BiosBaseTableType l_propMap; 102 i_msg.read(l_objPath, l_propMap); 103 104 for (auto l_property : l_propMap) 105 { 106 if (l_property.first != "BaseBIOSTable") 107 { 108 // Looking for change in Base BIOS table only. 109 continue; 110 } 111 112 if (auto l_attributeList = 113 std::get_if<std::map<std::string, types::BiosProperty>>( 114 &(l_property.second))) 115 { 116 for (const auto& l_attribute : *l_attributeList) 117 { 118 if (auto l_val = std::get_if<std::string>( 119 &(std::get<5>(std::get<1>(l_attribute))))) 120 { 121 std::string l_attributeName = std::get<0>(l_attribute); 122 if (l_attributeName == "hb_memory_mirror_mode") 123 { 124 saveAmmToVpd(*l_val); 125 } 126 127 if (l_attributeName == "pvm_keep_and_clear") 128 { 129 saveKeepAndClearToVpd(*l_val); 130 } 131 132 if (l_attributeName == "pvm_create_default_lpar") 133 { 134 saveCreateDefaultLparToVpd(*l_val); 135 } 136 137 if (l_attributeName == "pvm_clear_nvram") 138 { 139 saveClearNvramToVpd(*l_val); 140 } 141 142 continue; 143 } 144 145 if (auto l_val = std::get_if<int64_t>( 146 &(std::get<5>(std::get<1>(l_attribute))))) 147 { 148 std::string l_attributeName = std::get<0>(l_attribute); 149 if (l_attributeName == "hb_field_core_override") 150 { 151 saveFcoToVpd(*l_val); 152 } 153 } 154 } 155 } 156 else 157 { 158 logging::logMessage("Invalid type received for BIOS table."); 159 EventLogger::createSyncPel( 160 types::ErrorType::FirmwareError, types::SeverityType::Warning, 161 __FILE__, __FUNCTION__, 0, 162 std::string("Invalid type received for BIOS table."), 163 std::nullopt, std::nullopt, std::nullopt, std::nullopt); 164 break; 165 } 166 } 167 } 168 169 void IbmBiosHandler::backUpOrRestoreBiosAttributes() 170 { 171 // process FCO 172 processFieldCoreOverride(); 173 174 // process AMM 175 processActiveMemoryMirror(); 176 177 // process LPAR 178 processCreateDefaultLpar(); 179 180 // process clear NVRAM 181 processClearNvram(); 182 183 // process keep and clear 184 processKeepAndClear(); 185 } 186 187 types::BiosAttributeCurrentValue IbmBiosHandler::readBiosAttribute( 188 const std::string& i_attributeName) 189 { 190 types::BiosAttributeCurrentValue l_attrValueVariant = 191 dbusUtility::biosGetAttributeMethodCall(i_attributeName); 192 193 return l_attrValueVariant; 194 } 195 196 void IbmBiosHandler::processFieldCoreOverride() 197 { 198 // TODO: Should we avoid doing this at runtime? 199 200 // Read required keyword from Dbus. 201 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 202 constants::pimServiceName, constants::systemVpdInvPath, 203 constants::vsysInf, constants::kwdRG); 204 205 if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 206 { 207 // default length of the keyword is 4 bytes. 208 if (l_fcoInVpd->size() != constants::VALUE_4) 209 { 210 logging::logMessage( 211 "Invalid value read for FCO from D-Bus. Skipping."); 212 } 213 214 // If FCO in VPD contains anything other that ASCII Space, restore to 215 // BIOS 216 if (std::any_of(l_fcoInVpd->cbegin(), l_fcoInVpd->cend(), 217 [](uint8_t l_val) { 218 return l_val != constants::ASCII_OF_SPACE; 219 })) 220 { 221 // Restore the data to BIOS. 222 saveFcoToBios(*l_fcoInVpd); 223 } 224 else 225 { 226 types::BiosAttributeCurrentValue l_attrValueVariant = 227 readBiosAttribute("hb_field_core_override"); 228 229 if (auto l_fcoInBios = std::get_if<int64_t>(&l_attrValueVariant)) 230 { 231 // save the BIOS data to VPD 232 saveFcoToVpd(*l_fcoInBios); 233 234 return; 235 } 236 logging::logMessage("Invalid type recieved for FCO from BIOS."); 237 } 238 return; 239 } 240 logging::logMessage("Invalid type recieved for FCO from VPD."); 241 } 242 243 void IbmBiosHandler::saveFcoToVpd(int64_t i_fcoInBios) 244 { 245 if (i_fcoInBios < 0) 246 { 247 logging::logMessage("Invalid FCO value in BIOS. Skip updating to VPD"); 248 return; 249 } 250 251 // Read required keyword from Dbus. 252 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 253 constants::pimServiceName, constants::systemVpdInvPath, 254 constants::vsysInf, constants::kwdRG); 255 256 if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 257 { 258 // default length of the keyword is 4 bytes. 259 if (l_fcoInVpd->size() != constants::VALUE_4) 260 { 261 logging::logMessage( 262 "Invalid value read for FCO from D-Bus. Skipping."); 263 return; 264 } 265 266 // convert to VPD value type 267 types::BinaryVector l_biosValInVpdFormat = { 268 0, 0, 0, static_cast<uint8_t>(i_fcoInBios)}; 269 270 // Update only when the data are different. 271 if (std::memcmp(l_biosValInVpdFormat.data(), l_fcoInVpd->data(), 272 constants::VALUE_4) != constants::SUCCESS) 273 { 274 if (constants::FAILURE == 275 m_manager->updateKeyword( 276 SYSTEM_VPD_FILE_PATH, 277 types::IpzData("VSYS", constants::kwdRG, 278 l_biosValInVpdFormat))) 279 { 280 logging::logMessage( 281 "Failed to update " + std::string(constants::kwdRG) + 282 " keyword to VPD."); 283 } 284 } 285 } 286 else 287 { 288 logging::logMessage("Invalid type read for FCO from DBus."); 289 } 290 } 291 292 void IbmBiosHandler::saveFcoToBios(const types::BinaryVector& i_fcoVal) 293 { 294 if (i_fcoVal.size() != constants::VALUE_4) 295 { 296 logging::logMessage("Bad size for FCO received. Skip writing to BIOS"); 297 return; 298 } 299 300 types::PendingBIOSAttrs l_pendingBiosAttribute; 301 l_pendingBiosAttribute.push_back(std::make_pair( 302 "hb_field_core_override", 303 std::make_tuple( 304 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer", 305 i_fcoVal.at(constants::VALUE_3)))); 306 307 if (!dbusUtility::writeDbusProperty( 308 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 309 constants::biosConfigMgrInterface, "PendingAttributes", 310 l_pendingBiosAttribute)) 311 { 312 // TODO: Should we log informational PEL here as well? 313 logging::logMessage( 314 "DBus call to update FCO value in pending attribute failed. "); 315 } 316 } 317 318 void IbmBiosHandler::saveAmmToVpd(const std::string& i_memoryMirrorMode) 319 { 320 if (i_memoryMirrorMode.empty()) 321 { 322 logging::logMessage( 323 "Empty memory mirror mode value from BIOS. Skip writing to VPD"); 324 return; 325 } 326 327 // Read existing value. 328 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 329 constants::pimServiceName, constants::systemVpdInvPath, 330 constants::utilInf, constants::kwdAMM); 331 332 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 333 { 334 auto l_ammValInVpd = *l_pVal; 335 336 types::BinaryVector l_valToUpdateInVpd{ 337 (i_memoryMirrorMode == "Enabled" ? constants::AMM_ENABLED_IN_VPD 338 : constants::AMM_DISABLED_IN_VPD)}; 339 340 // Check if value is already updated on VPD. 341 if (l_ammValInVpd.at(0) == l_valToUpdateInVpd.at(0)) 342 { 343 return; 344 } 345 346 if (constants::FAILURE == 347 m_manager->updateKeyword( 348 SYSTEM_VPD_FILE_PATH, 349 types::IpzData("UTIL", constants::kwdAMM, l_valToUpdateInVpd))) 350 { 351 logging::logMessage( 352 "Failed to update " + std::string(constants::kwdAMM) + 353 " keyword to VPD"); 354 } 355 } 356 else 357 { 358 // TODO: Add PEL 359 logging::logMessage( 360 "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD"); 361 } 362 } 363 364 void IbmBiosHandler::saveAmmToBios(const uint8_t& i_ammVal) 365 { 366 const std::string l_valtoUpdate = 367 (i_ammVal == constants::VALUE_2) ? "Enabled" : "Disabled"; 368 369 types::PendingBIOSAttrs l_pendingBiosAttribute; 370 l_pendingBiosAttribute.push_back(std::make_pair( 371 "hb_memory_mirror_mode", 372 std::make_tuple( 373 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 374 l_valtoUpdate))); 375 376 if (!dbusUtility::writeDbusProperty( 377 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 378 constants::biosConfigMgrInterface, "PendingAttributes", 379 l_pendingBiosAttribute)) 380 { 381 // TODO: Should we log informational PEL here as well? 382 logging::logMessage( 383 "DBus call to update AMM value in pending attribute failed."); 384 } 385 } 386 387 void IbmBiosHandler::processActiveMemoryMirror() 388 { 389 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 390 constants::pimServiceName, constants::systemVpdInvPath, 391 constants::utilInf, constants::kwdAMM); 392 393 if (auto pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 394 { 395 auto l_ammValInVpd = *pVal; 396 397 // Check if active memory mirror value is default in VPD. 398 if (l_ammValInVpd.at(0) == constants::VALUE_0) 399 { 400 types::BiosAttributeCurrentValue l_attrValueVariant = 401 readBiosAttribute("hb_memory_mirror_mode"); 402 403 if (auto pVal = std::get_if<std::string>(&l_attrValueVariant)) 404 { 405 saveAmmToVpd(*pVal); 406 return; 407 } 408 logging::logMessage( 409 "Invalid type recieved for auto memory mirror mode from BIOS."); 410 return; 411 } 412 else 413 { 414 saveAmmToBios(l_ammValInVpd.at(0)); 415 } 416 return; 417 } 418 logging::logMessage( 419 "Invalid type recieved for auto memory mirror mode from VPD."); 420 } 421 422 void IbmBiosHandler::saveCreateDefaultLparToVpd( 423 const std::string& i_createDefaultLparVal) 424 { 425 if (i_createDefaultLparVal.empty()) 426 { 427 logging::logMessage( 428 "Empty value received for Lpar from BIOS. Skip writing in VPD."); 429 return; 430 } 431 432 // Read required keyword from DBus as we need to set only a Bit. 433 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 434 constants::pimServiceName, constants::systemVpdInvPath, 435 constants::utilInf, constants::kwdClearNVRAM_CreateLPAR); 436 437 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 438 { 439 commonUtility::toLower( 440 const_cast<std::string&>(i_createDefaultLparVal)); 441 442 // Check for second bit. Bit set for enabled else disabled. 443 if (((((*l_pVal).at(0) & 0x02) == 0x02) && 444 (i_createDefaultLparVal.compare("enabled") == 445 constants::STR_CMP_SUCCESS)) || 446 ((((*l_pVal).at(0) & 0x02) == 0x00) && 447 (i_createDefaultLparVal.compare("disabled") == 448 constants::STR_CMP_SUCCESS))) 449 { 450 // Values are same, Don;t update. 451 return; 452 } 453 454 types::BinaryVector l_valToUpdateInVpd; 455 if (i_createDefaultLparVal.compare("enabled") == 456 constants::STR_CMP_SUCCESS) 457 { 458 // 2nd Bit is used to store the value. 459 l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) | 0x02); 460 } 461 else 462 { 463 // 2nd Bit is used to store the value. 464 l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) & ~(0x02)); 465 } 466 467 if (-1 == 468 m_manager->updateKeyword( 469 SYSTEM_VPD_FILE_PATH, 470 types::IpzData("UTIL", constants::kwdClearNVRAM_CreateLPAR, 471 l_valToUpdateInVpd))) 472 { 473 logging::logMessage( 474 "Failed to update " + 475 std::string(constants::kwdClearNVRAM_CreateLPAR) + 476 " keyword to VPD"); 477 } 478 479 return; 480 } 481 logging::logMessage( 482 "Invalid type recieved for create default Lpar from VPD."); 483 } 484 485 void IbmBiosHandler::saveCreateDefaultLparToBios( 486 const std::string& i_createDefaultLparVal) 487 { 488 // checking for exact length as it is a string and can have garbage value. 489 if (i_createDefaultLparVal.size() != constants::VALUE_1) 490 { 491 logging::logMessage( 492 "Bad size for Create default LPAR in VPD. Skip writing to BIOS."); 493 return; 494 } 495 496 std::string l_valtoUpdate = 497 (i_createDefaultLparVal.at(0) & 0x02) ? "Enabled" : "Disabled"; 498 499 types::PendingBIOSAttrs l_pendingBiosAttribute; 500 l_pendingBiosAttribute.push_back(std::make_pair( 501 "pvm_create_default_lpar", 502 std::make_tuple( 503 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 504 l_valtoUpdate))); 505 506 if (!dbusUtility::writeDbusProperty( 507 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 508 constants::biosConfigMgrInterface, "PendingAttributes", 509 l_pendingBiosAttribute)) 510 { 511 logging::logMessage( 512 "DBus call to update lpar value in pending attribute failed."); 513 } 514 515 return; 516 } 517 518 void IbmBiosHandler::processCreateDefaultLpar() 519 { 520 // Read required keyword from DBus. 521 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 522 constants::pimServiceName, constants::systemVpdInvPath, 523 constants::utilInf, constants::kwdClearNVRAM_CreateLPAR); 524 525 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 526 { 527 saveCreateDefaultLparToBios(std::to_string(l_pVal->at(0))); 528 return; 529 } 530 logging::logMessage( 531 "Invalid type recieved for create default Lpar from VPD."); 532 } 533 534 void IbmBiosHandler::saveClearNvramToVpd(const std::string& i_clearNvramVal) 535 { 536 if (i_clearNvramVal.empty()) 537 { 538 logging::logMessage( 539 "Empty value received for clear NVRAM from BIOS. Skip updating to VPD."); 540 return; 541 } 542 543 // Read required keyword from DBus as we need to set only a Bit. 544 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 545 constants::pimServiceName, constants::systemVpdInvPath, 546 constants::utilInf, constants::kwdClearNVRAM_CreateLPAR); 547 548 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 549 { 550 commonUtility::toLower(const_cast<std::string&>(i_clearNvramVal)); 551 552 // Check for third bit. Bit set for enabled else disabled. 553 if (((((*l_pVal).at(0) & 0x04) == 0x04) && 554 (i_clearNvramVal.compare("enabled") == 555 constants::STR_CMP_SUCCESS)) || 556 ((((*l_pVal).at(0) & 0x04) == 0x00) && 557 (i_clearNvramVal.compare("disabled") == 558 constants::STR_CMP_SUCCESS))) 559 { 560 // Don't update, values are same. 561 return; 562 } 563 564 types::BinaryVector l_valToUpdateInVpd; 565 if (i_clearNvramVal.compare("enabled") == constants::STR_CMP_SUCCESS) 566 { 567 // 3rd bit is used to store the value. 568 l_valToUpdateInVpd.emplace_back( 569 (*l_pVal).at(0) | constants::VALUE_4); 570 } 571 else 572 { 573 // 3rd bit is used to store the value. 574 l_valToUpdateInVpd.emplace_back( 575 (*l_pVal).at(0) & ~(constants::VALUE_4)); 576 } 577 578 if (-1 == 579 m_manager->updateKeyword( 580 SYSTEM_VPD_FILE_PATH, 581 types::IpzData("UTIL", constants::kwdClearNVRAM_CreateLPAR, 582 l_valToUpdateInVpd))) 583 { 584 logging::logMessage( 585 "Failed to update " + 586 std::string(constants::kwdClearNVRAM_CreateLPAR) + 587 " keyword to VPD"); 588 } 589 590 return; 591 } 592 logging::logMessage("Invalid type recieved for clear NVRAM from VPD."); 593 } 594 595 void IbmBiosHandler::saveClearNvramToBios(const std::string& i_clearNvramVal) 596 { 597 // Check for the exact length as it is a string and it can have a garbage 598 // value. 599 if (i_clearNvramVal.size() != constants::VALUE_1) 600 { 601 logging::logMessage( 602 "Bad size for clear NVRAM in VPD. Skip writing to BIOS."); 603 return; 604 } 605 606 // 3rd bit is used to store clear NVRAM value. 607 std::string l_valtoUpdate = 608 (i_clearNvramVal.at(0) & constants::VALUE_4) ? "Enabled" : "Disabled"; 609 610 types::PendingBIOSAttrs l_pendingBiosAttribute; 611 l_pendingBiosAttribute.push_back(std::make_pair( 612 "pvm_clear_nvram", 613 std::make_tuple( 614 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 615 l_valtoUpdate))); 616 617 if (!dbusUtility::writeDbusProperty( 618 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 619 constants::biosConfigMgrInterface, "PendingAttributes", 620 l_pendingBiosAttribute)) 621 { 622 logging::logMessage( 623 "DBus call to update NVRAM value in pending attribute failed."); 624 } 625 } 626 627 void IbmBiosHandler::processClearNvram() 628 { 629 // Read required keyword from VPD. 630 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 631 constants::pimServiceName, constants::systemVpdInvPath, 632 constants::utilInf, constants::kwdClearNVRAM_CreateLPAR); 633 634 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 635 { 636 saveClearNvramToBios(std::to_string(l_pVal->at(0))); 637 return; 638 } 639 logging::logMessage("Invalid type recieved for clear NVRAM from VPD."); 640 } 641 642 void IbmBiosHandler::saveKeepAndClearToVpd(const std::string& i_KeepAndClearVal) 643 { 644 if (i_KeepAndClearVal.empty()) 645 { 646 logging::logMessage( 647 "Empty value received for keep and clear from BIOS. Skip updating to VPD."); 648 return; 649 } 650 651 // Read required keyword from DBus as we need to set only a Bit. 652 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 653 constants::pimServiceName, constants::systemVpdInvPath, 654 constants::utilInf, constants::kwdKeepAndClear); 655 656 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 657 { 658 commonUtility::toLower(const_cast<std::string&>(i_KeepAndClearVal)); 659 660 // Check for first bit. Bit set for enabled else disabled. 661 if (((((*l_pVal).at(0) & 0x01) == 0x01) && 662 (i_KeepAndClearVal.compare("enabled") == 663 constants::STR_CMP_SUCCESS)) || 664 ((((*l_pVal).at(0) & 0x01) == 0x00) && 665 (i_KeepAndClearVal.compare("disabled") == 666 constants::STR_CMP_SUCCESS))) 667 { 668 // Don't update, values are same. 669 return; 670 } 671 672 types::BinaryVector l_valToUpdateInVpd; 673 if (i_KeepAndClearVal.compare("enabled") == constants::STR_CMP_SUCCESS) 674 { 675 // 1st bit is used to store the value. 676 l_valToUpdateInVpd.emplace_back( 677 (*l_pVal).at(0) | constants::VALUE_1); 678 } 679 else 680 { 681 // 1st bit is used to store the value. 682 l_valToUpdateInVpd.emplace_back( 683 (*l_pVal).at(0) & ~(constants::VALUE_1)); 684 } 685 686 if (-1 == m_manager->updateKeyword( 687 SYSTEM_VPD_FILE_PATH, 688 types::IpzData("UTIL", constants::kwdKeepAndClear, 689 l_valToUpdateInVpd))) 690 { 691 logging::logMessage( 692 "Failed to update " + std::string(constants::kwdKeepAndClear) + 693 " keyword to VPD"); 694 } 695 696 return; 697 } 698 logging::logMessage("Invalid type recieved for keep and clear from VPD."); 699 } 700 701 void IbmBiosHandler::saveKeepAndClearToBios( 702 const std::string& i_KeepAndClearVal) 703 { 704 // checking for exact length as it is a string and can have garbage value. 705 if (i_KeepAndClearVal.size() != constants::VALUE_1) 706 { 707 logging::logMessage( 708 "Bad size for keep and clear in VPD. Skip writing to BIOS."); 709 return; 710 } 711 712 // 1st bit is used to store keep and clear value. 713 std::string l_valtoUpdate = 714 (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled"; 715 716 types::PendingBIOSAttrs l_pendingBiosAttribute; 717 l_pendingBiosAttribute.push_back(std::make_pair( 718 "pvm_keep_and_clear", 719 std::make_tuple( 720 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 721 l_valtoUpdate))); 722 723 if (!dbusUtility::writeDbusProperty( 724 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 725 constants::biosConfigMgrInterface, "PendingAttributes", 726 l_pendingBiosAttribute)) 727 { 728 logging::logMessage( 729 "DBus call to update keep and clear value in pending attribute failed."); 730 } 731 } 732 733 void IbmBiosHandler::processKeepAndClear() 734 { 735 // Read required keyword from VPD. 736 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 737 constants::pimServiceName, constants::systemVpdInvPath, 738 constants::utilInf, constants::kwdKeepAndClear); 739 740 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 741 { 742 saveKeepAndClearToBios(std::to_string(l_pVal->at(0))); 743 return; 744 } 745 logging::logMessage("Invalid type recieved for keep and clear from VPD."); 746 } 747 } // namespace vpd 748