oem-ibm: add readFileByTypeIntoMemory handler

Add a handler for file type 'LID', which are host firmware image files
on IBM systems. These would be read by the host firmware as it boots.

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I83e3ee398a4c6a4198a40b8b2188a3c11d0e55c4
diff --git a/meson.build b/meson.build
index 13a1899..bca95eb 100644
--- a/meson.build
+++ b/meson.build
@@ -20,6 +20,8 @@
 if get_option('oem-ibm').enabled()
   conf_data.set_quoted('FILE_TABLE_JSON', '/usr/share/pldm/fileTable.json')
   conf_data.set_quoted('PEL_TEMP_DIR', '/tmp/pel')
+  conf_data.set_quoted('LID_PERM_DIR', '/var/lib/pldm/lid')
+  conf_data.set_quoted('LID_TEMP_DIR', '/var/lib/pldm/lid/temp')
   add_global_arguments('-DOEM_IBM', language : 'c')
   add_global_arguments('-DOEM_IBM', language : 'cpp')
 endif
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index c4ab935..8d9a9a3 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -48,6 +48,8 @@
  */
 enum pldm_fileio_file_type {
 	PLDM_FILE_TYPE_PEL = 0,
+	PLDM_FILE_TYPE_LID_PERM = 1,
+	PLDM_FILE_TYPE_LID_TEMP = 2,
 };
 
 #define PLDM_RW_FILE_MEM_REQ_BYTES 20
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 692ae1b..0c7216b 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -45,6 +45,8 @@
     registerHandler(PLDM_OEM, PLDM_WRITE_FILE, std::move(writeFile));
     registerHandler(PLDM_OEM, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
                     std::move(writeFileByTypeFromMemory));
+    registerHandler(PLDM_OEM, PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
+                    std::move(readFileByTypeIntoMemory));
 }
 
 } // namespace oem_ibm
@@ -536,8 +538,8 @@
     return response;
 }
 
-Response writeFileByTypeFromMemory(const pldm_msg* request,
-                                   size_t payloadLength)
+Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
+                                size_t payloadLength)
 {
     Response response(
         sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
@@ -545,9 +547,9 @@
 
     if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
     {
-        encode_rw_file_by_type_memory_resp(
-            request->hdr.instance_id, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
-            PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
+        encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
+                                           PLDM_ERROR_INVALID_LENGTH, 0,
+                                           responsePtr);
         return response;
     }
 
@@ -561,18 +563,17 @@
                                                 &length, &address);
     if (rc != PLDM_SUCCESS)
     {
-        encode_rw_file_by_type_memory_resp(request->hdr.instance_id,
-                                           PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
-                                           rc, 0, responsePtr);
+        encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc, 0,
+                                           responsePtr);
         return response;
     }
     if (length % dma::minSize)
     {
-        log<level::ERR>("Write length is not a multiple of DMA minSize",
+        log<level::ERR>("Length is not a multiple of DMA minSize",
                         entry("LENGTH=%d", length));
-        encode_rw_file_by_type_memory_resp(
-            request->hdr.instance_id, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
-            PLDM_INVALID_WRITE_LENGTH, 0, responsePtr);
+        encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
+                                           PLDM_INVALID_WRITE_LENGTH, 0,
+                                           responsePtr);
         return response;
     }
 
@@ -584,18 +585,32 @@
     catch (const InternalFailure& e)
     {
         log<level::ERR>("unknown file type ", entry("TYPE=%d", fileType));
-        encode_rw_file_by_type_memory_resp(
-            request->hdr.instance_id, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
-            PLDM_INVALID_FILE_TYPE, 0, responsePtr);
+        encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
+                                           PLDM_INVALID_FILE_TYPE, 0,
+                                           responsePtr);
         return response;
     }
 
-    rc = handler->writeFromMemory(offset, length, address);
-    encode_rw_file_by_type_memory_resp(request->hdr.instance_id,
-                                       PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, rc,
+    rc = cmd == PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY
+             ? handler->writeFromMemory(offset, length, address)
+             : handler->readIntoMemory(offset, length, address);
+    encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc,
                                        length, responsePtr);
     return response;
 }
 
+Response writeFileByTypeFromMemory(const pldm_msg* request,
+                                   size_t payloadLength)
+{
+    return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
+                                  payloadLength);
+}
+
+Response readFileByTypeIntoMemory(const pldm_msg* request, size_t payloadLength)
+{
+    return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
+                                  payloadLength);
+}
+
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index 2086fc1..b67f0f9 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -150,6 +150,16 @@
 Response writeFileByTypeFromMemory(const pldm_msg* request,
                                    size_t payloadLength);
 
