vpd-tool mfgClean: implement sync BIOS attributes
This commit implements --syncBiosAttributes feature in vpd-tool
--mfgClean. When --syncBiosAttributes is selected along with --mfgClean,
the VPD keywords which are used for backing up BIOS attributes are
updated with the BIOS attribute values read from BIOS Config Manager
service.
Test:
```
- Install BMC image on rainier_2s2u.
- Reboot and wait for BMC to reach Ready state.
- Using vpd-tool, check the value of all the System VPD keywords used
for backing up BIOS attributes both on EEPROM and on D-Bus.
- Run vpd-tool --mfgClean --syncBiosAttributes/-s --yes
- Check return code
- Use pldmtool to check the current values of respective BIOS attributes
- Use vpd-tool, check the value of all the System VPD keywords used for
backing up BIOS attributes, both on EEPROM and on D-Bus.
- The VPD values should correspond with the BIOS attribute values.
- For all other keywords for which --mfgClean applies, the value on
EEPROM and D-Bus should be the default value from the respective
backup_restore JSON file.
```
Change-Id: I57c5df6ac0b3c4c91533d1ef22e69efcd4c87162
Signed-off-by: Souvik Roy <souvikroyofficial10@gmail.com>
diff --git a/vpd-tool/include/tool_constants.hpp b/vpd-tool/include/tool_constants.hpp
index 7fe0190..dbc4eb2 100644
--- a/vpd-tool/include/tool_constants.hpp
+++ b/vpd-tool/include/tool_constants.hpp
@@ -46,5 +46,20 @@
constexpr auto i2cDeviceInf =
"xyz.openbmc_project.Inventory.Decorator.I2CDevice";
constexpr auto vpdManagerProcessName = "vpd-manager";
+constexpr auto biosConfigMgrObjPath =
+ "/xyz/openbmc_project/bios_config/manager";
+constexpr auto biosConfigMgrInterface =
+ "xyz.openbmc_project.BIOSConfig.Manager";
+
+static constexpr auto VALUE_0 = 0;
+static constexpr auto VALUE_1 = 1;
+static constexpr auto VALUE_2 = 2;
+static constexpr auto VALUE_3 = 3;
+static constexpr auto VALUE_4 = 4;
+static constexpr auto VALUE_5 = 5;
+static constexpr auto VALUE_6 = 6;
+static constexpr auto VALUE_7 = 7;
+static constexpr auto VALUE_8 = 8;
+static constexpr auto VALUE_32 = 32;
} // namespace constants
} // namespace vpd
diff --git a/vpd-tool/include/tool_types.hpp b/vpd-tool/include/tool_types.hpp
index 86e942c..56088b1 100644
--- a/vpd-tool/include/tool_types.hpp
+++ b/vpd-tool/include/tool_types.hpp
@@ -4,6 +4,7 @@
#include <cstdint>
#include <tuple>
+#include <unordered_map>
#include <variant>
#include <vector>
@@ -82,5 +83,35 @@
SkipCurrent
};
+using BiosAttributeCurrentValue =
+ std::variant<std::monostate, int64_t, std::string>;
+using BiosAttributePendingValue = std::variant<int64_t, std::string>;
+using BiosGetAttrRetType = std::tuple<std::string, BiosAttributeCurrentValue,
+ BiosAttributePendingValue>;
+
+// VPD keyword to BIOS attribute map
+struct IpzKeyHash
+{
+ std::size_t operator()(const IpzType& i_key) const
+ {
+ return std::hash<std::string>()(std::get<0>(i_key)) ^ std::hash<std::string>()(std::get<1>(i_key));
+ }
+};
+
+struct IpzKeyEqual
+{
+ bool operator()(const IpzType& i_leftKey, const IpzType& i_rightKey) const
+ {
+ return std::get<0>(i_leftKey) == std::get<0>(i_rightKey) && std::get<1>(i_leftKey) == std::get<1>(i_rightKey);
+ }
+};
+
+// Bios attribute metadata container : {attribute name, number of bits, starting bit position, enabled value, disabled value}
+using BiosAttributeMetaData = std::tuple<std::string, uint8_t, std::optional<uint8_t>, std::optional<uint8_t>, std::optional<uint8_t>>;
+
+// IPZ keyword to BIOS attribute map
+//{Record, Keyword} -> {attribute name, number of bits in keyword, starting bit
+// position, enabled value, disabled value}
+using BiosAttributeKeywordMap = std::unordered_map<IpzType,std::vector<BiosAttributeMetaData>,IpzKeyHash,IpzKeyEqual>;
} // namespace types
} // namespace vpd
diff --git a/vpd-tool/include/tool_utils.hpp b/vpd-tool/include/tool_utils.hpp
index d4bde8a..16253ee 100644
--- a/vpd-tool/include/tool_utils.hpp
+++ b/vpd-tool/include/tool_utils.hpp
@@ -903,5 +903,98 @@
return l_retVal;
}
+/**
+ * @brief API to call "GetAttribute" method under BIOS Config Manager.
+ *
+ * The API reads the given attribute from BIOS Config Manager and returns a
+ * variant containing current value for that attribute if the value is found.
+ * API returns an empty variant of type BiosAttributeCurrentValue in case of any
+ * error.
+ *
+ * @param[in] i_attributeName - Attribute to be read.
+ *
+ * @return Tuple of PLDM attribute Type, current attribute value and pending
+ * attribute value.
+ */
+inline types::BiosAttributeCurrentValue biosGetAttributeMethodCall(
+ const std::string& i_attributeName) noexcept
+{
+ types::BiosGetAttrRetType l_attributeVal;
+
+ try
+ {
+ auto l_bus = sdbusplus::bus::new_default();
+ auto l_method = l_bus.new_method_call(
+ constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+ constants::biosConfigMgrInterface, "GetAttribute");
+ l_method.append(i_attributeName);
+
+ auto l_result = l_bus.call(l_method);
+ l_result.read(std::get<0>(l_attributeVal), std::get<1>(l_attributeVal),
+ std::get<2>(l_attributeVal));
+ }
+ catch (const sdbusplus::exception::SdBusError& l_ex)
+ {
+ // TODO : enable logging when verbose is implemented
+ std::cerr << "Failed to read BIOS Attribute: " + i_attributeName +
+ " due to error " + std::string(l_ex.what())
+ << std::endl;
+ }
+
+ return std::get<1>(l_attributeVal);
+}
+
+/**
+ * @brief Converts string to lower case.
+ *
+ * @param [in,out] io_string - Input string.
+ *
+ * @throw std::terminate, std::bad_alloc
+ */
+inline void toLower(std::string& io_string)
+{
+ std::transform(io_string.begin(), io_string.end(), io_string.begin(),
+ [](const unsigned char& l_char) {
+ return std::tolower(l_char);
+ });
+}
+
+/**
+ * @brief Converts an integral data value to a vector of bytes.
+ * The LSB of integer is copied to MSB of the vector.
+ *
+ * @param[in] i_integralData - Input integral data.
+ * @param[in] i_numBytesCopy - Number of bytes to copy.
+ *
+ * @return - On success, returns the Binary vector representation of the
+ * integral data, empty binary vector otherwise.
+ *
+ * @throw std::length_error
+ */
+template <typename T>
+ requires std::integral<T>
+inline types::BinaryVector convertIntegralTypeToBytes(
+ const T& i_integralData, size_t i_numBytesCopy = constants::VALUE_1)
+{
+ types::BinaryVector l_result;
+ constexpr auto l_byteMask{0xFF};
+
+ l_result.resize(i_numBytesCopy, constants::VALUE_0);
+
+ // sanitize number of bytes to copy
+ if (i_numBytesCopy > sizeof(T))
+ {
+ i_numBytesCopy = sizeof(T);
+ }
+
+ // LSB of source -> MSB of result
+ for (size_t l_byte = 0; l_byte < i_numBytesCopy; ++l_byte)
+ {
+ l_result[l_result.size() - (l_byte + constants::VALUE_1)] =
+ (i_integralData >> (l_byte * constants::VALUE_8)) & l_byteMask;
+ }
+ return l_result;
+}
+
} // namespace utils
} // namespace vpd
diff --git a/vpd-tool/include/vpd_tool.hpp b/vpd-tool/include/vpd_tool.hpp
index 0004949..ed2aa00 100644
--- a/vpd-tool/include/vpd_tool.hpp
+++ b/vpd-tool/include/vpd_tool.hpp
@@ -217,8 +217,19 @@
* @throw std::terminate, std::bad_alloc
*/
types::BinaryVector getVpdValueInBiosConfigManager(
- [[maybe_unused]] const std::string& i_recordName,
- [[maybe_unused]] const std::string& i_keywordName) const;
+ const std::string& i_recordName,
+ const std::string& i_keywordName) const;
+
+ /**
+ * @brief VPD keyword to BIOS attribute map
+ *
+ * This map specifies which VPD keyword is used to backup which BIOS
+ * attribute.
+ * {Record, Keyword} -> {attribute name, number of bits in keyword, starting
+ * bit position, enabled value, disabled value}
+ *
+ */
+ static const types::BiosAttributeKeywordMap m_biosAttributeVpdKeywordMap;
public:
/**