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