PLDM: System specific BIOS attributes

This commit adds code to populate BIOS attributes
based on the system type that is the platform.

The BIOS Jsons are installed based on the platform/
system type. The system type is populated by entity
manager.

TESTED on hardware across different platform/system type.
On systems where the compatible system interface is not
implemented or entity manager not running, then the BIOS
Jsons with default values are installed.

Signed-off-by: Sagar Srinivas <sagar.srinivas@ibm.com>
Change-Id: I179dad34537ed0d1fb263584d687a1b8cb64c335
diff --git a/common/test/mocked_utils.hpp b/common/test/mocked_utils.hpp
index f8f3665..71bc6e7 100644
--- a/common/test/mocked_utils.hpp
+++ b/common/test/mocked_utils.hpp
@@ -7,7 +7,6 @@
 {
 namespace utils
 {
-
 /** @brief helper function for parameter matching
  *  @param[in] lhs - left-hand side value
  *  @param[in] rhs - right-hand side value
@@ -36,4 +35,8 @@
 
     MOCK_METHOD(pldm::utils::PropertyValue, getDbusPropertyVariant,
                 (const char*, const char*, const char*), (const override));
+
+    MOCK_METHOD(pldm::utils::GetSubTreeResponse, getSubtree,
+                (const std::string&, int, const std::vector<std::string>&),
+                (const override));
 };
diff --git a/common/utils.hpp b/common/utils.hpp
index cc6db01..2ae7b86 100644
--- a/common/utils.hpp
+++ b/common/utils.hpp
@@ -138,7 +138,7 @@
 
 using PropertyValue =
     std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
-                 uint64_t, double, std::string>;
+                 uint64_t, double, std::string, std::vector<std::string>>;
 using DbusProp = std::string;
 using DbusChangedProps = std::map<DbusProp, PropertyValue>;
 using DBusInterfaceAdded = std::vector<
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 4c46b9a..986e74a 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -70,9 +70,10 @@
 DBusHandler dbusHandler;
 
 Handler::Handler(int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb,
-                 pldm::requester::Handler<pldm::requester::Request>* handler) :
+                 pldm::requester::Handler<pldm::requester::Request>* handler,
+                 pldm::responder::oem_bios::Handler* oemBiosHandler) :
     biosConfig(BIOS_JSONS_DIR, BIOS_TABLES_DIR, &dbusHandler, fd, eid,
-               instanceIdDb, handler)
+               instanceIdDb, handler, oemBiosHandler)
 {
     biosConfig.removeTables();
     biosConfig.buildTables();
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index 517231f..bb075d2 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -33,9 +33,11 @@
      *  @param[in] eid - MCTP EID of host firmware
      *  @param[in] instanceIdDb - pointer to an InstanceIdDb object
      *  @param[in] handler - PLDM request handler
+     *  @param[in] systemConfig - pointer to SystemConfig object
      */
     Handler(int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb,
-            pldm::requester::Handler<pldm::requester::Request>* handler);
+            pldm::requester::Handler<pldm::requester::Request>* handler,
+            pldm::responder::oem_bios::Handler* oemBiosHandler);
 
     /** @brief Handler for GetDateTime
      *
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
index a9d7723..094b5e5 100644
--- a/libpldmresponder/bios_config.cpp
+++ b/libpldmresponder/bios_config.cpp
@@ -44,12 +44,21 @@
 BIOSConfig::BIOSConfig(
     const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler,
     int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb,
-    pldm::requester::Handler<pldm::requester::Request>* handler) :
+    pldm::requester::Handler<pldm::requester::Request>* handler,
+    pldm::responder::oem_bios::Handler* oemBiosHandler) :
     jsonDir(jsonDir),
     tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid),
-    instanceIdDb(instanceIdDb), handler(handler)
+    instanceIdDb(instanceIdDb), handler(handler), oemBiosHandler(oemBiosHandler)
 
 {
+    if (oemBiosHandler)
+    {
+        auto systemType = oemBiosHandler->getPlatformName();
+        if (systemType.has_value())
+        {
+            sysType = systemType.value();
+        }
+    }
     fs::create_directories(tableDir);
     constructAttributes();
     listenPendingAttributes();
@@ -473,13 +482,13 @@
 
 void BIOSConfig::constructAttributes()
 {
-    load(jsonDir / stringJsonFile, [this](const Json& entry) {
+    load(jsonDir / sysType / stringJsonFile, [this](const Json& entry) {
         constructAttribute<BIOSStringAttribute>(entry);
     });
-    load(jsonDir / integerJsonFile, [this](const Json& entry) {
+    load(jsonDir / sysType / integerJsonFile, [this](const Json& entry) {
         constructAttribute<BIOSIntegerAttribute>(entry);
     });
-    load(jsonDir / enumJsonFile, [this](const Json& entry) {
+    load(jsonDir / sysType / enumJsonFile, [this](const Json& entry) {
         constructAttribute<BIOSEnumAttribute>(entry);
     });
 }
@@ -561,9 +570,9 @@
         strings.emplace(entry.at("attribute_name"));
     };
 
-    load(jsonDir / stringJsonFile, handler);
-    load(jsonDir / integerJsonFile, handler);
-    load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
+    load(jsonDir / sysType / stringJsonFile, handler);
+    load(jsonDir / sysType / integerJsonFile, handler);
+    load(jsonDir / sysType / enumJsonFile, [&strings](const Json& entry) {
         strings.emplace(entry.at("attribute_name"));
         auto possibleValues = entry.at("possible_values");
         for (auto& pv : possibleValues)
diff --git a/libpldmresponder/bios_config.hpp b/libpldmresponder/bios_config.hpp
index 6e27642..2bd7c72 100644
--- a/libpldmresponder/bios_config.hpp
+++ b/libpldmresponder/bios_config.hpp
@@ -2,6 +2,7 @@
 
 #include "bios_attribute.hpp"
 #include "bios_table.hpp"
+#include "oem_handler.hpp"
 #include "pldmd/instance_id.hpp"
 #include "requester/handler.hpp"
 
@@ -76,12 +77,14 @@
      *  @param[in] eid - MCTP EID of host firmware
      *  @param[in] instanceIdDb - pointer to an InstanceIdDb object
      *  @param[in] handler - PLDM request handler
+     *  @param[in] oemBiosHandler - pointer to oem Bios Handler
      */
     explicit BIOSConfig(
         const char* jsonDir, const char* tableDir,
         pldm::utils::DBusHandler* const dbusHandler, int fd, uint8_t eid,
         pldm::InstanceIdDb* instanceIdDb,
-        pldm::requester::Handler<pldm::requester::Request>* handler);
+        pldm::requester::Handler<pldm::requester::Request>* handler,
+        pldm::responder::oem_bios::Handler* oemBiosHandler);
 
     /** @brief Set attribute value on dbus and attribute value table
      *  @param[in] entry - attribute value entry
@@ -154,6 +157,9 @@
     /** @brief PLDM request handler */
     pldm::requester::Handler<pldm::requester::Request>* handler;
 
