oem-ibm: Send the event to host when BIOS attribute changes

IBM has the requirement to send a hot update to host when the
BIOS attribute changes. This patch enables sending an OEM platform
event message to host with the details of the BIOS attributes that
changed on the BMC. Once the host acknowledges the event, then BMC
updates the BaseBiosTable in the bios-config-manager. The host comes
down and reads the changed BIOS attributes by calling the command
GetBIOSAttribute value.

Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Change-Id: Id1579bfed1967e653da743313c825b765d227681
diff --git a/oem/ibm/libpldmresponder/platform_oem_ibm.cpp b/oem/ibm/libpldmresponder/platform_oem_ibm.cpp
new file mode 100644
index 0000000..3292004
--- /dev/null
+++ b/oem/ibm/libpldmresponder/platform_oem_ibm.cpp
@@ -0,0 +1,124 @@
+#include "platform_oem_ibm.hpp"

+

+#include "libpldm/platform_oem_ibm.h"

+#include "libpldm/requester/pldm.h"

+

+#include "common/utils.hpp"

+#include "libpldmresponder/pdr.hpp"

+

+#include <iostream>

+

+namespace pldm

+{

+namespace responder

+{

+namespace platform

+{

+

+int sendBiosAttributeUpdateEvent(int fd, uint8_t eid,

+                                 dbus_api::Requester* requester,

+                                 const std::vector<uint16_t>& handles)

+{

+    constexpr auto osStatePath = "/xyz/openbmc_project/state/host0";

+    constexpr auto osStateInterface =

+        "xyz.openbmc_project.State.OperatingSystem.Status";

+    constexpr auto osStateProperty = "OperatingSystemState";

+

+    try

+    {

+        auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(

+            osStatePath, osStateProperty, osStateInterface);

+        const auto& currHostState = std::get<std::string>(propVal);

+        if ((currHostState != "xyz.openbmc_project.State.OperatingSystem."

+                              "Status.OSStatus.Standby") &&

+            (currHostState != "xyz.openbmc_project.State.OperatingSystem."

+                              "Status.OSStatus.BootComplete"))

+        {

+            return PLDM_SUCCESS;

+        }

+    }

+    catch (const sdbusplus::exception::SdBusError& e)

+    {

+        std::cerr << "Error in getting current host state, continue ... \n";

+    }

+

+    auto instanceId = requester->getInstanceId(eid);

+

+    std::vector<uint8_t> requestMsg(

+        sizeof(pldm_msg_hdr) + sizeof(pldm_bios_attribute_update_event_req) -

+            1 + (handles.size() * sizeof(uint16_t)),

+        0);

+

+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());

+

+    auto rc = encode_bios_attribute_update_event_req(

+        instanceId, PLDM_PLATFORM_EVENT_MESSAGE_FORMAT_VERSION,

+        pldm::responder::pdr::BmcMctpEid, handles.size(),

+        reinterpret_cast<const uint8_t*>(handles.data()),

+        requestMsg.size() - sizeof(pldm_msg_hdr), request);

+    if (rc != PLDM_SUCCESS)

+    {

+        std::cerr << "Message encode failure 1. PLDM error code = " << std::hex

+                  << std::showbase << rc << "\n";

+        requester->markFree(eid, instanceId);

+        return rc;

+    }

+

+    if (requestMsg.size())

+    {

+        std::ostringstream tempStream;

+        for (int byte : requestMsg)

+        {

+            tempStream << std::setfill('0') << std::setw(2) << std::hex << byte

+                       << " ";

+        }

+        std::cout << tempStream.str() << std::endl;

+    }

+

+    uint8_t* responseMsg = nullptr;

+    size_t responseMsgSize{};

+

+    rc = pldm_send_recv(eid, fd, requestMsg.data(), requestMsg.size(),

+                        &responseMsg, &responseMsgSize);

+    std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,

+                                                                  std::free};

+    requester->markFree(eid, instanceId);

+

+    if (rc != PLDM_REQUESTER_SUCCESS)

+    {

+        std::cerr << "Failed to send BIOS attribute update event. RC = " << rc

+                  << ", errno = " << errno << "\n";

+        pldm::utils::reportError(

+            "xyz.openbmc_project.bmc.pldm.InternalFailure");

+        return rc;

+    }

+

+    auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());

+    uint8_t completionCode{};

+    uint8_t status{};

+    rc = decode_platform_event_message_resp(

+        responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,

+        &status);

+    if (rc != PLDM_SUCCESS)

+    {

+        std::cerr << "Failed to decode PlatformEventMessage response, rc = "

+                  << rc << "\n";

+        return rc;

+    }

+

+    if (completionCode != PLDM_SUCCESS)

+    {

+        std::cerr << "Failed to send the BIOS attribute update event, rc = "

+                  << (uint32_t)completionCode << "\n";

+        pldm::utils::reportError(

+            "xyz.openbmc_project.bmc.pldm.InternalFailure");

+    }

+

+    return completionCode;

+}

+

+} // namespace platform

+

+} // namespace responder

+

+} // namespace pldm
\ No newline at end of file