bios: Implement BIOSConfig
Load the parsed json configs into memory.
And provid APIs to get/set on bios tables.
Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: Ida1fedc923d31afc61dd2d4aec70d81bb6a90ae9
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
new file mode 100644
index 0000000..d5c39ba
--- /dev/null
+++ b/libpldmresponder/bios_config.cpp
@@ -0,0 +1,260 @@
+#include "bios_config.hpp"
+
+#include "bios_string_attribute.hpp"
+
+#include <fstream>
+#include <iostream>
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+namespace
+{
+
+constexpr auto enumJsonFile = "enum_attrs.json";
+constexpr auto stringJsonFile = "string_attrs.json";
+constexpr auto integerJsonFile = "integer_attrs.json";
+
+constexpr auto stringTableFile = "stringTable";
+constexpr auto attrTableFile = "attributeTable";
+constexpr auto attrValueTableFile = "attributeValueTable";
+
+} // namespace
+
+BIOSConfig::BIOSConfig(const char* jsonDir, const char* tableDir,
+ DBusHandler* const dbusHandler) :
+ jsonDir(jsonDir),
+ tableDir(tableDir), dbusHandler(dbusHandler)
+{
+ constructAttributes();
+}
+
+void BIOSConfig::buildTables()
+{
+ fs::create_directory(tableDir);
+ auto stringTable = buildAndStoreStringTable();
+ if (stringTable)
+ {
+ buildAndStoreAttrTables(*stringTable);
+ }
+}
+
+std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
+{
+ fs::path tablePath;
+ switch (tableType)
+ {
+ case PLDM_BIOS_STRING_TABLE:
+ tablePath = tableDir / stringTableFile;
+ break;
+ case PLDM_BIOS_ATTR_TABLE:
+ tablePath = tableDir / attrTableFile;
+ break;
+ case PLDM_BIOS_ATTR_VAL_TABLE:
+ tablePath = tableDir / attrValueTableFile;
+ break;
+ }
+ return loadTable(tablePath);
+}
+
+void BIOSConfig::constructAttributes()
+{
+ load(jsonDir / stringJsonFile, [this](const Json& entry) {
+ constructAttribute<BIOSStringAttribute>(entry);
+ });
+}
+
+void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
+{
+ BIOSStringTable biosStringTable(stringTable);
+
+ if (biosAttributes.empty())
+ {
+ return;
+ }
+
+ Table attrTable, attrValueTable;
+
+ for (auto& attr : biosAttributes)
+ {
+ try
+ {
+ attr->constructEntry(biosStringTable, attrTable, attrValueTable);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Construct Table Entry Error, AttributeName = "
+ << attr->name << std::endl;
+ }
+ }
+
+ table::appendPadAndChecksum(attrTable);
+ table::appendPadAndChecksum(attrValueTable);
+
+ storeTable(tableDir / attrTableFile, attrTable);
+ storeTable(tableDir / attrValueTableFile, attrValueTable);
+}
+
+std::optional<Table> BIOSConfig::buildAndStoreStringTable()
+{
+ std::set<std::string> strings;
+ auto handler = [&strings](const Json& entry) {
+ strings.emplace(entry.at("attribute_name"));
+ };
+
+ load(jsonDir / stringJsonFile, handler);
+ load(jsonDir / integerJsonFile, handler);
+ load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
+ strings.emplace(entry.at("attribute_name"));
+ auto possibleValues = entry.at("possible_values");
+ for (auto& pv : possibleValues)
+ {
+ strings.emplace(pv);
+ }
+ });
+
+ if (strings.empty())
+ {
+ return std::nullopt;
+ }
+
+ Table table;
+ for (const auto& elem : strings)
+ {
+ table::string::constructEntry(table, elem);
+ }
+
+ table::appendPadAndChecksum(table);
+ storeTable(tableDir / stringTableFile, table);
+ return table;
+}
+
+void BIOSConfig::storeTable(const fs::path& path, const Table& table)
+{
+ BIOSTable biosTable(path.c_str());
+ biosTable.store(table);
+}
+
+std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
+{
+ BIOSTable biosTable(path.c_str());
+ if (biosTable.isEmpty())
+ {
+ return std::nullopt;
+ }
+
+ Table table;
+ biosTable.load(table);
+ return table;
+}
+
+void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
+{
+ std::ifstream file;
+ Json jsonConf;
+ if (fs::exists(filePath))
+ {
+ try
+ {
+ file.open(filePath);
+ jsonConf = Json::parse(file);
+ auto entries = jsonConf.at("entries");
+ for (auto& entry : entries)
+ {
+ try
+ {
+ handler(entry);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr
+ << "Failed to parse JSON config file(entry handler) : "
+ << filePath.c_str() << ", " << e.what() << std::endl;
+ }
+ }
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Failed to parse JSON config file : "
+ << filePath.c_str() << std::endl;
+ }
+ }
+}
+
+int BIOSConfig::setAttrValue(const void* entry, size_t size)
+{
+ auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+ auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+ auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ if (!attrValueTable || !attrTable || !stringTable)
+ {
+ return PLDM_BIOS_TABLE_UNAVAILABLE;
+ }
+
+ auto destTable =
+ table::attribute_value::updateTable(*attrValueTable, entry, size);
+
+ if (!destTable)
+ {
+ return PLDM_ERROR;
+ }
+ auto attrValueEntry =
+ reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
+
+ auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
+
+ auto attrEntry =
+ table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
+ if (!attrEntry)
+ {
+ return PLDM_ERROR;
+ }
+
+ try
+ {
+ auto attrHeader = table::attribute::decodeHeader(attrEntry);
+
+ BIOSStringTable biosStringTable(*stringTable);
+ auto attrName = biosStringTable.findString(attrHeader.stringHandle);
+
+ auto iter = std::find_if(
+ biosAttributes.begin(), biosAttributes.end(),
+ [&attrName](const auto& attr) { return attr->name == attrName; });
+
+ if (iter == biosAttributes.end())
+ {
+ return PLDM_ERROR;
+ }
+ (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Set attribute value error: " << e.what() << std::endl;
+ return PLDM_ERROR;
+ }
+
+ BIOSTable biosAttrValueTable((tableDir / attrValueTableFile).c_str());
+ biosAttrValueTable.store(*destTable);
+ return PLDM_SUCCESS;
+}
+
+void BIOSConfig::removeTables()
+{
+ try
+ {
+ fs::remove(tableDir / stringTableFile);
+ fs::remove(tableDir / attrTableFile);
+ fs::remove(tableDir / attrValueTableFile);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Remove the tables error: " << e.what() << std::endl;
+ }
+}
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/bios_config.hpp b/libpldmresponder/bios_config.hpp
new file mode 100644
index 0000000..dd892b1
--- /dev/null
+++ b/libpldmresponder/bios_config.hpp
@@ -0,0 +1,127 @@
+#pragma once
+
+#include "bios_attribute.hpp"
+#include "bios_table.hpp"
+
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <nlohmann/json.hpp>
+#include <optional>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "bios_table.h"
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+
+/** @class BIOSConfig
+ * @brief Manager BIOS Attributes
+ */
+class BIOSConfig
+{
+ public:
+ BIOSConfig() = delete;
+ BIOSConfig(const BIOSConfig&) = delete;
+ BIOSConfig(BIOSConfig&&) = delete;
+ BIOSConfig& operator=(const BIOSConfig&) = delete;
+ BIOSConfig& operator=(BIOSConfig&&) = delete;
+ ~BIOSConfig() = default;
+
+ /** @brief Construct BIOSConfig
+ * @param[in] jsonDir - The directory where json file exists
+ * @param[in] tableDir - The directory where the persistent table is placed
+ * @param[in] dbusHandler - Dbus Handler
+ */
+ explicit BIOSConfig(const char* jsonDir, const char* tableDir,
+ DBusHandler* const dbusHandler);
+
+ /** @brief Set attribute value on dbus and attribute value table
+ * @param[in] entry - attribute value entry
+ * @param[in] size - size of the attribute value entry
+ * @return pldm_completion_codes
+ */
+ int setAttrValue(const void* entry, size_t size);
+
+ /** @brief Remove the persistent tables */
+ void removeTables();
+
+ /** @brief Build bios tables(string,attribute,attribute value table)*/
+ void buildTables();
+
+ /** @brief Get BIOS table of specified type
+ * @param[in] tableType - The table type
+ * @return The bios table, std::nullopt if the table is unaviliable
+ */
+ std::optional<Table> getBIOSTable(pldm_bios_table_types tableType);
+
+ private:
+ const fs::path jsonDir;
+ const fs::path tableDir;
+ DBusHandler* const dbusHandler;
+
+ // vector persists all attributes
+ using BIOSAttributes = std::vector<std::unique_ptr<BIOSAttribute>>;
+ BIOSAttributes biosAttributes;
+
+ /** @brief Construct an attribute and persist it
+ * @tparam T - attribute type
+ * @param[in] entry - json entry
+ */
+ template <typename T>
+ void constructAttribute(const Json& entry)
+ {
+ try
+ {
+ biosAttributes.push_back(std::make_unique<T>(entry, dbusHandler));
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Constructs Attribute Error, " << e.what()
+ << std::endl;
+ }
+ }
+
+ /** Construct attributes and persist them */
+ void constructAttributes();
+
+ using ParseHandler = std::function<void(const Json& entry)>;
+
+ /** @brief Helper function to parse json
+ * @param[in] filePath - Path of json file
+ * @param[in] handler - Handler to process each entry in the json
+ */
+ void load(const fs::path& filePath, ParseHandler handler);
+
+ /** @brief Build String Table and persist it
+ * @return The built string table, std::nullopt if it fails.
+ */
+ std::optional<Table> buildAndStoreStringTable();
+
+ /** @brief Build attr table and attr value table and persist them
+ * @param[in] stringTable - The string Table
+ */
+ void buildAndStoreAttrTables(const Table& stringTable);
+
+ /** @brief Persist the table
+ * @param[in] path - Path to persist the table
+ * @param[in] table - The table
+ */
+ void storeTable(const fs::path& path, const Table& table);
+
+ /** @brief Load bios table to ram
+ * @param[in] path - Path of the table
+ * @return The table, std::nullopt if loading fails
+ */
+ std::optional<Table> loadTable(const fs::path& path);
+};
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm
\ No newline at end of file
diff --git a/libpldmresponder/bios_table.cpp b/libpldmresponder/bios_table.cpp
index e68884b..4a190f0 100644
--- a/libpldmresponder/bios_table.cpp
+++ b/libpldmresponder/bios_table.cpp
@@ -82,6 +82,16 @@
namespace table
{
+void appendPadAndChecksum(Table& table)
+{
+ auto sizeWithoutPad = table.size();
+ auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad);
+ table.resize(table.size() + padAndChecksumSize);
+
+ pldm_bios_table_append_pad_checksum(table.data(), table.size(),
+ sizeWithoutPad);
+}
+
namespace string
{
@@ -98,6 +108,17 @@
buffer.size());
return std::string(buffer.data(), buffer.data() + strLength);
}
+const pldm_bios_string_table_entry* constructEntry(Table& table,
+ const std::string& str)
+{
+ auto tableSize = table.size();
+ auto entryLength = pldm_bios_table_string_entry_encode_length(str.length());
+ table.resize(tableSize + entryLength);
+ pldm_bios_table_string_entry_encode(table.data() + tableSize, entryLength,
+ str.c_str(), str.length());
+ return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() +
+ tableSize);
+}
} // namespace string
@@ -112,6 +133,13 @@
return {attrHandle, attrType, stringHandle};
}
+const pldm_bios_attr_table_entry* findByHandle(const Table& table,
+ uint16_t handle)
+{
+ return pldm_bios_table_attr_find_by_handle(table.data(), table.size(),
+ handle);
+}
+
const pldm_bios_attr_table_entry*
constructStringEntry(Table& table,
pldm_bios_table_attr_entry_string_info* info)
@@ -179,6 +207,30 @@
return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
tableSize);
}
+std::optional<Table> updateTable(const Table& table, const void* entry,
+ size_t size)
+{
+ // Replace the old attribute with the new attribute, the size of table will
+ // change:
+ // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) -
+ // sizeof(oldAttribute) + pad(4-byte alignment, max =
+ // 3)
+ // For simplicity, we use
+ // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3
+ size_t destBufferLength = table.size() + size + 3;
+ Table destTable(destBufferLength);
+
+ auto rc = pldm_bios_table_attr_value_copy_and_update(
+ table.data(), table.size(), destTable.data(), &destBufferLength, entry,
+ size);
+ if (rc != PLDM_SUCCESS)
+ {
+ return std::nullopt;
+ }
+ destTable.resize(destBufferLength);
+
+ return destTable;
+}
} // namespace attribute_value
diff --git a/libpldmresponder/bios_table.hpp b/libpldmresponder/bios_table.hpp
index d1dc7c9..4a482db 100644
--- a/libpldmresponder/bios_table.hpp
+++ b/libpldmresponder/bios_table.hpp
@@ -3,6 +3,7 @@
#include <stdint.h>
#include <filesystem>
+#include <optional>
#include <string>
#include <vector>
@@ -137,6 +138,12 @@
namespace table
{
+/** @brief Append Pad and Checksum
+ *
+ * @param[in,out] table - table to be appended with pad and checksum
+ */
+void appendPadAndChecksum(Table& table);
+
namespace string
{
@@ -152,6 +159,15 @@
*/
std::string decodeString(const pldm_bios_string_table_entry* entry);
+/** @brief construct entry of string table at the end of the given
+ * table
+ * @param[in,out] table - The given table
+ * @param[in] str - string itself
+ * @return pointer to the constructed entry
+ */
+const pldm_bios_string_table_entry* constructEntry(Table& table,
+ const std::string& str);
+
} // namespace string
namespace attribute
@@ -173,6 +189,14 @@
*/
TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry);
+/** @brief Find attribute entry by handle
+ * @param[in] table - attribute table
+ * @param[in] handle - attribute handle
+ * @return Pointer to the attribute table entry
+ */
+const pldm_bios_attr_table_entry* findByHandle(const Table& table,
+ uint16_t handle);
+
/** @struct StringField
* @brief String field of attribute table
*/
@@ -239,6 +263,15 @@
constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
const std::string& str);
+/** @brief construct a table with an new entry
+ * @param[in] table - the table need to be updated
+ * @param[in] entry - the new attribute value entry
+ * @param[in] size - size of the new entry
+ * @return newly constructed table, std::nullopt if failed
+ */
+std::optional<Table> updateTable(const Table& table, const void* entry,
+ size_t size);
+
} // namespace attribute_value
} // namespace table
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 372cae0..0a5bfa2 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -12,6 +12,7 @@
'bios_parser.cpp',
'bios_attribute.cpp',
'bios_string_attribute.cpp',
+ 'bios_config.cpp',
'pdr_utils.cpp',
'pdr.cpp',
'platform.cpp',
diff --git a/test/libpldmresponder_bios_config_test.cpp b/test/libpldmresponder_bios_config_test.cpp
new file mode 100644
index 0000000..2a2b72f
--- /dev/null
+++ b/test/libpldmresponder_bios_config_test.cpp
@@ -0,0 +1,255 @@
+#include "bios_utils.hpp"
+#include "libpldmresponder/bios_config.hpp"
+#include "libpldmresponder/bios_string_attribute.hpp"
+#include "mocked_bios.hpp"
+#include "mocked_utils.hpp"
+
+#include <fstream>
+#include <memory>
+#include <nlohmann/json.hpp>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace pldm::bios::utils;
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Throw;
+
+class TestBIOSConfig : public ::testing::Test
+{
+ public:
+ static void SetUpTestCase() // will execute once at the begining of all
+ // TestBIOSConfig objects
+ {
+ char tmpdir[] = "/tmp/BIOSTables.XXXXXX";
+ tableDir = fs::path(mkdtemp(tmpdir));
+
+ std::vector<fs::path> paths = {
+ "./bios_jsons/string_attrs.json",
+ };
+
+ for (auto& path : paths)
+ {
+ std::ifstream file;
+ file.open(path);
+ auto j = Json::parse(file);
+ jsons.emplace_back(j);
+ }
+ }
+
+ std::optional<Json> findJsonEntry(const std::string& name)
+ {
+ for (auto& json : jsons)
+ {
+ auto entries = json.at("entries");
+ for (auto& entry : entries)
+ {
+ auto n = entry.at("attribute_name").get<std::string>();
+ if (n == name)
+ {
+ return entry;
+ }
+ }
+ }
+ return std::nullopt;
+ }
+
+ static void TearDownTestCase() // will be executed once at th end of all
+ // TestBIOSConfig objects
+ {
+ fs::remove_all(tableDir);
+ }
+
+ static fs::path tableDir;
+ static std::vector<Json> jsons;
+};
+
+fs::path TestBIOSConfig::tableDir;
+std::vector<Json> TestBIOSConfig::jsons;
+
+TEST_F(TestBIOSConfig, buildTablesTest)
+{
+ MockdBusHandler dbusHandler;
+
+ ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
+ .WillByDefault(Throw(std::exception()));
+
+ BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler);
+ biosConfig.buildTables();
+
+ auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+ auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+
+ EXPECT_TRUE(stringTable);
+ EXPECT_TRUE(attrTable);
+ EXPECT_TRUE(attrValueTable);
+
+ std::set<std::string> expectedStrings = {"HMCManagedState",
+ "On",
+ "Off",
+ "FWBootSide",
+ "Perm",
+ "Temp",
+ "InbandCodeUpdate",
+ "Allowed",
+ "NotAllowed",
+ "CodeUpdatePolicy",
+ "Concurrent",
+ "Disruptive",
+ "VDD_AVSBUS_RAIL",
+ "SBE_IMAGE_MINIMUM_VALID_ECS",
+ "INTEGER_INVALID_CASE",
+ "str_example1",
+ "str_example2",
+ "str_example3"};
+ std::set<std::string> strings;
+ for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>(
+ stringTable->data(), stringTable->size()))
+ {
+ auto str = table::string::decodeString(entry);
+ strings.emplace(str);
+ }
+
+ EXPECT_EQ(strings, expectedStrings);
+
+ BIOSStringTable biosStringTable(*stringTable);
+
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(),
+ attrTable->size()))
+ {
+ auto header = table::attribute::decodeHeader(entry);
+ auto attrName = biosStringTable.findString(header.stringHandle);
+ auto jsonEntry = findJsonEntry(attrName);
+ EXPECT_TRUE(jsonEntry);
+ switch (header.attrType)
+ {
+ case PLDM_BIOS_STRING:
+ case PLDM_BIOS_STRING_READ_ONLY:
+ {
+ auto stringField = table::attribute::decodeStringEntry(entry);
+ auto stringType = BIOSStringAttribute::strTypeMap.at(
+ jsonEntry->at("string_type").get<std::string>());
+ EXPECT_EQ(stringField.stringType,
+ static_cast<uint8_t>(stringType));
+
+ EXPECT_EQ(
+ stringField.minLength,
+ jsonEntry->at("minimum_string_length").get<uint16_t>());
+ EXPECT_EQ(
+ stringField.maxLength,
+ jsonEntry->at("maximum_string_length").get<uint16_t>());
+ EXPECT_EQ(
+ stringField.defLength,
+ jsonEntry->at("default_string_length").get<uint16_t>());
+ EXPECT_EQ(stringField.defString,
+ jsonEntry->at("default_string").get<std::string>());
+ break;
+ }
+ default:
+ EXPECT_TRUE(false);
+ break;
+ }
+ }
+
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+ attrValueTable->data(), attrValueTable->size()))
+ {
+ auto header = table::attribute_value::decodeHeader(entry);
+ auto attrEntry =
+ table::attribute::findByHandle(*attrTable, header.attrHandle);
+ auto attrHeader = table::attribute::decodeHeader(attrEntry);
+ auto attrName = biosStringTable.findString(attrHeader.stringHandle);
+ auto jsonEntry = findJsonEntry(attrName);
+ EXPECT_TRUE(jsonEntry);
+ switch (header.attrType)
+ {
+ case PLDM_BIOS_STRING:
+ case PLDM_BIOS_STRING_READ_ONLY:
+ {
+ auto value = table::attribute_value::decodeStringEntry(entry);
+ auto defValue =
+ jsonEntry->at("default_string").get<std::string>();
+ EXPECT_EQ(value, defValue);
+ break;
+ }
+ default:
+ EXPECT_TRUE(false);
+ break;
+ }
+ }
+}
+
+TEST_F(TestBIOSConfig, setAttrValue)
+{
+ MockdBusHandler dbusHandler;
+
+ BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler);
+ biosConfig.removeTables();
+ biosConfig.buildTables();
+
+ auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+ BIOSStringTable biosStringTable(*stringTable);
+ BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(),
+ attrTable->size());
+ auto stringHandle = biosStringTable.findHandle("str_example1");
+ uint16_t attrHandle{};
+
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(),
+ attrTable->size()))
+ {
+ auto header = table::attribute::decodeHeader(entry);
+ if (header.stringHandle == stringHandle)
+ {
+ attrHandle = header.attrHandle;
+ break;
+ }
+ }
+
+ EXPECT_NE(attrHandle, 0);
+
+ std::vector<uint8_t> attrValueEntry{
+ 0, 0, /* attr handle */
+ 1, /* attr type string read-write */
+ 4, 0, /* current string length */
+ 'a', 'b', 'c', 'd', /* defaut value string handle index */
+ };
+
+ attrValueEntry[0] = attrHandle & 0xff;
+ attrValueEntry[1] = (attrHandle >> 8) & 0xff;
+
+ DBusMapping dbusMapping{"/xyz/abc/def",
+ "xyz.openbmc_project.str_example1.value",
+ "Str_example1", "string"};
+ PropertyValue value = std::string("abcd");
+ EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1);
+
+ auto rc =
+ biosConfig.setAttrValue(attrValueEntry.data(), attrValueEntry.size());
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+
+ auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+ auto findEntry =
+ [&attrValueTable](
+ uint16_t handle) -> const pldm_bios_attr_val_table_entry* {
+ for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+ attrValueTable->data(), attrValueTable->size()))
+ {
+ auto [attrHandle, _] = table::attribute_value::decodeHeader(entry);
+ if (attrHandle == handle)
+ return entry;
+ }
+ return nullptr;
+ };
+
+ auto entry = findEntry(attrHandle);
+ EXPECT_NE(entry, nullptr);
+
+ auto p = reinterpret_cast<const uint8_t*>(entry);
+ EXPECT_THAT(std::vector<uint8_t>(p, p + attrValueEntry.size()),
+ ElementsAreArray(attrValueEntry));
+}
diff --git a/test/meson.build b/test/meson.build
index 827f9fc..5c03866 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -21,6 +21,7 @@
'libpldmresponder_bios_test',
'libpldmresponder_bios_attribute_test',
'libpldmresponder_bios_string_attribute_test',
+ 'libpldmresponder_bios_config_test',
'libpldmresponder_pdr_state_effecter_test',
'libpldmresponder_bios_table_test',
'libpldmresponder_platform_test',