+/** @brief Handler for readFileByTypeIntoMemory command
+ *
+ *  @param[in] request - pointer to PLDM request payload
+ *  @param[in] payloadLength - length of the message
+ *
+ *  @return PLDM response message
+ */
+Response readFileByTypeIntoMemory(const pldm_msg* request,
+                                  size_t payloadLength);
+
 /** @brief Handler for GetFileTable command
  *
  *  @param[in] request - pointer to PLDM request payload
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.cpp b/oem/ibm/libpldmresponder/file_io_by_type.cpp
index d8a40a5..152efb9 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.cpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.cpp
@@ -2,6 +2,7 @@
 
 #include "file_io_by_type.hpp"
 
+#include "file_io_type_lid.hpp"
 #include "file_io_type_pel.hpp"
 #include "libpldmresponder/utils.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
@@ -31,6 +32,29 @@
                                   uint32_t offset, uint32_t length,
                                   uint64_t address)
 {
+    if (upstream)
+    {
+        if (!fs::exists(path))
+        {
+            log<level::ERR>("File does not exist",
+                            entry("PATH=%s", path.c_str()));
+            return PLDM_INVALID_FILE_HANDLE;
+        }
+
+        size_t fileSize = fs::file_size(path);
+        if (offset >= fileSize)
+        {
+            log<level::ERR>("Offset exceeds file size",
+                            entry("OFFSET=%d", offset),
+                            entry("FILE_SIZE=%d", fileSize));
+            return PLDM_DATA_OUT_OF_RANGE;
+        }
+        if (offset + length > fileSize)
+        {
+            length = fileSize - offset;
+        }
+    }
+
     dma::DMA xdmaInterface;
 
     while (length > dma::maxSize)
@@ -60,6 +84,16 @@
             return std::make_unique<PelHandler>(fileHandle);
             break;
         }
+        case PLDM_FILE_TYPE_LID_PERM:
+        {
+            return std::make_unique<LidHandler>(fileHandle, true);
+            break;
+        }
+        case PLDM_FILE_TYPE_LID_TEMP:
+        {
+            return std::make_unique<LidHandler>(fileHandle, false);
+            break;
+        }
         default:
         {
             elog<InternalFailure>();
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.hpp b/oem/ibm/libpldmresponder/file_io_by_type.hpp
index 6c31252..f39650d 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.hpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.hpp
@@ -29,6 +29,17 @@
     virtual int writeFromMemory(uint32_t offset, uint32_t length,
                                 uint64_t address) = 0;
 
+    /** @brief Method to read an oem file type into host memory. Individual
+     *  file types need to override this method to do the file specific
+     *  processing
+     *  @param[in] offset - offset to read
+     *  @param[in] length - length to be read mentioned by Host
+     *  @param[in] address - DMA address
+     *  @return PLDM status code
+     */
+    virtual int readIntoMemory(uint32_t offset, uint32_t length,
+                               uint64_t address) = 0;
+
     /** @brief Method to do the file content transfer ove DMA between host and
      *  bmc. This method is made virtual to be overridden in test case. And need
      *  not be defined in other child classes
diff --git a/oem/ibm/libpldmresponder/file_io_type_lid.hpp b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
new file mode 100644
index 0000000..45d4f73
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "config.h"
+
+#include "file_io_by_type.hpp"
+
+#include <sstream>
+#include <string>
+
+namespace pldm
+{
+namespace responder
+{
+
+using namespace pldm::responder::dma;
+
+/** @class LidHandler
+ *
+ *  @brief Inherits and implements FileHandler. This class is used
+ *  to read/write LIDs.
+ */
+class LidHandler : public FileHandler
+{
+  public:
+    /** @brief LidHandler constructor
+     */
+    LidHandler(uint32_t fileHandle, bool permSide) : FileHandler(fileHandle)
+    {
+        std::string dir = permSide ? LID_PERM_DIR : LID_TEMP_DIR;
+        std::stringstream stream;
+        stream << std::hex << fileHandle;
+        lidPath = std::move(dir) + '/' + stream.str() + ".lid";
+    }
+
+    virtual int writeFromMemory(uint32_t /*offset*/, uint32_t /*length*/,
+                                uint64_t /*address*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
+    virtual int readIntoMemory(uint32_t offset, uint32_t length,
+                               uint64_t address)
+    {
+        return transferFileData(lidPath, true, offset, length, address);
+    }
+
+    /** @brief LidHandler destructor
+     */
+    ~LidHandler()
+    {
+    }
+
+  protected:
+    std::string lidPath;
+};
+
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.cpp b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
index 400d336..014511c 100644
--- a/oem/ibm/libpldmresponder/file_io_type_pel.cpp
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
@@ -25,6 +25,12 @@
 
 using namespace phosphor::logging;
 
+int PelHandler::readIntoMemory(uint32_t /*offset*/, uint32_t /*length*/,
+                               uint64_t /*address*/)
+{
+    return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+}
+
 int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
                                 uint64_t address)
 {
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.hpp b/oem/ibm/libpldmresponder/file_io_type_pel.hpp
index 92bcbf6..4c79452 100644
--- a/oem/ibm/libpldmresponder/file_io_type_pel.hpp
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.hpp
@@ -25,6 +25,8 @@
 
     virtual int writeFromMemory(uint32_t offset, uint32_t length,
                                 uint64_t address);
+    virtual int readIntoMemory(uint32_t offset, uint32_t length,
+                               uint64_t address);
 
     /** @brief method to store a pel file in tempfs and send
      *  d-bus notification to pel daemon that it is ready for consumption