+    /** @brief oem Bios Handler*/
+    pldm::responder::oem_bios::Handler* oemBiosHandler;
+
     // vector persists all attributes
     using BIOSAttributes = std::vector<std::unique_ptr<BIOSAttribute>>;
     BIOSAttributes biosAttributes;
@@ -167,6 +173,9 @@
     // vector to catch the D-Bus property change signals for BIOS attributes
     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> biosAttrMatch;
 
+    /** @brief system type/model */
+    std::string sysType;
+
     /** @brief Method to update a BIOS attribute when the corresponding Dbus
      *  property is changed
      *  @param[in] chProperties - list of properties which have changed
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 65d4b99..ad4207b 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -49,6 +49,7 @@
     '../oem/ibm/requester/dbus_to_file_handler.cpp',
     '../oem/ibm/libpldmresponder/file_io_type_progress_src.cpp',
     '../oem/ibm/libpldmresponder/file_io_type_vpd.cpp',
+    '../oem/ibm/libpldmresponder/bios_oem_ibm.cpp',
   ]
 endif
 
@@ -67,3 +68,4 @@
 if get_option('tests').enabled()
   subdir('test')
 endif
+
diff --git a/libpldmresponder/oem_handler.hpp b/libpldmresponder/oem_handler.hpp
index 3e3742d..accfc80 100644
--- a/libpldmresponder/oem_handler.hpp
+++ b/libpldmresponder/oem_handler.hpp
@@ -2,6 +2,7 @@
 
 #include "common/types.hpp"
 #include "common/utils.hpp"
+#include "libpldmresponder/pdr_utils.hpp"
 #include "pldmd/handler.hpp"
 
 namespace pldm
@@ -97,6 +98,28 @@
 
 } // namespace oem_platform
 
+namespace oem_bios
+{
+/** Interface to the oem bios Handler class*/
+class Handler : public CmdHandler
+{
+  public:
+    Handler(const pldm::utils::DBusHandler* dBusIntf) : dBusIntf(dBusIntf) {}
+
+    /** @brief Interface to get the system type information
+     *
+     *  @return - the system type information
+     */
+    virtual std::optional<std::string> getPlatformName() = 0;
+
+    virtual ~Handler() = default;
+
+  protected:
+    const pldm::utils::DBusHandler* dBusIntf;
+};
+
+} // namespace oem_bios
+
 } // namespace responder
 
 } // namespace pldm
