pldm: Meson option for system specific bios attributes

PLDM users who want to use bios attributes based on the system type
can enable this meson option.
With disabled option default bios json files are picked to build
bios attribute tables.

Added meson option "system-specific-bios-json" to add the support
for system specific bios attributes.
Below is the pre-requisite to support system specific bios
attributes:
1. Entity Manager service is active
2. Entity Manager should have Decorator.Compatible interface
   and system type in Names property under this interface
3. BIOS Attribute json files are added into the folder(Named on
   the System Type property value) and should be installed
   under /usr/share/pldm/bios/

With disabled "system-specific-bios-json" option default bios
attributes are populated.

Tested:
Poweron system-specific-bios-json enabled/disabled

Change-Id: I95a953cdb12c344d22f487b83040356a1b5fa937
Signed-off-by: Archana Kakani <archana.kakani@ibm.com>
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
index 6cc9c24..991b5c0 100644
--- a/libpldmresponder/bios_config.cpp
+++ b/libpldmresponder/bios_config.cpp
@@ -55,33 +55,38 @@
 {
     fs::create_directories(tableDir);
     removeTables();
-    if (isSystemTypeAvailable())
-    {
-        initBIOSAttributes(sysType);
-    }
+
+#ifdef SYSTEM_SPECIFIC_BIOS_JSON
+    checkSystemTypeAvailability();
+#else
+    initBIOSAttributes(sysType, false);
+#endif
+
     listenPendingAttributes();
 }
 
-bool BIOSConfig::isSystemTypeAvailable()
+void BIOSConfig::checkSystemTypeAvailability()
 {
     if (platformConfigHandler)
     {
         auto systemType = platformConfigHandler->getPlatformName();
         if (systemType.has_value())
         {
+            // Received System Type from Entity Manager
             sysType = systemType.value();
+            initBIOSAttributes(sysType, true);
         }
         else
         {
-            platformConfigHandler->registerSystemTypeCallback(std::bind(
-                &BIOSConfig::initBIOSAttributes, this, std::placeholders::_1));
-            return false;
+            platformConfigHandler->registerSystemTypeCallback(
+                std::bind(&BIOSConfig::initBIOSAttributes, this,
+                          std::placeholders::_1, std::placeholders::_2));
         }
     }
-    return true;
 }
 
-void BIOSConfig::initBIOSAttributes(const std::string& systemType)
+void BIOSConfig::initBIOSAttributes(const std::string& systemType,
+                                    bool registerService)
 {
     sysType = systemType;
     fs::path dir{jsonDir / sysType};
@@ -93,7 +98,10 @@
     }
     constructAttributes();
     buildTables();
-    requestPLDMServiceName();
+    if (registerService)
+    {
+        requestPLDMServiceName();
+    }
 }
 
 void BIOSConfig::buildTables()
diff --git a/libpldmresponder/bios_config.hpp b/libpldmresponder/bios_config.hpp
index 2cb13e4..dba7a09 100644
--- a/libpldmresponder/bios_config.hpp
+++ b/libpldmresponder/bios_config.hpp
@@ -132,10 +132,13 @@
 
     /** @brief Construct the BIOS Attributes and build the tables
      *         after receiving system type from entity manager.
+     *         Also register the Service Name only if
+     *         System specific Bios attributes are supported
      *  @param[in] String - System Type
+     *  @param[in] bool - flag to register service name
      *  @return void
      */
-    void initBIOSAttributes(const std::string& sysType);
+    void initBIOSAttributes(const std::string& sysType, bool registerService);
 
   private:
     /** @enum Index into the fields in the BaseBIOSTable
@@ -203,12 +206,12 @@
     void processBiosAttrChangeNotification(
         const DbusChObjProperties& chProperties, uint32_t biosAttrIndex);
 
-    /** @brief Method to get know if the system type is received from entity
-     *  manager or if we want to use the default bios json files.
-     *  @return - Returns true is the system type is received from EM or
-     *            if default option is chosen
+    /** @brief Method is used to initiate bios attributes only if system type
+     *  is already populated by entity manager.
+     *  Register the callback if system type is yet to be populated by Entity
+     * manager
      */
