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