oem-ibm: implement WriteFileByTypeFromMemory handler

This commit implements a framework for handling oem file types
received to/from host. Along with that it also implements the responder
for oem command WriteFileByTypeFromMemory and processes PELs received
from the host firmware.

Change-Id: Ice866aed0343b90769013c4be31a0c730f6e6bcd
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.cpp b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
new file mode 100644
index 0000000..400d336
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
@@ -0,0 +1,85 @@
+#include "config.h"
+
+#include "file_io_type_pel.hpp"
+
+#include "libpldmresponder/utils.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <stdint.h>
+#include <systemd/sd-bus.h>
+#include <unistd.h>
+
+#include <exception>
+#include <filesystem>
+#include <sdbusplus/server.hpp>
+#include <vector>
+#include <xyz/openbmc_project/Logging/Entry/server.hpp>
+
+#include "libpldm/base.h"
+#include "oem/ibm/libpldm/file_io.h"
+
+namespace pldm
+{
+namespace responder
+{
+
+using namespace phosphor::logging;
+
+int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
+                                uint64_t address)
+{
+    fs::create_directories(PEL_TEMP_DIR);
+
+    auto timeMs =
+        std::chrono::duration_cast<std::chrono::milliseconds>(
+            std::chrono::high_resolution_clock::now().time_since_epoch())
+            .count();
+    std::string fileName(PEL_TEMP_DIR);
+    fileName += "/pel." + std::to_string(timeMs);
+    fs::path path(std::move(fileName));
+
+    auto rc = transferFileData(path, false, offset, length, address);
+    if (rc == PLDM_SUCCESS)
+    {
+        rc = storePel(path.string());
+    }
+    fs::remove(path);
+    return rc;
+}
+
+int PelHandler::storePel(std::string&& pelFileName)
+{
+    static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
+    static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create";
+
+    static sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
+
+    try
+    {
+        auto service = getService(bus, logObjPath, logInterface);
+        using namespace sdbusplus::xyz::openbmc_project::Logging::server;
+        std::map<std::string, std::string> addlData{};
+        addlData.emplace("RAWPEL", std::move(pelFileName));
+        auto severity =
+            sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
+                sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
+                    Error);
+
+        auto method = bus.new_method_call(service.c_str(), logObjPath,
+                                          logInterface, "Create");
+        method.append("xyz.openbmc_project.Host.Error.Event", severity,
+                      addlData);
+        bus.call_noreply(method);
+    }
+    catch (const std::exception& e)
+    {
+        log<level::ERR>("failed to make a d-bus call to PEL daemon",
+                        entry("ERROR=%s", e.what()));
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+} // namespace responder
+} // namespace pldm