diff --git a/libpldmresponder/test/libpldmresponder_bios_config_test.cpp b/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
index 4990f5a..d70a961 100644
--- a/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
+++ b/libpldmresponder/test/libpldmresponder_bios_config_test.cpp
@@ -2,6 +2,7 @@
 #include "common/test/mocked_utils.hpp"
 #include "libpldmresponder/bios_config.hpp"
 #include "libpldmresponder/bios_string_attribute.hpp"
+#include "libpldmresponder/oem_handler.hpp"
 #include "mocked_bios.hpp"
 
 #include <nlohmann/json.hpp>
@@ -18,6 +19,8 @@
 
 using ::testing::_;
 using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::StrEq;
 using ::testing::Throw;
 
 class TestBIOSConfig : public ::testing::Test
@@ -74,15 +77,28 @@
 fs::path TestBIOSConfig::tableDir;
 std::vector<Json> TestBIOSConfig::jsons;
 
+class MockBiosSystemConfig : public pldm::responder::oem_bios::Handler
+{
+  public:
+    MockBiosSystemConfig(const pldm::utils::DBusHandler* dBusIntf) :
+        pldm::responder::oem_bios::Handler(dBusIntf)
+    {}
+    MOCK_METHOD(void, ibmCompatibleAddedCallback,
+                (sdbusplus::message::message&), ());
+    MOCK_METHOD(std::optional<std::string>, getPlatformName, ());
+};
+
 TEST_F(TestBIOSConfig, buildTablesTest)
 {
     MockdBusHandler dbusHandler;
 
+    MockBiosSystemConfig mockBiosSystemConfig(&dbusHandler);
+
     ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
         .WillByDefault(Throw(std::exception()));
 
     BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0,
-                          nullptr, nullptr);
+                          nullptr, nullptr, &mockBiosSystemConfig);
     biosConfig.buildTables();
 
     auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
@@ -101,6 +117,7 @@
                                              "Temp",
                                              "InbandCodeUpdate",
                                              "Allowed",
+                                             "Allowed",
                                              "NotAllowed",
                                              "CodeUpdatePolicy",
                                              "Concurrent",
@@ -246,12 +263,87 @@
     }
 }
 
+TEST_F(TestBIOSConfig, buildTablesSystemSpecificTest)
+{
+    MockdBusHandler dbusHandler;
+
+    MockBiosSystemConfig mockBiosSystemConfig(&dbusHandler);
+
+    ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
+        .WillByDefault(Throw(std::exception()));
+
+    BIOSConfig biosConfig("./system_type1/bios_jsons", tableDir.c_str(),
+                          &dbusHandler, 0, 0, nullptr, nullptr,
+                          &mockBiosSystemConfig);
+
+    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);
+
+    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, setAttrValue)
 {
     MockdBusHandler dbusHandler;
 
+    MockBiosSystemConfig mockBiosSystemConfig(&dbusHandler);
+
     BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0,
-                          nullptr, nullptr);
+                          nullptr, nullptr, &mockBiosSystemConfig);
     biosConfig.removeTables();
     biosConfig.buildTables();
 
