oem ibm: infrastructure for oem handlers

1. This commit adds the framework for an oem handler
which can be used by specific oem use-cases
for implementing various commands.

2. This commit adds implementation for getStateSensorReadings
and setStateEffecterStates commands for oem state sets.

3. Also adds implementation for inband code update.

Change-Id: Ib38a66ee381dd06b93f6a9313d51de1c23e6ee65
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/oem/ibm/libpldmresponder/inband_code_update.cpp b/oem/ibm/libpldmresponder/inband_code_update.cpp
new file mode 100644
index 0000000..f17b209
--- /dev/null
+++ b/oem/ibm/libpldmresponder/inband_code_update.cpp
@@ -0,0 +1,217 @@
+#include "inband_code_update.hpp"
+
+#include "oem_ibm_handler.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <sdbusplus/server.hpp>
+#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
+
+#include <exception>
+
+namespace pldm
+{
+
+namespace responder
+{
+using namespace oem_ibm_platform;
+
+std::string CodeUpdate::fetchCurrentBootSide()
+{
+    return currBootSide;
+}
+
+std::string CodeUpdate::fetchNextBootSide()
+{
+    return nextBootSide;
+}
+
+int CodeUpdate::setCurrentBootSide(const std::string& currSide)
+{
+    currBootSide = currSide;
+    return PLDM_SUCCESS;
+}
+
+int CodeUpdate::setNextBootSide(const std::string& nextSide)
+{
+    nextBootSide = nextSide;
+    std::string objPath{};
+    if (nextBootSide == currBootSide)
+    {
+        objPath = runningVersion;
+    }
+    else
+    {
+        objPath = nonRunningVersion;
+    }
+    if (objPath.empty())
+    {
+        std::cerr << "no nonRunningVersion present \n";
+        return PLDM_PLATFORM_INVALID_STATE_VALUE;
+    }
+
+    pldm::utils::DBusMapping dbusMapping{objPath, redundancyIntf, "Priority",
+                                         "uint8_t"};
+    uint8_t val = 0;
+    pldm::utils::PropertyValue value = static_cast<uint8_t>(val);
+    try
+    {
+        dBusIntf->setDbusProperty(dbusMapping, value);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "failed to set the next boot side to " << objPath.c_str()
+                  << " ERROR=" << e.what() << "\n";
+        return PLDM_ERROR;
+    }
+    return PLDM_SUCCESS;
+}
+
+void CodeUpdate::setVersions()
+{
+    static constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
+    static constexpr auto functionalObjPath =
+        "/xyz/openbmc_project/software/functional";
+    static constexpr auto activeObjPath =
+        "/xyz/openbmc_project/software/active";
+    static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
+
+    auto& bus = dBusIntf->getBus();
+
+    try
+    {
+        auto method = bus.new_method_call(mapperService, functionalObjPath,
+                                          propIntf, "Get");
+        method.append("xyz.openbmc_project.Association", "endpoints");
+        std::variant<std::vector<std::string>> paths;
+
+        auto reply = bus.call(method);
+        reply.read(paths);
+
+        runningVersion = std::get<std::vector<std::string>>(paths)[0];
+
+        auto method1 =
+            bus.new_method_call(mapperService, activeObjPath, propIntf, "Get");
+        method1.append("xyz.openbmc_project.Association", "endpoints");
+
+        auto reply1 = bus.call(method1);
+        reply1.read(paths);
+        for (const auto& path : std::get<std::vector<std::string>>(paths))
+        {
+            if (path != runningVersion)
+            {
+                nonRunningVersion = path;
+                break;
+            }
+        }
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "failed to make a d-bus call to Object Mapper "
+                     "Association, ERROR="
+                  << e.what() << "\n";
+        return;
+    }
+
+    using namespace sdbusplus::bus::match::rules;
+    captureNextBootSideChange.push_back(
+        std::make_unique<sdbusplus::bus::match::match>(
+            pldm::utils::DBusHandler::getBus(),
+            propertiesChanged(runningVersion, redundancyIntf),
+            [this](sdbusplus::message::message& msg) {
+                DbusChangedProps props;
+                std::string iface;
+                msg.read(iface, props);
+                processPriorityChangeNotification(props);
+            }));
+    fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+        pldm::utils::DBusHandler::getBus(),
+        "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
+        "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
+        [this](sdbusplus::message::message& msg) {
+            DBusInterfaceAdded interfaces;
+            sdbusplus::message::object_path path;
+            msg.read(path, interfaces);
+            for (auto& interface : interfaces)
+            {
+                if (interface.first ==
+                    "xyz.openbmc_project.Software.Activation")
+                {
+                    newImageId = path.str;
+                    break;
+                }
+            }
+        });
+}
+
+void CodeUpdate::processPriorityChangeNotification(
+    const DbusChangedProps& chProperties)
+{
+    static constexpr auto propName = "Priority";
+    const auto it = chProperties.find(propName);
+    if (it == chProperties.end())
+    {
+        return;
+    }
+    uint8_t newVal = std::get<uint8_t>(it->second);
+    nextBootSide = (newVal == 0) ? currBootSide
+                                 : ((currBootSide == Tside) ? Pside : Tside);
+}
+
+void CodeUpdate::setOemPlatformHandler(
+    pldm::responder::oem_platform::Handler* handler)
+{
+    oemPlatformHandler = handler;
+}
+
+uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate)
+{
+    uint8_t sensorOpState = tSideNum;
+
+    if (entityInstance == 0)
+    {
+        auto currSide = codeUpdate->fetchCurrentBootSide();
+        if (currSide == Pside)
+        {
+            sensorOpState = pSideNum;
+        }
+    }
+    else if (entityInstance == 1)
+    {
+        auto nextSide = codeUpdate->fetchNextBootSide();
+        if (nextSide == Pside)
+        {
+            sensorOpState = pSideNum;
+        }
+    }
+    else
+    {
+        sensorOpState = PLDM_SENSOR_UNKNOWN;
+    }
+
+    return sensorOpState;
+}
+
+int setBootSide(uint16_t entityInstance, uint8_t currState,
+                const std::vector<set_effecter_state_field>& stateField,
+                CodeUpdate* codeUpdate)
+{
+    int rc = PLDM_SUCCESS;
+    auto side = (stateField[currState].effecter_state == pSideNum) ? "P" : "T";
+
+    if (entityInstance == 0)
+    {
+        rc = codeUpdate->setCurrentBootSide(side);
+    }
+    else if (entityInstance == 1)
+    {
+        rc = codeUpdate->setNextBootSide(side);
+    }
+    else
+    {
+        rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
+    }
+    return rc;
+}
+
+} // namespace responder
+} // namespace pldm