-    bool isSystemTypeAvailable();
+    void checkSystemTypeAvailability();
 
     /** @brief Construct an attribute and persist it
      *  @tparam T - attribute type
diff --git a/libpldmresponder/platform_config.cpp b/libpldmresponder/platform_config.cpp
index 87fd334..5c46199 100644
--- a/libpldmresponder/platform_config.cpp
+++ b/libpldmresponder/platform_config.cpp
@@ -42,7 +42,7 @@
         systemType = names.front();
         if (sysTypeCallback)
         {
-            sysTypeCallback(systemType);
+            sysTypeCallback(systemType, true);
         }
     }
 
diff --git a/libpldmresponder/platform_config.hpp b/libpldmresponder/platform_config.hpp
index 3934c61..16e934c 100644
--- a/libpldmresponder/platform_config.hpp
+++ b/libpldmresponder/platform_config.hpp
@@ -19,7 +19,7 @@
     "xyz.openbmc_project.Inventory.Decorator.Compatible";
 static constexpr auto namesProperty = "Names";
 
-using SystemTypeCallback = std::function<void(const std::string&)>;
+using SystemTypeCallback = std::function<void(const std::string&, bool)>;
 
 class Handler : public CmdHandler
 {
diff --git a/libpldmresponder/test/libpldmresponder_bios_config_test.cpp b/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
index 3a15992..9bcf096 100644
--- a/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
+++ b/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
@@ -90,12 +90,10 @@
 {
     MockdBusHandler dbusHandler;
     MockSystemConfig mockSystemConfig;
+    std::string biosFilePath("./bios_jsons");
 
-    EXPECT_CALL(mockSystemConfig, getPlatformName())
-        .WillOnce(Return(std::filesystem::path("bios_jsons")));
-
-    BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
-                          nullptr, &mockSystemConfig, []() {});
+    BIOSConfig biosConfig(biosFilePath.c_str(), tableDir.c_str(), &dbusHandler,
+                          0, 0, nullptr, nullptr, &mockSystemConfig, []() {});
     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);
@@ -258,83 +256,11 @@
     }
 }
 
-TEST_F(TestBIOSConfig, buildTablesSystemSpecificTest)
-{
-    MockdBusHandler dbusHandler;
-    MockSystemConfig mockSystemConfig;
-
-    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return(""));
-    ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
-        .WillByDefault(Throw(std::exception()));
-
-    BIOSConfig biosConfig("./system_type1/bios_jsons", tableDir.c_str(),
-                          &dbusHandler, 0, 0, nullptr, nullptr,
-                          &mockSystemConfig, []() {});
-
-    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);
-
-    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:
-            {
-                if (attrName == "str_example2")
-                {
-                    auto stringField =
-                        table::attribute::decodeStringEntry(entry);
-                    EXPECT_EQ(stringField.maxLength, 200);
-                }
-
-                break;
-            }
-            case PLDM_BIOS_INTEGER:
-            case PLDM_BIOS_INTEGER_READ_ONLY:
-            {
-                if (attrName == "SBE_IMAGE_MINIMUM_VALID_ECS")
-                {
-                    auto integerField =
-                        table::attribute::decodeIntegerEntry(entry);
-                    EXPECT_EQ(integerField.upperBound, 30);
-                }
-                break;
-            }
-            case PLDM_BIOS_ENUMERATION:
-            case PLDM_BIOS_ENUMERATION_READ_ONLY:
-            {
-                if (attrName == "FWBootSide")
-                {
-                    auto [pvHdls,
-                          defInds] = table::attribute::decodeEnumEntry(entry);
-                    auto defValue =
-                        biosStringTable.findString(pvHdls[defInds[0]]);
-                    EXPECT_EQ(defValue, "Temp");
-                }
-            }
-        }
-    }
-}
-
 TEST_F(TestBIOSConfig, setBIOSTable)
 {
     MockdBusHandler dbusHandler;
     MockSystemConfig mockSystemConfig;
 
-    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons"));
     BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
                           nullptr, &mockSystemConfig, []() {});
 
@@ -360,9 +286,8 @@
     MockdBusHandler dbusHandler;
     MockSystemConfig mockSystemConfig;
 
-    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons"));
-    BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
-                          nullptr, &mockSystemConfig, []() {});
+    BIOSConfig biosConfig("./jsons", tableDir.c_str(), &dbusHandler, 0, 0,
+                          nullptr, nullptr, &mockSystemConfig, []() {});
 
     auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
     auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
@@ -378,9 +303,8 @@
     MockdBusHandler dbusHandler;
     MockSystemConfig mockSystemConfig;
 
-    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons"));
-    BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
-                          nullptr, &mockSystemConfig, []() {});
+    BIOSConfig biosConfig("./jsons", tableDir.c_str(), &dbusHandler, 0, 0,
+                          nullptr, nullptr, &mockSystemConfig, []() {});
 
     std::vector<uint8_t> attrValueEntry{
         0,   0,             /* attr handle */
