oem-meta: Add file IO responder for post code

Support write file request when multiple hosts send postcode to BMC
and store its post code history.

Tested: Verified in yosemite4 platform. The boot state property is
set correctly.

Change-Id: Ic4c7223b9e80f04f9c737f50b02af0d1cc119a52
Signed-off-by: Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>
Signed-off-by: Sora Su <baxiche@gmail.com>
diff --git a/oem/meta/libpldmresponder/file_io.cpp b/oem/meta/libpldmresponder/file_io.cpp
index e4800fb..3aac5a6 100644
--- a/oem/meta/libpldmresponder/file_io.cpp
+++ b/oem/meta/libpldmresponder/file_io.cpp
@@ -1,5 +1,7 @@
 #include "file_io.hpp"
 
+#include "file_io_type_post_code.hpp"
+
 #include <libpldm/oem/meta/file_io.h>
 
 #include <filesystem>
@@ -11,6 +13,8 @@
 {
     switch (fileIOType)
     {
+        case FileIOType::POST_CODE:
+            return std::make_unique<PostCodeHandler>(messageTid);
         default:
             error("Get invalid file io type {FILEIOTYPE}", "FILEIOTYPE",
                   fileIOType);
diff --git a/oem/meta/libpldmresponder/file_io_by_type.hpp b/oem/meta/libpldmresponder/file_io_by_type.hpp
index c8e7d05..af13553 100644
--- a/oem/meta/libpldmresponder/file_io_by_type.hpp
+++ b/oem/meta/libpldmresponder/file_io_by_type.hpp
@@ -12,6 +12,7 @@
 
 enum class FileIOType : uint8_t
 {
+    POST_CODE = 0x00
 };
 
 /**
diff --git a/oem/meta/libpldmresponder/file_io_type_post_code.cpp b/oem/meta/libpldmresponder/file_io_type_post_code.cpp
new file mode 100644
index 0000000..8b6d838
--- /dev/null
+++ b/oem/meta/libpldmresponder/file_io_type_post_code.cpp
@@ -0,0 +1,63 @@
+#include "file_io_type_post_code.hpp"
+
+#include "oem/meta/utils.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+#include <utility>
+
+PHOSPHOR_LOG2_USING;
+namespace pldm::responder::oem_meta
+{
+
+using postcode_t = std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>;
+
+int PostCodeHandler::write(const message& postCodeList)
+{
+    static constexpr auto dbusService = "xyz.openbmc_project.State.Boot.Raw";
+    static constexpr auto dbusObj = "/xyz/openbmc_project/state/boot/raw";
+    static constexpr auto AMD_POST_CODE_LENGTH = 4;
+
+    std::string slotNum = pldm::oem_meta::getSlotNumberStringByTID(tid);
+    std::string dbusObjStr = dbusObj + slotNum;
+
+    std::vector<uint8_t> primaryPostCode;
+
+    // Putting list of the bytes together to form a meaningful postcode
+    // AMD platform send four bytes as a post code unit
+    if (std::cmp_greater(
+            std::distance(std::begin(postCodeList), std::end(postCodeList)),
+            sizeof(AMD_POST_CODE_LENGTH)))
+    {
+        error("Get invalid post code length");
+        return PLDM_ERROR;
+    }
+
+    std::for_each(postCodeList.rbegin(), postCodeList.rend(),
+                  [&primaryPostCode](auto postcode) {
+                      primaryPostCode.push_back(postcode);
+                  });
+
+    try
+    {
+        auto& bus = pldm::utils::DBusHandler::getBus();
+        auto method =
+            bus.new_method_call(dbusService, dbusObjStr.c_str(),
+                                "org.freedesktop.DBus.Properties", "Set");
+
+        method.append(
+            dbusService, "Value",
+            std::variant<postcode_t>(postcode_t(primaryPostCode, {})));
+
+        bus.call(method);
+    }
+    catch (const std::exception& e)
+    {
+        error("Set Post code error with error code {ERROR}", "ERROR", e);
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+} // namespace pldm::responder::oem_meta
diff --git a/oem/meta/libpldmresponder/file_io_type_post_code.hpp b/oem/meta/libpldmresponder/file_io_type_post_code.hpp
new file mode 100644
index 0000000..889b19a
--- /dev/null
+++ b/oem/meta/libpldmresponder/file_io_type_post_code.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "common/utils.hpp"
+#include "file_io_by_type.hpp"
+#include "oem/meta/utils.hpp"
+
+namespace pldm::responder::oem_meta
+{
+/** @class PostCodeHandler
+ *
+ *  @brief Inherits and implements FileHandler. This class is used
+ *  to store incoming postcode
+ */
+class PostCodeHandler : public FileHandler
+{
+  public:
+    PostCodeHandler() = delete;
+    PostCodeHandler(const PostCodeHandler&) = delete;
+    PostCodeHandler(PostCodeHandler&&) = delete;
+    PostCodeHandler& operator=(const PostCodeHandler&) = delete;
+    PostCodeHandler& operator=(PostCodeHandler&&) = delete;
+
+    explicit PostCodeHandler(pldm_tid_t tid) : tid(tid) {}
+
+    ~PostCodeHandler() = default;
+
+    /** @brief Method to store postcode list
+     *  @param[in] data - post code
+     *  @return  PLDM status code
+     */
+    int write(const message& data) override;
+
+  private:
+    /** @brief The terminus ID of the message source*/
+    pldm_tid_t tid = 0;
+};
+
+} // namespace pldm::responder::oem_meta
diff --git a/oem/meta/libpldmresponder/meson.build b/oem/meta/libpldmresponder/meson.build
index 5494ada..21d84bc 100644
--- a/oem/meta/libpldmresponder/meson.build
+++ b/oem/meta/libpldmresponder/meson.build
@@ -1 +1 @@
-oem_files += files('file_io.cpp')
+oem_files += files('file_io.cpp', 'file_io_type_post_code.cpp')