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(constants::vsysInf, 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::vsysInf, 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(constants::vsysInf, constants::kwdAMM, 341 l_valToUpdateInVpd))) 342 { 343 logging::logMessage( 344 "Failed to update " + std::string(constants::kwdAMM) + 345 " keyword to VPD"); 346 } 347 } 348 else 349 { 350 // TODO: Add PEL 351 logging::logMessage( 352 "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD"); 353 } 354 } 355 356 void IbmBiosHandler::saveAmmToBios(const uint8_t& i_ammVal) 357 { 358 const std::string l_valtoUpdate = 359 (i_ammVal == constants::VALUE_2) ? "Enabled" : "Disabled"; 360 361 types::PendingBIOSAttrs l_pendingBiosAttribute; 362 l_pendingBiosAttribute.push_back(std::make_pair( 363 "hb_memory_mirror_mode", 364 std::make_tuple( 365 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 366 l_valtoUpdate))); 367 368 if (!dbusUtility::writeDbusProperty( 369 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 370 constants::biosConfigMgrInterface, "PendingAttributes", 371 l_pendingBiosAttribute)) 372 { 373 // TODO: Should we log informational PEL here as well? 374 logging::logMessage( 375 "DBus call to update AMM value in pending attribute failed."); 376 } 377 } 378 379 void IbmBiosHandler::processActiveMemoryMirror() 380 { 381 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 382 constants::pimServiceName, constants::systemVpdInvPath, 383 constants::vsysInf, constants::kwdAMM); 384 385 if (auto pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 386 { 387 auto l_ammValInVpd = *pVal; 388 389 // Check if active memory mirror value is default in VPD. 390 if (l_ammValInVpd.at(0) == constants::VALUE_0) 391 { 392 types::BiosAttributeCurrentValue l_attrValueVariant = 393 readBiosAttribute("hb_memory_mirror_mode"); 394 395 if (auto pVal = std::get_if<std::string>(&l_attrValueVariant)) 396 { 397 saveAmmToVpd(*pVal); 398 return; 399 } 400 logging::logMessage( 401 "Invalid type recieved for auto memory mirror mode from BIOS."); 402 return; 403 } 404 else 405 { 406 saveAmmToBios(l_ammValInVpd.at(0)); 407 } 408 return; 409 } 410 logging::logMessage( 411 "Invalid type recieved for auto memory mirror mode from VPD."); 412 } 413 414 void IbmBiosHandler::saveCreateDefaultLparToVpd( 415 const std::string& i_createDefaultLparVal) 416 { 417 if (i_createDefaultLparVal.empty()) 418 { 419 logging::logMessage( 420 "Empty value received for Lpar from BIOS. Skip writing in VPD."); 421 return; 422 } 423 424 // Read required keyword from DBus as we need to set only a Bit. 425 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 426 constants::pimServiceName, constants::systemVpdInvPath, 427 constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR); 428 429 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 430 { 431 commonUtility::toLower( 432 const_cast<std::string&>(i_createDefaultLparVal)); 433 434 // Check for second bit. Bit set for enabled else disabled. 435 if (((((*l_pVal).at(0) & 0x02) == 0x02) && 436 (i_createDefaultLparVal.compare("enabled") == 437 constants::STR_CMP_SUCCESS)) || 438 ((((*l_pVal).at(0) & 0x02) == 0x00) && 439 (i_createDefaultLparVal.compare("disabled") == 440 constants::STR_CMP_SUCCESS))) 441 { 442 // Values are same, Don;t update. 443 return; 444 } 445 446 types::BinaryVector l_valToUpdateInVpd; 447 if (i_createDefaultLparVal.compare("enabled") == 448 constants::STR_CMP_SUCCESS) 449 { 450 // 2nd Bit is used to store the value. 451 l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) | 0x02); 452 } 453 else 454 { 455 // 2nd Bit is used to store the value. 456 l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) & ~(0x02)); 457 } 458 459 if (-1 == m_manager->updateKeyword( 460 SYSTEM_VPD_FILE_PATH, 461 types::IpzData(constants::vsysInf, 462 constants::kwdClearNVRAM_CreateLPAR, 463 l_valToUpdateInVpd))) 464 { 465 logging::logMessage( 466 "Failed to update " + 467 std::string(constants::kwdClearNVRAM_CreateLPAR) + 468 " keyword to VPD"); 469 } 470 471 return; 472 } 473 logging::logMessage( 474 "Invalid type recieved for create default Lpar from VPD."); 475 } 476 477 void IbmBiosHandler::saveCreateDefaultLparToBios( 478 const std::string& i_createDefaultLparVal) 479 { 480 // checking for exact length as it is a string and can have garbage value. 481 if (i_createDefaultLparVal.size() != constants::VALUE_1) 482 { 483 logging::logMessage( 484 "Bad size for Create default LPAR in VPD. Skip writing to BIOS."); 485 return; 486 } 487 488 std::string l_valtoUpdate = 489 (i_createDefaultLparVal.at(0) & 0x02) ? "Enabled" : "Disabled"; 490 491 types::PendingBIOSAttrs l_pendingBiosAttribute; 492 l_pendingBiosAttribute.push_back(std::make_pair( 493 "pvm_create_default_lpar", 494 std::make_tuple( 495 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 496 l_valtoUpdate))); 497 498 if (!dbusUtility::writeDbusProperty( 499 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 500 constants::biosConfigMgrInterface, "PendingAttributes", 501 l_pendingBiosAttribute)) 502 { 503 logging::logMessage( 504 "DBus call to update lpar value in pending attribute failed."); 505 } 506 507 return; 508 } 509 510 void IbmBiosHandler::processCreateDefaultLpar() 511 { 512 // Read required keyword from DBus. 513 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 514 constants::pimServiceName, constants::systemVpdInvPath, 515 constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR); 516 517 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 518 { 519 saveCreateDefaultLparToBios(std::to_string(l_pVal->at(0))); 520 return; 521 } 522 logging::logMessage( 523 "Invalid type recieved for create default Lpar from VPD."); 524 } 525 526 void IbmBiosHandler::saveClearNvramToVpd(const std::string& i_clearNvramVal) 527 { 528 if (i_clearNvramVal.empty()) 529 { 530 logging::logMessage( 531 "Empty value received for clear NVRAM from BIOS. Skip updating to VPD."); 532 return; 533 } 534 535 // Read required keyword from DBus as we need to set only a Bit. 536 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 537 constants::pimServiceName, constants::systemVpdInvPath, 538 constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR); 539 540 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 541 { 542 commonUtility::toLower(const_cast<std::string&>(i_clearNvramVal)); 543 544 // Check for third bit. Bit set for enabled else disabled. 545 if (((((*l_pVal).at(0) & 0x04) == 0x04) && 546 (i_clearNvramVal.compare("enabled") == 547 constants::STR_CMP_SUCCESS)) || 548 ((((*l_pVal).at(0) & 0x04) == 0x00) && 549 (i_clearNvramVal.compare("disabled") == 550 constants::STR_CMP_SUCCESS))) 551 { 552 // Don't update, values are same. 553 return; 554 } 555 556 types::BinaryVector l_valToUpdateInVpd; 557 if (i_clearNvramVal.compare("enabled") == constants::STR_CMP_SUCCESS) 558 { 559 // 3rd bit is used to store the value. 560 l_valToUpdateInVpd.emplace_back( 561 (*l_pVal).at(0) | constants::VALUE_4); 562 } 563 else 564 { 565 // 3rd bit is used to store the value. 566 l_valToUpdateInVpd.emplace_back( 567 (*l_pVal).at(0) & ~(constants::VALUE_4)); 568 } 569 570 if (-1 == m_manager->updateKeyword( 571 SYSTEM_VPD_FILE_PATH, 572 types::IpzData(constants::vsysInf, 573 constants::kwdClearNVRAM_CreateLPAR, 574 l_valToUpdateInVpd))) 575 { 576 logging::logMessage( 577 "Failed to update " + 578 std::string(constants::kwdClearNVRAM_CreateLPAR) + 579 " keyword to VPD"); 580 } 581 582 return; 583 } 584 logging::logMessage("Invalid type recieved for clear NVRAM from VPD."); 585 } 586 587 void IbmBiosHandler::saveClearNvramToBios(const std::string& i_clearNvramVal) 588 { 589 // Check for the exact length as it is a string and it can have a garbage 590 // value. 591 if (i_clearNvramVal.size() != constants::VALUE_1) 592 { 593 logging::logMessage( 594 "Bad size for clear NVRAM in VPD. Skip writing to BIOS."); 595 return; 596 } 597 598 // 3rd bit is used to store clear NVRAM value. 599 std::string l_valtoUpdate = 600 (i_clearNvramVal.at(0) & constants::VALUE_4) ? "Enabled" : "Disabled"; 601 602 types::PendingBIOSAttrs l_pendingBiosAttribute; 603 l_pendingBiosAttribute.push_back(std::make_pair( 604 "pvm_clear_nvram", 605 std::make_tuple( 606 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 607 l_valtoUpdate))); 608 609 if (!dbusUtility::writeDbusProperty( 610 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 611 constants::biosConfigMgrInterface, "PendingAttributes", 612 l_pendingBiosAttribute)) 613 { 614 logging::logMessage( 615 "DBus call to update NVRAM value in pending attribute failed."); 616 } 617 } 618 619 void IbmBiosHandler::processClearNvram() 620 { 621 // Read required keyword from VPD. 622 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 623 constants::pimServiceName, constants::systemVpdInvPath, 624 constants::vsysInf, constants::kwdClearNVRAM_CreateLPAR); 625 626 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 627 { 628 saveClearNvramToBios(std::to_string(l_pVal->at(0))); 629 return; 630 } 631 logging::logMessage("Invalid type recieved for clear NVRAM from VPD."); 632 } 633 634 void IbmBiosHandler::saveKeepAndClearToVpd(const std::string& i_KeepAndClearVal) 635 { 636 if (i_KeepAndClearVal.empty()) 637 { 638 logging::logMessage( 639 "Empty value received for keep and clear from BIOS. Skip updating to VPD."); 640 return; 641 } 642 643 // Read required keyword from DBus as we need to set only a Bit. 644 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 645 constants::pimServiceName, constants::systemVpdInvPath, 646 constants::vsysInf, constants::kwdKeepAndClear); 647 648 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 649 { 650 commonUtility::toLower(const_cast<std::string&>(i_KeepAndClearVal)); 651 652 // Check for first bit. Bit set for enabled else disabled. 653 if (((((*l_pVal).at(0) & 0x01) == 0x01) && 654 (i_KeepAndClearVal.compare("enabled") == 655 constants::STR_CMP_SUCCESS)) || 656 ((((*l_pVal).at(0) & 0x01) == 0x00) && 657 (i_KeepAndClearVal.compare("disabled") == 658 constants::STR_CMP_SUCCESS))) 659 { 660 // Don't update, values are same. 661 return; 662 } 663 664 types::BinaryVector l_valToUpdateInVpd; 665 if (i_KeepAndClearVal.compare("enabled") == constants::STR_CMP_SUCCESS) 666 { 667 // 1st bit is used to store the value. 668 l_valToUpdateInVpd.emplace_back( 669 (*l_pVal).at(0) | constants::VALUE_1); 670 } 671 else 672 { 673 // 1st bit is used to store the value. 674 l_valToUpdateInVpd.emplace_back( 675 (*l_pVal).at(0) & ~(constants::VALUE_1)); 676 } 677 678 if (-1 == 679 m_manager->updateKeyword( 680 SYSTEM_VPD_FILE_PATH, 681 types::IpzData(constants::vsysInf, constants::kwdKeepAndClear, 682 l_valToUpdateInVpd))) 683 { 684 logging::logMessage( 685 "Failed to update " + std::string(constants::kwdKeepAndClear) + 686 " keyword to VPD"); 687 } 688 689 return; 690 } 691 logging::logMessage("Invalid type recieved for keep and clear from VPD."); 692 } 693 694 void IbmBiosHandler::saveKeepAndClearToBios( 695 const std::string& i_KeepAndClearVal) 696 { 697 // checking for exact length as it is a string and can have garbage value. 698 if (i_KeepAndClearVal.size() != constants::VALUE_1) 699 { 700 logging::logMessage( 701 "Bad size for keep and clear in VPD. Skip writing to BIOS."); 702 return; 703 } 704 705 // 1st bit is used to store keep and clear value. 706 std::string l_valtoUpdate = 707 (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled"; 708 709 types::PendingBIOSAttrs l_pendingBiosAttribute; 710 l_pendingBiosAttribute.push_back(std::make_pair( 711 "pvm_keep_and_clear", 712 std::make_tuple( 713 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration", 714 l_valtoUpdate))); 715 716 if (!dbusUtility::writeDbusProperty( 717 constants::biosConfigMgrService, constants::biosConfigMgrObjPath, 718 constants::biosConfigMgrInterface, "PendingAttributes", 719 l_pendingBiosAttribute)) 720 { 721 logging::logMessage( 722 "DBus call to update keep and clear value in pending attribute failed."); 723 } 724 } 725 726 void IbmBiosHandler::processKeepAndClear() 727 { 728 // Read required keyword from VPD. 729 auto l_kwdValueVariant = dbusUtility::readDbusProperty( 730 constants::pimServiceName, constants::systemVpdInvPath, 731 constants::vsysInf, constants::kwdKeepAndClear); 732 733 if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant)) 734 { 735 saveKeepAndClearToBios(std::to_string(l_pVal->at(0))); 736 return; 737 } 738 logging::logMessage("Invalid type recieved for keep and clear from VPD."); 739 } 740 } // namespace vpd 741