diff --git a/libpldmresponder/test/system_type1/bios_jsons/enum_attrs.json b/libpldmresponder/test/system_type1/bios_jsons/enum_attrs.json
new file mode 100644
index 0000000..18c221b
--- /dev/null
+++ b/libpldmresponder/test/system_type1/bios_jsons/enum_attrs.json
@@ -0,0 +1,60 @@
+{
+    "entries": [
+        {
+            "attribute_name": "HMCManagedState",
+            "possible_values": ["On", "Off"],
+            "default_values": ["On"],
+            "readOnly": false,
+            "helpText": "HMCManagedState HelpText",
+            "displayName": "HMCManagedState DisplayName",
+            "dbus": {
+                "object_path": "/xyz/abc/def",
+                "interface": "xyz.openbmc_project.HMCManaged.State",
+                "property_name": "State",
+                "property_type": "string",
+                "property_values": [
+                    "xyz.openbmc_project.State.On",
+                    "xyz.openbmc_project.State.Off"
+                ]
+            }
+        },
+        {
+            "attribute_name": "FWBootSide",
+            "possible_values": ["Perm", "Temp"],
+            "default_values": ["Temp"],
+            "readOnly": false,
+            "helpText": "FWBootSide HelpText",
+            "displayName": "FWBootSide DisplayName",
+            "dbus": {
+                "object_path": "/xyz/abc/def",
+                "interface": "xyz.openbmc.FWBoot.Side",
+                "property_name": "Side",
+                "property_type": "bool",
+                "property_values": [true, false]
+            }
+        },
+        {
+            "attribute_name": "InbandCodeUpdate",
+            "possible_values": ["Allowed", "NotAllowed"],
+            "default_values": ["Allowed"],
+            "readOnly": false,
+            "helpText": "InbandCodeUpdate HelpText",
+            "displayName": "InbandCodeUpdate DisplayName",
+            "dbus": {
+                "object_path": "/xyz/abc/def",
+                "interface": "xyz.openbmc.InBandCodeUpdate",
+                "property_name": "Policy",
+                "property_type": "uint8_t",
+                "property_values": [0, 1]
+            }
+        },
+        {
+            "attribute_name": "CodeUpdatePolicy",
+            "possible_values": ["Concurrent", "Disruptive"],
+            "default_values": ["Concurrent"],
+            "readOnly": true,
+            "helpText": "CodeUpdatePolicy HelpText",
+            "displayName": "CodeUpdatePolicy DisplayName"
+        }
+    ]
+}
diff --git a/libpldmresponder/test/system_type1/bios_jsons/integer_attrs.json b/libpldmresponder/test/system_type1/bios_jsons/integer_attrs.json
new file mode 100644
index 0000000..b735630
--- /dev/null
+++ b/libpldmresponder/test/system_type1/bios_jsons/integer_attrs.json
@@ -0,0 +1,40 @@
+{
+    "entries": [
+        {
+            "attribute_name": "VDD_AVSBUS_RAIL",
+            "lower_bound": 0,
+            "upper_bound": 15,
+            "scalar_increment": 1,
+            "default_value": 0,
+            "readOnly": false,
+            "helpText": "VDD_AVSBUS_RAIL HelpText",
+            "displayName": "VDD_AVSBUS_RAIL DisplayName",
+            "dbus": {
+                "object_path": "/xyz/openbmc_project/avsbus",
+                "interface": "xyz.openbmc.AvsBus.Manager",
+                "property_type": "uint8_t",
+                "property_name": "Rail"
+            }
+        },
+        {
+            "attribute_name": "SBE_IMAGE_MINIMUM_VALID_ECS",
+            "lower_bound": 1,
+            "upper_bound": 30,
+            "scalar_increment": 1,
+            "default_value": 2,
+            "readOnly": true,
+            "helpText": "SBE_IMAGE_MINIMUM_VALID_ECS HelpText",
+            "displayName": "SBE_IMAGE_MINIMUM_VALID_ECS DisplayName"
+        },
+        {
+            "attribute_name": "INTEGER_INVALID_CASE",
+            "lower_bound": 1,
+            "upper_bound": 15,
+            "scalar_increment": 2,
+            "default_value": 3,
+            "readOnly": true,
+            "helpText": "INTEGER_INVALID_CASE HelpText",
+            "displayName": "INTEGER_INVALID_CASE DisplayName"
+        }
+    ]
+}
diff --git a/libpldmresponder/test/system_type1/bios_jsons/string_attrs.json b/libpldmresponder/test/system_type1/bios_jsons/string_attrs.json
new file mode 100644
index 0000000..7e3b8f4
--- /dev/null
+++ b/libpldmresponder/test/system_type1/bios_jsons/string_attrs.json
@@ -0,0 +1,49 @@
+{
+    "entries": [
+        {
+            "attribute_name": "str_example1",
+            "string_type": "ASCII",
+            "minimum_string_length": 1,
+            "maximum_string_length": 100,
+            "default_string_length": 3,
+            "default_string": "abc",
+            "readOnly": false,
+            "helpText": "str_example1 HelpText",
+            "displayName": "str_example1 DisplayName",
+            "dbus": {
+                "object_path": "/xyz/abc/def",
+                "interface": "xyz.openbmc_project.str_example1.value",
+                "property_name": "Str_example1",
+                "property_type": "string"
+            }
+        },
+        {
+            "attribute_name": "str_example2",
+            "string_type": "Hex",
+            "minimum_string_length": 0,
+            "maximum_string_length": 200,
+            "default_string_length": 0,
+            "default_string": "",
+            "readOnly": false,
+            "helpText": "str_example2 HelpText",
+            "displayName": "str_example2 DisplayName",
+            "dbus": {
+                "object_path": "/xyz/abc/def",
+                "interface": "xyz.openbmc_project.str_example2.value",
+                "property_name": "Str_example2",
+                "property_type": "string"
+            }
+        },
+        {
+            "attribute_name": "str_example3",
+            "string_type": "Unknown",
+            "minimum_string_length": 1,
+            "maximum_string_length": 100,
+            "default_string_length": 2,
+            "default_string": "ef",
+            "readOnly": true,
+            "helpText": "str_example3 HelpText",
+            "displayName": "str_example3 DisplayName"
+        }
+    ]
+}
diff --git a/oem/ibm/libpldmresponder/bios_oem_ibm.cpp b/oem/ibm/libpldmresponder/bios_oem_ibm.cpp
new file mode 100644
index 0000000..308eac1
--- /dev/null
+++ b/oem/ibm/libpldmresponder/bios_oem_ibm.cpp
@@ -0,0 +1,103 @@
+#include "bios_oem_ibm.hpp"
+
+namespace pldm
+{
+namespace responder
+{
+namespace oem::ibm::bios
+{
+/** @brief Method to get the system type information
+ *
+ *  @return - the system type information
+ */
+std::optional<std::string>
+    pldm::responder::oem::ibm::bios::Handler::getPlatformName()
+{
+    if (!systemType.empty())
+    {
+        return systemType;
+    }
+
+    static constexpr auto searchpath = "/xyz/openbmc_project/";
+    int depth = 0;
+    std::vector<std::string> ibmCompatible = {compatibleInterface};
+    pldm::utils::GetSubTreeResponse response;
+    try
+    {
+        response = pldm::utils::DBusHandler().getSubtree(searchpath, depth,
+                                                         ibmCompatible);
+    }
+    catch (const sdbusplus::exception_t& e)
+    {
+        error(
+            " getSubtree call failed with, ERROR={ERROR} PATH={PATH} INTERFACE={INTERFACE}",
+            "ERROR", e.what(), "PATH", searchpath, "INTERFACE",
+            ibmCompatible[0]);
+        return std::nullopt;
+    }
+
+    for (const auto& [objectPath, serviceMap] : response)
+    {
+        try
+        {
+            auto value = pldm::utils::DBusHandler()
+                             .getDbusProperty<std::vector<std::string>>(
+                                 objectPath.c_str(), namesProperty,
+                                 ibmCompatible[0].c_str());
+            return value[0];
+        }
+        catch (const sdbusplus::exception_t& e)
+        {
+            error(
+                " Error getting Names property, ERROR={ERROR} PATH={PATH} INTERFACE={INTERFACE}",
+                "ERROR", e.what(), "PATH", searchpath, "INTERFACE",
+                ibmCompatible[0]);
+        }
+    }
+    return std::nullopt;
+}
+
+/** @brief callback function invoked when interfaces get added from
+ *      Entity manager
+ *
+ *  @param[in] msg - Data associated with subscribed signal
+ */
+void pldm::responder::oem::ibm::bios::Handler::ibmCompatibleAddedCallback(
+    sdbusplus::message::message& msg)
+{
+    sdbusplus::message::object_path path;
+
+    pldm::utils::InterfaceMap interfaceMap;
+
+    msg.read(path, interfaceMap);
+
+    if (!interfaceMap.contains(compatibleInterface))
+    {
+        return;
+    }
+    // Get the "Name" property value of the
+    // "xyz.openbmc_project.Configuration.IBMCompatibleSystem" interface
+    const auto& properties = interfaceMap.at(compatibleInterface);
+
+    if (!properties.contains(namesProperty))
+    {
+        return;
+    }
+    auto names =
+        std::get<pldm::utils::Interfaces>(properties.at(namesProperty));
+
+    // get only the first system type
+    if (!names.empty())
+    {
+        systemType = names.front();
+    }
+
+    if (!systemType.empty())
+    {
+        ibmCompatibleMatchConfig.reset();
+    }
+}
+
+} // namespace oem::ibm::bios
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/bios_oem_ibm.hpp b/oem/ibm/libpldmresponder/bios_oem_ibm.hpp
new file mode 100644
index 0000000..242241b
--- /dev/null
+++ b/oem/ibm/libpldmresponder/bios_oem_ibm.hpp
@@ -0,0 +1,60 @@
+#pragma once
+#include "common/utils.hpp"
+#include "libpldmresponder/bios.hpp"
+#include "libpldmresponder/oem_handler.hpp"
+
+#include <filesystem>
+
+namespace pldm
+{
+namespace responder
+{
+namespace oem::ibm::bios
+{
+static constexpr auto compatibleInterface =
+    "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
+static constexpr auto namesProperty = "Names";
+namespace fs = std::filesystem;
+class Handler : public oem_bios::Handler
+{
+  public:
+    Handler(const pldm::utils::DBusHandler* dBusIntf) :
+        oem_bios::Handler(dBusIntf)
+    {
+        ibmCompatibleMatchConfig = std::make_unique<sdbusplus::bus::match_t>(
+            dBusIntf->getBus(),
+            sdbusplus::bus::match::rules::interfacesAdded() +
+                sdbusplus::bus::match::rules::sender(
+                    "xyz.openbmc_project.EntityManager"),
+            std::bind_front(&Handler::ibmCompatibleAddedCallback, this));
+    }
+
+    /** @brief Method to get the system type information
+     *
+     *  @return - the system type information
+     */
+    std::optional<std::string> getPlatformName();
+
+  private:
+    /** @brief system type/model */
+    std::string systemType;
+
+    pldm::responder::bios::Handler* biosHandler;
+
+    /** @brief D-Bus Interface added signal match for Entity Manager */
+    std::unique_ptr<sdbusplus::bus::match::match> ibmCompatibleMatchConfig;
+
+    /** @brief D-Bus Interface object*/
+    const pldm::utils::DBusHandler* dBusIntf;
+
+    /** @brief callback function invoked when interfaces get added from
+     *     Entity manager
+     *
+     *  @param[in] msg - Data associated with subscribed signal
+     */
+    void ibmCompatibleAddedCallback(sdbusplus::message::message& msg);
+};
+
+} // namespace oem::ibm::bios
+} // namespace responder
+} // namespace pldm
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index 4df9f02..11c4ec2 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -57,6 +57,7 @@
 #endif
 
 #ifdef OEM_IBM
+#include "libpldmresponder/bios_oem_ibm.hpp"
 #include "libpldmresponder/file_io.hpp"
 #include "libpldmresponder/oem_ibm_handler.hpp"
 #endif
@@ -256,6 +257,7 @@
             sockfd, hostEID, instanceIdDb, &reqHandler);
     }
     std::unique_ptr<oem_platform::Handler> oemPlatformHandler{};