@@ -395,7 +319,6 @@
 
     auto rc = biosConfig.setAttrValue(attrValueEntry.data(),
                                       attrValueEntry.size(), false);
-    std::cout << "Error in settig Attribute " << rc << std::endl;
     EXPECT_EQ(rc, PLDM_BIOS_TABLE_UNAVAILABLE);
 }
 
@@ -404,7 +327,6 @@
     MockdBusHandler dbusHandler;
     MockSystemConfig mockSystemConfig;
 
-    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return(""));
     BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0,
                           nullptr, nullptr, &mockSystemConfig, []() {});
 
diff --git a/libpldmresponder/test/libpldmresponder_systemspecific_bios_test.cpp b/libpldmresponder/test/libpldmresponder_systemspecific_bios_test.cpp
new file mode 100644
index 0000000..6d80b9d
--- /dev/null
+++ b/libpldmresponder/test/libpldmresponder_systemspecific_bios_test.cpp
@@ -0,0 +1,476 @@
+#include "common/bios_utils.hpp"
+#include "common/test/mocked_utils.hpp"
+#include "libpldmresponder/bios_config.hpp"
+#include "libpldmresponder/bios_string_attribute.hpp"
+#include "libpldmresponder/oem_handler.hpp"
+#include "libpldmresponder/platform_config.hpp"
+#include "mocked_bios.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <fstream>
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace pldm::bios::utils;
+using namespace pldm::responder::bios;
+using namespace pldm::utils;
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Throw;
+
+class TestSystemSpecificBIOSConfig : public ::testing::Test
+{
+  public:
+    static void SetUpTestCase() // will execute once at the begining of all
+                                // TestSystemSpecificBIOSConfig objects
+    {
+        char tmpdir[] = "/tmp/BIOSTables.XXXXXX";
+        tableDir = fs::path(mkdtemp(tmpdir));
+
+        std::vector<fs::path> paths = {
+            "./bios_jsons/string_attrs.json",
+            "./bios_jsons/integer_attrs.json",
+            "./bios_jsons/enum_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
+                                   // TestSystemSpecificBIOSConfig objects
+    {
+        fs::remove_all(tableDir);
+    }
+
+    static fs::path tableDir;
+    static std::vector<Json> jsons;
+};
+
+fs::path TestSystemSpecificBIOSConfig::tableDir;
+std::vector<Json> TestSystemSpecificBIOSConfig::jsons;
+
+class MockSystemConfig : public pldm::responder::platform_config::Handler
+{
+  public:
+    MockSystemConfig() {}
+    MOCK_METHOD(void, ibmCompatibleAddedCallback, (sdbusplus::message_t&), ());
+    MOCK_METHOD(std::optional<std::filesystem::path>, getPlatformName, ());
+};
+
+TEST_F(TestSystemSpecificBIOSConfig, buildTablesTest)
+{
+    MockdBusHandler dbusHandler;
+    MockSystemConfig mockSystemConfig;
+    std::string biosFilePath("./");
+
+    EXPECT_CALL(mockSystemConfig, getPlatformName())
+        .WillOnce(Return(std::filesystem::path("bios_jsons")));
+
+    BIOSConfig biosConfig(biosFilePath.c_str(), tableDir.c_str(), &dbusHandler,
+                          0, 0, nullptr, nullptr, &mockSystemConfig, []() {});
+    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",
+                                             "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;
+            }
+            case PLDM_BIOS_INTEGER:
+            case PLDM_BIOS_INTEGER_READ_ONLY:
+            {
+                auto integerField = table::attribute::decodeIntegerEntry(entry);
+                EXPECT_EQ(integerField.lowerBound,
+                          jsonEntry->at("lower_bound").get<uint64_t>());
+                EXPECT_EQ(integerField.upperBound,
+                          jsonEntry->at("upper_bound").get<uint64_t>());
+                EXPECT_EQ(integerField.scalarIncrement,
+                          jsonEntry->at("scalar_increment").get<uint32_t>());
+                EXPECT_EQ(integerField.defaultValue,
+                          jsonEntry->at("default_value").get<uint64_t>());
+                break;
+            }
+            case PLDM_BIOS_ENUMERATION:
+            case PLDM_BIOS_ENUMERATION_READ_ONLY:
+            {
+                auto [pvHdls,
+                      defInds] = table::attribute::decodeEnumEntry(entry);
+                auto possibleValues = jsonEntry->at("possible_values")
+                                          .get<std::vector<std::string>>();
+                std::vector<std::string> strings;
+                for (auto pv : pvHdls)
+                {
+                    auto s = biosStringTable.findString(pv);
+                    strings.emplace_back(s);
+                }
+                EXPECT_EQ(strings, possibleValues);
+                EXPECT_EQ(defInds.size(), 1);
+
+                auto defValue = biosStringTable.findString(pvHdls[defInds[0]]);
+                auto defaultValues = jsonEntry->at("default_values")
+                                         .get<std::vector<std::string>>();
+                EXPECT_EQ(defValue, defaultValues[0]);
+
+                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;
+            }
+            case PLDM_BIOS_INTEGER:
+            case PLDM_BIOS_INTEGER_READ_ONLY:
+            {
+                auto value = table::attribute_value::decodeIntegerEntry(entry);
+                auto defValue = jsonEntry->at("default_value").get<uint64_t>();
+                EXPECT_EQ(value, defValue);
+                break;
+            }
+            case PLDM_BIOS_ENUMERATION:
+            case PLDM_BIOS_ENUMERATION_READ_ONLY:
+            {
+                auto indices = table::attribute_value::decodeEnumEntry(entry);
+                EXPECT_EQ(indices.size(), 1);
+                auto possibleValues = jsonEntry->at("possible_values")
+                                          .get<std::vector<std::string>>();
+
+                auto defValues = jsonEntry->at("default_values")
+                                     .get<std::vector<std::string>>();
+                EXPECT_EQ(possibleValues[indices[0]], defValues[0]);
+                break;
+            }
+            default:
+                EXPECT_TRUE(false);
+                break;
+        }
+    }
+}
+
+TEST_F(TestSystemSpecificBIOSConfig, buildTablesSystemSpecificTest)
+{
+    MockdBusHandler dbusHandler;
+    MockSystemConfig mockSystemConfig;
+
+    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return(""));
+    ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
+        .WillByDefault(Throw(std::exception()));
+
+    BIOSConfig biosConfig("./system_type1/bios_jsons", tableDir.c_str(),
+                          &dbusHandler, 0, 0, nullptr, nullptr,
+                          &mockSystemConfig, []() {});
+
+    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);
+
+    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:
+            {
+                if (attrName == "str_example2")
+                {
+                    auto stringField =
+                        table::attribute::decodeStringEntry(entry);
+                    EXPECT_EQ(stringField.maxLength, 200);
+                }
+
+                break;
+            }
+            case PLDM_BIOS_INTEGER:
+            case PLDM_BIOS_INTEGER_READ_ONLY:
+            {
+                if (attrName == "SBE_IMAGE_MINIMUM_VALID_ECS")
+                {
+                    auto integerField =
+                        table::attribute::decodeIntegerEntry(entry);
+                    EXPECT_EQ(integerField.upperBound, 30);
+                }
+                break;
+            }
+            case PLDM_BIOS_ENUMERATION:
+            case PLDM_BIOS_ENUMERATION_READ_ONLY:
+            {
+                if (attrName == "FWBootSide")
+                {
+                    auto [pvHdls,
+                          defInds] = table::attribute::decodeEnumEntry(entry);
+                    auto defValue =
+                        biosStringTable.findString(pvHdls[defInds[0]]);
+                    EXPECT_EQ(defValue, "Temp");
+                }
+            }
+        }
+    }
+}
+
+TEST_F(TestSystemSpecificBIOSConfig, setBIOSTable)
+{
+    MockdBusHandler dbusHandler;
+    MockSystemConfig mockSystemConfig;
+
+    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons"));
+    BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
+                          nullptr, &mockSystemConfig, []() {});
+
+    std::set<std::string> strings{"pvm_system_name", "pvm_stop_at_standby",
+                                  "fw_boot_side", "fw_next_boot_side"};
+
+    Table table;
+    for (const auto& elem : strings)
+    {
+        table::string::constructEntry(table, elem);
+    }
+
+    table::appendPadAndChecksum(table);
+    auto rc = biosConfig.setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+    EXPECT_TRUE(stringTable);
+}
+
+TEST_F(TestSystemSpecificBIOSConfig, getBIOSTableFailure)
+{
+    MockdBusHandler dbusHandler;
+    MockSystemConfig mockSystemConfig;
+
+    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons"));
+    BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
+                          nullptr, &mockSystemConfig, []() {});
+
+    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_FALSE(stringTable);
+    EXPECT_FALSE(attrTable);
+    EXPECT_FALSE(attrValueTable);
+}
+
+TEST_F(TestSystemSpecificBIOSConfig, setAttrValueFailure)
+{
+    MockdBusHandler dbusHandler;
+    MockSystemConfig mockSystemConfig;
+
+    EXPECT_CALL(mockSystemConfig, getPlatformName()).WillOnce(Return("jsons"));
+    BIOSConfig biosConfig("./", tableDir.c_str(), &dbusHandler, 0, 0, nullptr,
+                          nullptr, &mockSystemConfig, []() {});
+
+    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 */
+    };
+
+    uint16_t attrHandle{10};
+    attrValueEntry[0] = attrHandle & 0xff;
+    attrValueEntry[1] = (attrHandle >> 8) & 0xff;
+
+    auto rc = biosConfig.setAttrValue(attrValueEntry.data(),
+                                      attrValueEntry.size(), false);
+    std::cout << "Error in settig Attribute " << rc << std::endl;
+    EXPECT_EQ(rc, PLDM_BIOS_TABLE_UNAVAILABLE);
+}
+
+TEST_F(TestSystemSpecificBIOSConfig, setAttrValue)
+{
+    MockdBusHandler dbusHandler;
+    MockSystemConfig mockSystemConfig;
+
+    EXPECT_CALL(mockSystemConfig, getPlatformName())
+        .WillOnce(Return(std::filesystem::path("")));
+
+    BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0,
+                          nullptr, nullptr, &mockSystemConfig, []() {});
+
+    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(), false);
+    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/libpldmresponder/test/meson.build b/libpldmresponder/test/meson.build
index 17eceac..f2242c4 100644
--- a/libpldmresponder/test/meson.build
+++ b/libpldmresponder/test/meson.build
@@ -2,7 +2,6 @@
   'libpldmresponder_base_test',
   'libpldmresponder_bios_test',
   'libpldmresponder_bios_attribute_test',
