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/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index 771d038..9f6492c 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -7,6 +7,7 @@
#include "oem/ibm/libpldm/host.h"
#include "common/utils.hpp"
+#include "oem_ibm_handler.hpp"
#include "pldmd/handler.hpp"
#include <fcntl.h>
@@ -157,7 +158,8 @@
class Handler : public CmdHandler
{
public:
- Handler()
+ Handler(oem_platform::Handler* oemPlatformHandler) :
+ oemPlatformHandler(oemPlatformHandler)
{
handlers.emplace(PLDM_READ_FILE_INTO_MEMORY,
[this](const pldm_msg* request, size_t payloadLength) {
@@ -312,6 +314,9 @@
* @return PLDM response message
*/
Response newFileAvailable(const pldm_msg* request, size_t payloadLength);
+
+ private:
+ oem_platform::Handler* oemPlatformHandler;
};
} // namespace oem_ibm
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
diff --git a/oem/ibm/libpldmresponder/inband_code_update.hpp b/oem/ibm/libpldmresponder/inband_code_update.hpp
new file mode 100644
index 0000000..6607de0
--- /dev/null
+++ b/oem/ibm/libpldmresponder/inband_code_update.hpp
@@ -0,0 +1,128 @@
+#pragma once
+
+#include "common/utils.hpp"
+#include "libpldmresponder/platform.hpp"
+
+#include <string>
+
+using namespace pldm::utils;
+namespace pldm
+{
+namespace responder
+{
+
+static constexpr uint8_t pSideNum = 1;
+static constexpr uint8_t tSideNum = 2;
+static constexpr auto Pside = "P";
+static constexpr auto Tside = "T";
+
+static constexpr auto redundancyIntf =
+ "xyz.openbmc_project.Software.RedundancyPriority";
+
+/** @class CodeUpdate
+ *
+ * @brief This class performs the necessary operation in pldm for
+ * inband code update. That includes taking actions on the
+ * setStateEffecterStates calls from Host and also sending
+ * notification to phosphor-software-manager app
+ */
+class CodeUpdate
+{
+ public:
+ /** @brief Constructor to create an inband codeupdate object
+ * @param[in] dBusIntf - D-Bus handler pointer
+ */
+ CodeUpdate(const pldm::utils::DBusHandler* dBusIntf) : dBusIntf(dBusIntf)
+ {
+ currBootSide = Tside;
+ nextBootSide = Tside;
+ }
+
+ /* @brief Method to return the current boot side
+ */
+ std::string fetchCurrentBootSide();
+
+ /* @brief Method to return the next boot side
+ */
+ std::string fetchNextBootSide();
+
+ /* @brief Method to set the current boot side or
+ * perform a rename operation on current boot side
+ * @param[in] currSide - current side to be set to
+ * @return PLDM_SUCCESS codes
+ */
+ int setCurrentBootSide(const std::string& currSide);
+
+ /* @brief Method to set the next boot side
+ * @param[in] nextSide - next boot side to be set to
+ * @return PLDM_SUCCESS codes
+ */
+ int setNextBootSide(const std::string& nextSide);
+
+ /* @brief Method to set the running and non-running
+ * images
+ */
+ virtual void setVersions();
+
+ /* @brief Method to return the newly upoaded image id in
+ * /tmp
+ */
+ std::string fetchnewImageId()
+ {
+ return newImageId;
+ }
+
+ /* @brief Method to set the oem platform handler in CodeUpdate class */
+ void setOemPlatformHandler(pldm::responder::oem_platform::Handler* handler);
+
+ virtual ~CodeUpdate()
+ {}
+
+ private:
+ std::string currBootSide; //!< current boot side
+ std::string nextBootSide; //!< next boot side
+ std::string runningVersion; //!< currently running image
+ std::string nonRunningVersion; //!< alternate image
+ std::string newImageId; //!< new image id
+ bool codeUpdateInProgress =
+ false; //!< indicates whether codeupdate is going on
+ const pldm::utils::DBusHandler* dBusIntf; //!< D-Bus handler
+ std::vector<std::unique_ptr<sdbusplus::bus::match::match>>
+ captureNextBootSideChange; //!< vector to catch the D-Bus property
+ //!< change for next boot side
+ std::unique_ptr<sdbusplus::bus::match::match>
+ fwUpdateMatcher; //!< pointer to capture the interface added signal for
+ //!< new image
+ pldm::responder::oem_platform::Handler*
+ oemPlatformHandler; //!< oem platform handler
+
+ /* @brief Method to take action when the subscribed D-Bus property is
+ * changed
+ * @param[in] chProperties - list of properties which have changed
+ * @return - none
+ */
+
+ void
+ processPriorityChangeNotification(const DbusChangedProps& chProperties);
+};
+
+/* @brief Method to fetch current or next boot side
+ * @param[in] entityInstance - entity instance for the sensor
+ * @param[in] codeUpdate - pointer to the CodeUpdate object
+ *
+ * @return - boot side
+ */
+uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate);
+
+/* @brief Method to set current or next boot side
+ * @param[in] entityInstance - entity instance for the effecter
+ * @param[in] currState - state to be set
+ * @param[in] stateField - state field set as sent by Host
+ * @return - PLDM_SUCCESS codes
+ */
+int setBootSide(uint16_t entityInstance, uint8_t currState,
+ const std::vector<set_effecter_state_field>& stateField,
+ CodeUpdate* codeUpdate);
+
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
new file mode 100644
index 0000000..2e6bd4c
--- /dev/null
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
@@ -0,0 +1,83 @@
+#include "oem_ibm_handler.hpp"
+
+#include "libpldm/entity.h"
+
+namespace pldm
+{
+
+namespace responder
+{
+
+namespace oem_ibm_platform
+{
+
+int pldm::responder::oem_ibm_platform::Handler::
+ getOemStateSensorReadingsHandler(
+ EntityType entityType, EntityInstance entityInstance,
+ StateSetId stateSetId, CompositeCount compSensorCnt,
+ std::vector<get_sensor_state_field>& stateField)
+{
+ int rc = PLDM_SUCCESS;
+ stateField.clear();
+
+ for (size_t i = 0; i < compSensorCnt; i++)
+ {
+ uint8_t sensorOpState{};
+ if (entityType == PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER &&
+ stateSetId == PLDM_OEM_IBM_BOOT_STATE)
+ {
+ sensorOpState = fetchBootSide(entityInstance, codeUpdate);
+ }
+ else
+ {
+ rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
+ break;
+ }
+ stateField.push_back({PLDM_SENSOR_ENABLED, PLDM_SENSOR_UNKNOWN,
+ PLDM_SENSOR_UNKNOWN, sensorOpState});
+ }
+ return rc;
+}
+
+int pldm::responder::oem_ibm_platform::Handler::
+ oemSetStateEffecterStatesHandler(
+ EntityType entityType, EntityInstance entityInstance,
+ StateSetId stateSetId, CompositeCount compEffecterCnt,
+ const std::vector<set_effecter_state_field>& stateField)
+{
+ int rc = PLDM_SUCCESS;
+
+ for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
+ {
+ if (stateField[currState].set_request == PLDM_REQUEST_SET)
+ {
+ if (entityType == PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER &&
+ stateSetId == PLDM_OEM_IBM_BOOT_STATE)
+ {
+ rc = setBootSide(entityInstance, currState, stateField,
+ codeUpdate);
+ }
+ else
+ {
+ rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
+ }
+ }
+ if (rc != PLDM_SUCCESS)
+ {
+ break;
+ }
+ }
+ return rc;
+}
+
+void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
+ pldm::responder::platform::Handler* handler)
+{
+ platformHandler = handler;
+}
+
+} // namespace oem_ibm_platform
+
+} // namespace responder
+
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
new file mode 100644
index 0000000..2d294f0
--- /dev/null
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "inband_code_update.hpp"
+#include "libpldmresponder/oem_handler.hpp"
+#include "libpldmresponder/platform.hpp"
+
+namespace pldm
+{
+
+namespace responder
+{
+
+namespace oem_ibm_platform
+{
+
+#define PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE 32768
+#define PLDM_OEM_IBM_BOOT_STATE 32769
+
+class Handler : public oem_platform::Handler
+{
+ public:
+ Handler(const pldm::utils::DBusHandler* dBusIntf,
+ pldm::responder::CodeUpdate* codeUpdate) :
+ oem_platform::Handler(dBusIntf),
+ codeUpdate(codeUpdate), platformHandler(nullptr)
+ {
+ codeUpdate->setVersions();
+ }
+
+ int getOemStateSensorReadingsHandler(
+ EntityType entityType, EntityInstance entityInstance,
+ StateSetId stateSetId, CompositeCount compSensorCnt,
+ std::vector<get_sensor_state_field>& stateField);
+
+ int oemSetStateEffecterStatesHandler(
+ EntityType entityType, EntityInstance entityInstance,
+ StateSetId stateSetId, CompositeCount compEffecterCnt,
+ const std::vector<set_effecter_state_field>& stateField);
+
+ /** @brief Method to set the platform handler in the
+ * oem_ibm_handler class
+ * @param[in] handler - pointer to PLDM platform handler
+ */
+ void setPlatformHandler(pldm::responder::platform::Handler* handler);
+
+ ~Handler() = default;
+
+ pldm::responder::CodeUpdate* codeUpdate; //!< pointer to CodeUpdate object
+ pldm::responder::platform::Handler*
+ platformHandler; //!< pointer to PLDM platform handler
+};
+
+} // namespace oem_ibm_platform
+
+} // namespace responder
+
+} // namespace pldm