+    std::unique_ptr<oem_bios::Handler> oemBiosHandler{};
 
 #ifdef OEM_IBM
     std::unique_ptr<pldm::responder::CodeUpdate> codeUpdate =
@@ -268,10 +270,11 @@
     invoker.registerHandler(PLDM_OEM, std::make_unique<oem_ibm::Handler>(
                                           oemPlatformHandler.get(), sockfd,
                                           hostEID, &instanceIdDb, &reqHandler));
+    oemBiosHandler = std::make_unique<oem::ibm::bios::Handler>(&dbusHandler);
 #endif
-    invoker.registerHandler(
-        PLDM_BIOS, std::make_unique<bios::Handler>(sockfd, hostEID,
-                                                   &instanceIdDb, &reqHandler));
+
+    auto biosHandler = std::make_unique<bios::Handler>(
+        sockfd, hostEID, &instanceIdDb, &reqHandler, oemBiosHandler.get());
     auto fruHandler = std::make_unique<fru::Handler>(
         FRU_JSONS_DIR, FRU_MASTER_JSON, pdrRepo.get(), entityTree.get(),
         bmcEntityTree.get());
@@ -287,8 +290,10 @@
         dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
             oemPlatformHandler.get());
     oemIbmPlatformHandler->setPlatformHandler(platformHandler.get());
+
 #endif
 
+    invoker.registerHandler(PLDM_BIOS, std::move(biosHandler));
     invoker.registerHandler(PLDM_PLATFORM, std::move(platformHandler));
     invoker.registerHandler(
         PLDM_BASE,