-  'libpldmresponder_bios_config_test',
   'libpldmresponder_bios_enum_attribute_test',
   'libpldmresponder_bios_integer_attribute_test',
   'libpldmresponder_bios_string_attribute_test',
@@ -21,6 +20,16 @@
   ]
 endif
 
+if get_option('system-specific-bios-json').allowed()
+  tests += [
+    'libpldmresponder_systemspecific_bios_test'
+  ]
+else
+  tests += [
+    'libpldmresponder_bios_config_test'
+  ]
+endif
+
 foreach t : tests
   test(t, executable(t.underscorify(), t + '.cpp',
                      implicit_include_directories: false,
diff --git a/meson.build b/meson.build
index f64e718..b0ca947 100644
--- a/meson.build
+++ b/meson.build
@@ -33,6 +33,7 @@
 endif
 if get_option('libpldmresponder').allowed()
 conf_data.set_quoted('BIOS_JSONS_DIR', join_paths(package_datadir, 'bios'))
+conf_data.set('SYSTEM_SPECIFIC_BIOS_JSON', get_option('system-specific-bios-json').allowed())
 conf_data.set_quoted('BIOS_TABLES_DIR', join_paths(package_localstatedir, 'bios'))
 conf_data.set_quoted('PDR_JSONS_DIR', join_paths(package_datadir, 'pdr'))
 conf_data.set_quoted('FRU_JSONS_DIR', join_paths(package_datadir, 'fru'))
diff --git a/meson.options b/meson.options
index 9e2339f..8449821 100644
--- a/meson.options
+++ b/meson.options
@@ -140,6 +140,14 @@
                     requested by the FD, via RequestFirmwareData command'''
 )
 
+# Bios Attributes option
+option(
+    'system-specific-bios-json',
+    type : 'feature',
+    value: 'disabled',
+    description : 'Support for different set of bios attributes for different types of systems'
+)
+
 # PLDM Soft Power off options
 option(
     'softoff',
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index 3bd9e90..1dd5de8 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -376,6 +376,9 @@
     };
 
     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+#ifndef SYSTEM_SPECIFIC_BIOS_JSON
+    bus.request_name("xyz.openbmc_project.PLDM");
+#endif
     IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
 #ifdef LIBPLDMRESPONDER
     if (hostPDRHandler)