Revamped code for VPD parser
The commit removes all the pre-existing code from the branch
and pushes the revamped code.
Major modification includes:
- Movement from multi exe to single daemon model.
- Multithreaded approach to parse FRU VPD.
- Better error handling.
- Refactored code for performance optimization.
Note: This code supports all the existing functionalities as it is.
Change-Id: I1ddce1f0725ac59020b72709689a1013643bda8b
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-manager/src/bios_handler.cpp b/vpd-manager/src/bios_handler.cpp
new file mode 100644
index 0000000..44afff3
--- /dev/null
+++ b/vpd-manager/src/bios_handler.cpp
@@ -0,0 +1,764 @@
+#include "config.h"
+
+#include "bios_handler.hpp"
+
+#include "constants.hpp"
+#include "logger.hpp"
+
+#include <sdbusplus/bus/match.hpp>
+#include <utility/common_utility.hpp>
+#include <utility/dbus_utility.hpp>
+
+#include <string>
+
+namespace vpd
+{
+// Template declaration to define APIs.
+template class BiosHandler<IbmBiosHandler>;
+
+template <typename T>
+void BiosHandler<T>::checkAndListenPldmService()
+{
+ // Setup a call back match on NameOwnerChanged to determine when PLDM is up.
+ static std::shared_ptr<sdbusplus::bus::match_t> l_nameOwnerMatch =
+ std::make_shared<sdbusplus::bus::match_t>(
+ *m_asioConn,
+ sdbusplus::bus::match::rules::nameOwnerChanged(
+ constants::pldmServiceName),
+ [this](sdbusplus::message_t& l_msg) {
+ if (l_msg.is_method_error())
+ {
+ logging::logMessage(
+ "Error in reading PLDM name owner changed signal.");
+ return;
+ }
+
+ std::string l_name;
+ std::string l_newOwner;
+ std::string l_oldOwner;
+
+ l_msg.read(l_name, l_oldOwner, l_newOwner);
+
+ if (!l_newOwner.empty() &&
+ (l_name.compare(constants::pldmServiceName) ==
+ constants::STR_CMP_SUCCESS))
+ {
+ m_specificBiosHandler->backUpOrRestoreBiosAttributes();
+
+ // Start listener now that we have done the restore.
+ listenBiosAttributes();
+
+ // We don't need the match anymore
+ l_nameOwnerMatch.reset();
+ }
+ });
+
+ // Based on PLDM service status reset owner match registered above and
+ // trigger BIOS attribute sync.
+ if (dbusUtility::isServiceRunning(constants::pldmServiceName))
+ {
+ l_nameOwnerMatch.reset();
+ m_specificBiosHandler->backUpOrRestoreBiosAttributes();
+
+ // Start listener now that we have done the restore.
+ listenBiosAttributes();
+ }
+}
+
+template <typename T>
+void BiosHandler<T>::listenBiosAttributes()
+{
+ static std::shared_ptr<sdbusplus::bus::match_t> l_biosMatch =
+ std::make_shared<sdbusplus::bus::match_t>(
+ *m_asioConn,
+ sdbusplus::bus::match::rules::propertiesChanged(
+ constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface),
+ [this](sdbusplus::message_t& l_msg) {
+ m_specificBiosHandler->biosAttributesCallback(l_msg);
+ });
+}
+
+void IbmBiosHandler::biosAttributesCallback(sdbusplus::message_t& i_msg)
+{
+ if (i_msg.is_method_error())
+ {
+ logging::logMessage("Error in reading BIOS attribute signal. ");
+ return;
+ }
+
+ std::string l_objPath;
+ types::BiosBaseTableType l_propMap;
+ i_msg.read(l_objPath, l_propMap);
+
+ for (auto l_property : l_propMap)
+ {
+ if (l_property.first != "BaseBIOSTable")
+ {
+ // Looking for change in Base BIOS table only.
+ continue;
+ }
+
+ if (auto l_attributeList =
+ std::get_if<std::map<std::string, types::BiosProperty>>(
+ &(l_property.second)))
+ {
+ for (const auto& l_attribute : *l_attributeList)
+ {
+ if (auto l_val = std::get_if<std::string>(
+ &(std::get<5>(std::get<1>(l_attribute)))))
+ {
+ std::string l_attributeName = std::get<0>(l_attribute);
+ if (l_attributeName == "hb_memory_mirror_mode")
+ {
+ saveAmmToVpd(*l_val);
+ }
+
+ if (l_attributeName == "pvm_keep_and_clear")
+ {
+ saveKeepAndClearToVpd(*l_val);
+ }
+
+ if (l_attributeName == "pvm_create_default_lpar")
+ {
+ saveCreateDefaultLparToVpd(*l_val);
+ }
+
+ if (l_attributeName == "pvm_clear_nvram")
+ {
+ saveClearNvramToVpd(*l_val);
+ }
+
+ continue;
+ }
+
+ if (auto l_val = std::get_if<int64_t>(
+ &(std::get<5>(std::get<1>(l_attribute)))))
+ {
+ std::string l_attributeName = std::get<0>(l_attribute);
+ if (l_attributeName == "hb_field_core_override")
+ {
+ saveFcoToVpd(*l_val);
+ }
+ }
+ }
+ }
+ else
+ {
+ // TODO: log a predicitive PEL.
+ logging::logMessage("Invalid typre received from BIOS table.");
+ break;
+ }
+ }
+}
+
+void IbmBiosHandler::backUpOrRestoreBiosAttributes()
+{
+ // process FCO
+ processFieldCoreOverride();
+
+ // process AMM
+ processActiveMemoryMirror();
+
+ // process LPAR
+ processCreateDefaultLpar();
+
+ // process clear NVRAM
+ processClearNvram();
+
+ // process keep and clear
+ processKeepAndClear();
+}
+
+types::BiosAttributeCurrentValue
+ IbmBiosHandler::readBiosAttribute(const std::string& i_attributeName)
+{
+ types::BiosAttributeCurrentValue l_attrValueVariant =
+ dbusUtility::biosGetAttributeMethodCall(i_attributeName);
+
+ return l_attrValueVariant;
+}
+
+void IbmBiosHandler::processFieldCoreOverride()
+{
+ // TODO: Should we avoid doing this at runtime?
+
+ // Read required keyword from Dbus.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::vsysInf, constants::kwdRG);
+
+ if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ // default length of the keyword is 4 bytes.
+ if (l_fcoInVpd->size() != constants::VALUE_4)
+ {
+ logging::logMessage(
+ "Invalid value read for FCO from D-Bus. Skipping.");
+ }
+
+ // If FCO in VPD contains anything other that ASCII Space, restore to
+ // BIOS
+ if (std::any_of(l_fcoInVpd->cbegin(), l_fcoInVpd->cend(),
+ [](uint8_t l_val) {
+ return l_val != constants::ASCII_OF_SPACE;
+ }))
+ {
+ // Restore the data to BIOS.
+ saveFcoToBios(*l_fcoInVpd);
+ }
+ else
+ {
+ types::BiosAttributeCurrentValue l_attrValueVariant =
+ readBiosAttribute("hb_field_core_override");
+
+ if (auto l_fcoInBios = std::get_if<int64_t>(&l_attrValueVariant))
+ {
+ // save the BIOS data to VPD
+ saveFcoToVpd(*l_fcoInBios);
+
+ return;
+ }
+ logging::logMessage("Invalid type recieved for FCO from BIOS.");
+ }
+ return;
+ }
+ logging::logMessage("Invalid type recieved for FCO from VPD.");
+}
+
+void IbmBiosHandler::saveFcoToVpd(int64_t i_fcoInBios)
+{
+ if (i_fcoInBios < 0)
+ {
+ logging::logMessage("Invalid FCO value in BIOS. Skip updating to VPD");
+ return;
+ }
+
+ // Read required keyword from Dbus.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::vsysInf, constants::kwdRG);
+
+ if (auto l_fcoInVpd = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ // default length of the keyword is 4 bytes.
+ if (l_fcoInVpd->size() != constants::VALUE_4)
+ {
+ logging::logMessage(
+ "Invalid value read for FCO from D-Bus. Skipping.");
+ return;
+ }
+
+ // convert to VPD value type
+ types::BinaryVector l_biosValInVpdFormat = {
+ 0, 0, 0, static_cast<uint8_t>(i_fcoInBios)};
+
+ // Update only when the data are different.
+ if (std::memcmp(l_biosValInVpdFormat.data(), l_fcoInVpd->data(),
+ constants::VALUE_4) != constants::SUCCESS)
+ {
+ if (constants::FAILURE ==
+ m_manager->updateKeyword(
+ SYSTEM_VPD_FILE_PATH,
+ types::IpzData("VSYS", constants::kwdRG,
+ l_biosValInVpdFormat)))
+ {
+ logging::logMessage(
+ "Failed to update " + std::string(constants::kwdRG) +
+ " keyword to VPD.");
+ }
+ }
+ }
+ else
+ {
+ logging::logMessage("Invalid type read for FCO from DBus.");
+ }
+}
+
+void IbmBiosHandler::saveFcoToBios(const types::BinaryVector& i_fcoVal)
+{
+ if (i_fcoVal.size() != constants::VALUE_4)
+ {
+ logging::logMessage("Bad size for FCO received. Skip writing to BIOS");
+ return;
+ }
+
+ types::PendingBIOSAttrs l_pendingBiosAttribute;
+ l_pendingBiosAttribute.push_back(std::make_pair(
+ "hb_field_core_override",
+ std::make_tuple(
+ "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer",
+ i_fcoVal.at(constants::VALUE_3))));
+
+ try
+ {
+ dbusUtility::writeDbusProperty(
+ constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface, "PendingAttributes",
+ l_pendingBiosAttribute);
+ }
+ catch (const std::exception& l_ex)
+ {
+ // TODO: Should we log informational PEL here as well?
+ logging::logMessage(
+ "DBus call to update FCO value in pending attribute failed. " +
+ std::string(l_ex.what()));
+ }
+}
+
+void IbmBiosHandler::saveAmmToVpd(const std::string& i_memoryMirrorMode)
+{
+ if (i_memoryMirrorMode.empty())
+ {
+ logging::logMessage(
+ "Empty memory mirror mode value from BIOS. Skip writing to VPD");
+ return;
+ }
+
+ // Read existing value.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdAMM);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ auto l_ammValInVpd = *l_pVal;
+
+ types::BinaryVector l_valToUpdateInVpd{
+ (i_memoryMirrorMode == "Enabled" ? constants::AMM_ENABLED_IN_VPD
+ : constants::AMM_DISABLED_IN_VPD)};
+
+ // Check if value is already updated on VPD.
+ if (l_ammValInVpd.at(0) == l_valToUpdateInVpd.at(0))
+ {
+ return;
+ }
+
+ if (constants::FAILURE ==
+ m_manager->updateKeyword(
+ SYSTEM_VPD_FILE_PATH,
+ types::IpzData("UTIL", constants::kwdAMM, l_valToUpdateInVpd)))
+ {
+ logging::logMessage(
+ "Failed to update " + std::string(constants::kwdAMM) +
+ " keyword to VPD");
+ }
+ }
+ else
+ {
+ // TODO: Add PEL
+ logging::logMessage(
+ "Invalid type read for memory mirror mode value from DBus. Skip writing to VPD");
+ }
+}
+
+void IbmBiosHandler::saveAmmToBios(const std::string& i_ammVal)
+{
+ if (i_ammVal.size() != constants::VALUE_1)
+ {
+ logging::logMessage("Bad size for AMM received, Skip writing to BIOS");
+ return;
+ }
+
+ const std::string l_valtoUpdate =
+ (i_ammVal.at(0) == constants::VALUE_2) ? "Enabled" : "Disabled";
+
+ types::PendingBIOSAttrs l_pendingBiosAttribute;
+ l_pendingBiosAttribute.push_back(std::make_pair(
+ "hb_memory_mirror_mode",
+ std::make_tuple(
+ "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
+ l_valtoUpdate)));
+
+ try
+ {
+ dbusUtility::writeDbusProperty(
+ constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface, "PendingAttributes",
+ l_pendingBiosAttribute);
+ }
+ catch (const std::exception& l_ex)
+ {
+ // TODO: Should we log informational PEL here as well?
+ logging::logMessage(
+ "DBus call to update AMM value in pending attribute failed. " +
+ std::string(l_ex.what()));
+ }
+}
+
+void IbmBiosHandler::processActiveMemoryMirror()
+{
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdAMM);
+
+ if (auto pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ auto l_ammValInVpd = *pVal;
+
+ // Check if active memory mirror value is default in VPD.
+ if (l_ammValInVpd.at(0) == constants::VALUE_0)
+ {
+ types::BiosAttributeCurrentValue l_attrValueVariant =
+ readBiosAttribute("hb_memory_mirror_mode");
+
+ if (auto pVal = std::get_if<std::string>(&l_attrValueVariant))
+ {
+ saveAmmToVpd(*pVal);
+ return;
+ }
+ logging::logMessage(
+ "Invalid type recieved for auto memory mirror mode from BIOS.");
+ return;
+ }
+ else
+ {
+ saveAmmToBios(std::to_string(l_ammValInVpd.at(0)));
+ }
+ return;
+ }
+ logging::logMessage(
+ "Invalid type recieved for auto memory mirror mode from VPD.");
+}
+
+void IbmBiosHandler::saveCreateDefaultLparToVpd(
+ const std::string& i_createDefaultLparVal)
+{
+ if (i_createDefaultLparVal.empty())
+ {
+ logging::logMessage(
+ "Empty value received for Lpar from BIOS. Skip writing in VPD.");
+ return;
+ }
+
+ // Read required keyword from DBus as we need to set only a Bit.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ commonUtility::toLower(
+ const_cast<std::string&>(i_createDefaultLparVal));
+
+ // Check for second bit. Bit set for enabled else disabled.
+ if (((((*l_pVal).at(0) & 0x02) == 0x02) &&
+ (i_createDefaultLparVal.compare("enabled") ==
+ constants::STR_CMP_SUCCESS)) ||
+ ((((*l_pVal).at(0) & 0x02) == 0x00) &&
+ (i_createDefaultLparVal.compare("disabled") ==
+ constants::STR_CMP_SUCCESS)))
+ {
+ // Values are same, Don;t update.
+ return;
+ }
+
+ types::BinaryVector l_valToUpdateInVpd;
+ if (i_createDefaultLparVal.compare("enabled") ==
+ constants::STR_CMP_SUCCESS)
+ {
+ // 2nd Bit is used to store the value.
+ l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) | 0x02);
+ }
+ else
+ {
+ // 2nd Bit is used to store the value.
+ l_valToUpdateInVpd.emplace_back((*l_pVal).at(0) & ~(0x02));
+ }
+
+ if (-1 ==
+ m_manager->updateKeyword(
+ SYSTEM_VPD_FILE_PATH,
+ types::IpzData("UTIL", constants::kwdClearNVRAM_CreateLPAR,
+ l_valToUpdateInVpd)))
+ {
+ logging::logMessage(
+ "Failed to update " +
+ std::string(constants::kwdClearNVRAM_CreateLPAR) +
+ " keyword to VPD");
+ }
+
+ return;
+ }
+ logging::logMessage(
+ "Invalid type recieved for create default Lpar from VPD.");
+}
+
+void IbmBiosHandler::saveCreateDefaultLparToBios(
+ const std::string& i_createDefaultLparVal)
+{
+ // checking for exact length as it is a string and can have garbage value.
+ if (i_createDefaultLparVal.size() != constants::VALUE_1)
+ {
+ logging::logMessage(
+ "Bad size for Create default LPAR in VPD. Skip writing to BIOS.");
+ return;
+ }
+
+ std::string l_valtoUpdate =
+ (i_createDefaultLparVal.at(0) & 0x02) ? "Enabled" : "Disabled";
+
+ types::PendingBIOSAttrs l_pendingBiosAttribute;
+ l_pendingBiosAttribute.push_back(std::make_pair(
+ "pvm_create_default_lpar",
+ std::make_tuple(
+ "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
+ l_valtoUpdate)));
+
+ try
+ {
+ dbusUtility::writeDbusProperty(
+ constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface, "PendingAttributes",
+ l_pendingBiosAttribute);
+ }
+ catch (const std::exception& l_ex)
+ {
+ logging::logMessage(
+ "DBus call to update lpar value in pending attribute failed. " +
+ std::string(l_ex.what()));
+ }
+
+ return;
+}
+
+void IbmBiosHandler::processCreateDefaultLpar()
+{
+ // Read required keyword from DBus.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ saveCreateDefaultLparToBios(std::to_string(l_pVal->at(0)));
+ return;
+ }
+ logging::logMessage(
+ "Invalid type recieved for create default Lpar from VPD.");
+}
+
+void IbmBiosHandler::saveClearNvramToVpd(const std::string& i_clearNvramVal)
+{
+ if (i_clearNvramVal.empty())
+ {
+ logging::logMessage(
+ "Empty value received for clear NVRAM from BIOS. Skip updating to VPD.");
+ return;
+ }
+
+ // Read required keyword from DBus as we need to set only a Bit.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ commonUtility::toLower(const_cast<std::string&>(i_clearNvramVal));
+
+ // Check for third bit. Bit set for enabled else disabled.
+ if (((((*l_pVal).at(0) & 0x04) == 0x04) &&
+ (i_clearNvramVal.compare("enabled") ==
+ constants::STR_CMP_SUCCESS)) ||
+ ((((*l_pVal).at(0) & 0x04) == 0x00) &&
+ (i_clearNvramVal.compare("disabled") ==
+ constants::STR_CMP_SUCCESS)))
+ {
+ // Don't update, values are same.
+ return;
+ }
+
+ types::BinaryVector l_valToUpdateInVpd;
+ if (i_clearNvramVal.compare("enabled") == constants::STR_CMP_SUCCESS)
+ {
+ // 3rd bit is used to store the value.
+ l_valToUpdateInVpd.emplace_back(
+ (*l_pVal).at(0) | constants::VALUE_4);
+ }
+ else
+ {
+ // 3rd bit is used to store the value.
+ l_valToUpdateInVpd.emplace_back(
+ (*l_pVal).at(0) & ~(constants::VALUE_4));
+ }
+
+ if (-1 ==
+ m_manager->updateKeyword(
+ SYSTEM_VPD_FILE_PATH,
+ types::IpzData("UTIL", constants::kwdClearNVRAM_CreateLPAR,
+ l_valToUpdateInVpd)))
+ {
+ logging::logMessage(
+ "Failed to update " +
+ std::string(constants::kwdClearNVRAM_CreateLPAR) +
+ " keyword to VPD");
+ }
+
+ return;
+ }
+ logging::logMessage("Invalid type recieved for clear NVRAM from VPD.");
+}
+
+void IbmBiosHandler::saveClearNvramToBios(const std::string& i_clearNvramVal)
+{
+ // Check for the exact length as it is a string and it can have a garbage
+ // value.
+ if (i_clearNvramVal.size() != constants::VALUE_1)
+ {
+ logging::logMessage(
+ "Bad size for clear NVRAM in VPD. Skip writing to BIOS.");
+ return;
+ }
+
+ // 3rd bit is used to store clear NVRAM value.
+ std::string l_valtoUpdate =
+ (i_clearNvramVal.at(0) & constants::VALUE_4) ? "Enabled" : "Disabled";
+
+ types::PendingBIOSAttrs l_pendingBiosAttribute;
+ l_pendingBiosAttribute.push_back(std::make_pair(
+ "pvm_clear_nvram",
+ std::make_tuple(
+ "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
+ l_valtoUpdate)));
+
+ try
+ {
+ dbusUtility::writeDbusProperty(
+ constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface, "PendingAttributes",
+ l_pendingBiosAttribute);
+ }
+ catch (const std::exception& l_ex)
+ {
+ logging::logMessage(
+ "DBus call to update NVRAM value in pending attribute failed. " +
+ std::string(l_ex.what()));
+ }
+}
+
+void IbmBiosHandler::processClearNvram()
+{
+ // Read required keyword from VPD.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdClearNVRAM_CreateLPAR);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ saveClearNvramToBios(std::to_string(l_pVal->at(0)));
+ return;
+ }
+ logging::logMessage("Invalid type recieved for clear NVRAM from VPD.");
+}
+
+void IbmBiosHandler::saveKeepAndClearToVpd(const std::string& i_KeepAndClearVal)
+{
+ if (i_KeepAndClearVal.empty())
+ {
+ logging::logMessage(
+ "Empty value received for keep and clear from BIOS. Skip updating to VPD.");
+ return;
+ }
+
+ // Read required keyword from DBus as we need to set only a Bit.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdKeepAndClear);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ commonUtility::toLower(const_cast<std::string&>(i_KeepAndClearVal));
+
+ // Check for first bit. Bit set for enabled else disabled.
+ if (((((*l_pVal).at(0) & 0x01) == 0x01) &&
+ (i_KeepAndClearVal.compare("enabled") ==
+ constants::STR_CMP_SUCCESS)) ||
+ ((((*l_pVal).at(0) & 0x01) == 0x00) &&
+ (i_KeepAndClearVal.compare("disabled") ==
+ constants::STR_CMP_SUCCESS)))
+ {
+ // Don't update, values are same.
+ return;
+ }
+
+ types::BinaryVector l_valToUpdateInVpd;
+ if (i_KeepAndClearVal.compare("enabled") == constants::STR_CMP_SUCCESS)
+ {
+ // 1st bit is used to store the value.
+ l_valToUpdateInVpd.emplace_back(
+ (*l_pVal).at(0) | constants::VALUE_1);
+ }
+ else
+ {
+ // 1st bit is used to store the value.
+ l_valToUpdateInVpd.emplace_back(
+ (*l_pVal).at(0) & ~(constants::VALUE_1));
+ }
+
+ if (-1 == m_manager->updateKeyword(
+ SYSTEM_VPD_FILE_PATH,
+ types::IpzData("UTIL", constants::kwdKeepAndClear,
+ l_valToUpdateInVpd)))
+ {
+ logging::logMessage(
+ "Failed to update " + std::string(constants::kwdKeepAndClear) +
+ " keyword to VPD");
+ }
+
+ return;
+ }
+ logging::logMessage("Invalid type recieved for keep and clear from VPD.");
+}
+
+void IbmBiosHandler::saveKeepAndClearToBios(
+ const std::string& i_KeepAndClearVal)
+{
+ // checking for exact length as it is a string and can have garbage value.
+ if (i_KeepAndClearVal.size() != constants::VALUE_1)
+ {
+ logging::logMessage(
+ "Bad size for keep and clear in VPD. Skip writing to BIOS.");
+ return;
+ }
+
+ // 1st bit is used to store keep and clear value.
+ std::string l_valtoUpdate =
+ (i_KeepAndClearVal.at(0) & constants::VALUE_1) ? "Enabled" : "Disabled";
+
+ types::PendingBIOSAttrs l_pendingBiosAttribute;
+ l_pendingBiosAttribute.push_back(std::make_pair(
+ "pvm_keep_and_clear",
+ std::make_tuple(
+ "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration",
+ l_valtoUpdate)));
+
+ try
+ {
+ dbusUtility::writeDbusProperty(
+ constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface, "PendingAttributes",
+ l_pendingBiosAttribute);
+ }
+ catch (const std::exception& l_ex)
+ {
+ logging::logMessage(
+ "DBus call to update keep and clear value in pending attribute failed. " +
+ std::string(l_ex.what()));
+ }
+}
+
+void IbmBiosHandler::processKeepAndClear()
+{
+ // Read required keyword from VPD.
+ auto l_kwdValueVariant = dbusUtility::readDbusProperty(
+ constants::pimServiceName, constants::systemVpdInvPath,
+ constants::utilInf, constants::kwdKeepAndClear);
+
+ if (auto l_pVal = std::get_if<types::BinaryVector>(&l_kwdValueVariant))
+ {
+ saveKeepAndClearToBios(std::to_string(l_pVal->at(0)));
+ return;
+ }
+ logging::logMessage("Invalid type recieved for keep and clear from VPD.");
+}
+} // namespace vpd