Sync ibm-pldm-oem repository changes to pldm repository
Change-Id: I6f30b39f483647ad84fe2fbe1c24298841040801
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/.gitignore b/.gitignore
index 26a8d6d..f13de14 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,10 @@
/test/libpldmresponder_base_test
/test/libpldm_bios_test
/test/libpldmresponder_bios_formatTime_test
+/test/libpldm_platform_test
+/test/libpldmoem_fileio_test
+/test/libpldmoemresponder_fileio_test
+/test/libpldmresponder_bios_test
+/test/libpldmresponder_file_io_test
+/test/libpldmresponder_pdr_state_effecter_test
+
diff --git a/configure.ac b/configure.ac
index 3ffeca4..e06f062 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,6 +77,7 @@
AS_IF([test "x$enable_oem_ibm" == "xyes"], [
AX_APPEND_COMPILE_FLAGS([-DOEM_IBM], [CXXFLAGS])
AX_APPEND_COMPILE_FLAGS([-DOEM_IBM], [CFLAGS])
+ AC_DEFINE(FILE_TABLE_JSON, "/var/lib/pldm/fileTable.json", [JSON file containing file info for File I/O])
])
# Setup verbose option
diff --git a/libpldm/pldm_types.h b/libpldm/pldm_types.h
index 3470413..093d016 100644
--- a/libpldm/pldm_types.h
+++ b/libpldm/pldm_types.h
@@ -30,4 +30,42 @@
typedef uint8_t bool8_t;
+typedef union {
+ uint32_t value;
+ struct {
+ uint8_t bit0 : 1;
+ uint8_t bit1 : 1;
+ uint8_t bit2 : 1;
+ uint8_t bit3 : 1;
+ uint8_t bit4 : 1;
+ uint8_t bit5 : 1;
+ uint8_t bit6 : 1;
+ uint8_t bit7 : 1;
+ uint8_t bit8 : 1;
+ uint8_t bit9 : 1;
+ uint8_t bit10 : 1;
+ uint8_t bit11 : 1;
+ uint8_t bit12 : 1;
+ uint8_t bit13 : 1;
+ uint8_t bit14 : 1;
+ uint8_t bit15 : 1;
+ uint8_t bit16 : 1;
+ uint8_t bit17 : 1;
+ uint8_t bit18 : 1;
+ uint8_t bit19 : 1;
+ uint8_t bit20 : 1;
+ uint8_t bit21 : 1;
+ uint8_t bit22 : 1;
+ uint8_t bit23 : 1;
+ uint8_t bit24 : 1;
+ uint8_t bit25 : 1;
+ uint8_t bit26 : 1;
+ uint8_t bit27 : 1;
+ uint8_t bit28 : 1;
+ uint8_t bit29 : 1;
+ uint8_t bit30 : 1;
+ uint8_t bit31 : 1;
+ } __attribute__((packed)) bits;
+} bitfield32_t;
+
#endif /* PLDM_TYPES_H */
diff --git a/libpldmresponder/Makefile.am b/libpldmresponder/Makefile.am
index 0bd1ea5..c40b749 100644
--- a/libpldmresponder/Makefile.am
+++ b/libpldmresponder/Makefile.am
@@ -23,12 +23,13 @@
libpldmresponder_la_CPPFLAGS = \
$(CODE_COVERAGE_CPPFLAGS) \
- -I$(top_builddir)/libpldm/ \
+ -I$(top_builddir)/libpldm/ \
-I$(top_srcdir)
if OEM_IBM
libpldmresponder_la_SOURCES += \
- $(top_builddir)/oem/ibm/libpldmresponder/file_io.cpp
+ $(top_builddir)/oem/ibm/libpldmresponder/file_io.cpp \
+ $(top_builddir)/oem/ibm/libpldmresponder/file_table.cpp
libpldmresponder_la_CPPFLAGS += \
-I$(top_builddir)/oem/ibm/
endif
diff --git a/oem/ibm/libpldm/file_io.c b/oem/ibm/libpldm/file_io.c
index 2fa3034..a415414 100644
--- a/oem/ibm/libpldm/file_io.c
+++ b/oem/ibm/libpldm/file_io.c
@@ -52,3 +52,56 @@
return PLDM_SUCCESS;
}
+
+int decode_get_file_table_req(const uint8_t *msg, size_t payload_length,
+ uint32_t *transfer_handle,
+ uint8_t *transfer_opflag, uint8_t *table_type)
+{
+ if (msg == NULL || transfer_handle == NULL || transfer_opflag == NULL ||
+ table_type == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_FILE_TABLE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_file_table_req *request =
+ (struct pldm_get_file_table_req *)msg;
+
+ *transfer_handle = le32toh(request->transfer_handle);
+ *transfer_opflag = request->operation_flag;
+ *table_type = request->table_type;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_file_table_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t next_transfer_handle,
+ uint8_t transfer_flag, const uint8_t *table_data,
+ size_t table_size, struct pldm_msg *msg)
+{
+ struct pldm_header_info header = {0};
+ int rc = PLDM_SUCCESS;
+
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = PLDM_GET_FILE_TABLE;
+
+ if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_get_file_table_resp *response =
+ (struct pldm_get_file_table_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ if (completion_code == PLDM_SUCCESS) {
+ response->next_transfer_handle = htole32(next_transfer_handle);
+ response->transfer_flag = transfer_flag;
+ memcpy(response->table_data, table_data, table_size);
+ }
+
+ return PLDM_SUCCESS;
+}
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index 79a8035..eb23332 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -13,6 +13,7 @@
/** @brief PLDM Commands in IBM OEM type
*/
enum pldm_fileio_commands {
+ PLDM_GET_FILE_TABLE = 0x1,
PLDM_READ_FILE_INTO_MEMORY = 0x6,
PLDM_WRITE_FILE_FROM_MEMORY = 0x7,
};
@@ -24,10 +25,21 @@
PLDM_DATA_OUT_OF_RANGE = 0x81,
PLDM_INVALID_READ_LENGTH = 0x82,
PLDM_INVALID_WRITE_LENGTH = 0x83,
+ PLDM_FILE_TABLE_UNAVAILABLE = 0x84,
+ PLDM_INVALID_FILE_TABLE_TYPE = 0x85,
+};
+
+/** @brief PLDM File I/O table types
+ */
+enum pldm_fileio_table_type {
+ PLDM_FILE_ATTRIBUTE_TABLE = 0,
+ PLDM_OEM_FILE_ATTRIBUTE_TABLE = 1,
};
#define PLDM_RW_FILE_MEM_REQ_BYTES 20
#define PLDM_RW_FILE_MEM_RESP_BYTES 5
+#define PLDM_GET_FILE_TABLE_REQ_BYTES 6
+#define PLDM_GET_FILE_TABLE_MIN_RESP_BYTES 6
/** @brief Decode ReadFileIntoMemory and WriteFileFromMemory commands request
* data
@@ -61,6 +73,58 @@
uint8_t completion_code, uint32_t length,
struct pldm_msg *msg);
+/** @struct pldm_get_file_table_req
+ *
+ * Structure representing GetFileTable request
+ */
+struct pldm_get_file_table_req {
+ uint32_t transfer_handle; //!< Data transfer handle
+ uint8_t operation_flag; //!< Transfer operation flag
+ uint8_t table_type; //!< Table type
+} __attribute__((packed));
+
+/** @struct pldm_get_file_table_resp
+ *
+ * Structure representing GetFileTable response fixed data
+ */
+struct pldm_get_file_table_resp {
+ uint8_t completion_code; //!< Completion code
+ uint32_t next_transfer_handle; //!< Next data transfer handle
+ uint8_t transfer_flag; //!< Transfer flag
+ uint8_t table_data[1]; //!< Table Data
+} __attribute__((packed));
+
+/** @brief Decode GetFileTable command request data
+ *
+ * @param[in] msg - Pointer to PLDM request message payload
+ * @param[in] payload_length - Length of request payload
+ * @param[out] trasnfer_handle - the handle of data
+ * @param[out] transfer_opflag - Transfer operation flag
+ * @param[out] table_type - the type of file table
+ * @return pldm_completion_codes
+ */
+int decode_get_file_table_req(const uint8_t *msg, size_t payload_length,
+ uint32_t *transfer_handle,
+ uint8_t *transfer_opflag, uint8_t *table_type);
+
+/** @brief Create a PLDM response for GetFileTable command
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - Handle to identify next portion of
+ * data transfer
+ * @param[in] transfer_flag - Represents the part of transfer
+ * @param[in] table_data - pointer to file table data
+ * @param[in] table_size - file table size
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param 'msg'
+ */
+int encode_get_file_table_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t next_transfer_handle,
+ uint8_t transfer_flag, const uint8_t *table_data,
+ size_t table_size, struct pldm_msg *msg);
+
#ifdef __cplusplus
}
#endif
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 2fec526..6b893ed 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -1,5 +1,8 @@
+#include "config.h"
+
#include "file_io.hpp"
+#include "file_table.hpp"
#include "libpldmresponder/utils.hpp"
#include "registration.hpp"
@@ -26,6 +29,7 @@
void registerHandlers()
{
+ registerHandler(PLDM_OEM, PLDM_GET_FILE_TABLE, std::move(getFileTable));
registerHandler(PLDM_OEM, PLDM_READ_FILE_INTO_MEMORY,
std::move(readFileIntoMemory));
registerHandler(PLDM_OEM, PLDM_WRITE_FILE_FROM_MEMORY,
@@ -98,10 +102,17 @@
if (upstream)
{
- std::ifstream stream(path.string());
-
+ std::ifstream stream(path.string(), std::ios::in | std::ios::binary);
stream.seekg(offset);
- stream.read(static_cast<char*>(vgaMemPtr.get()), length);
+
+ // Writing to the VGA memory should be aligned at page boundary,
+ // otherwise write data into a buffer aligned at page boundary and
+ // then write to the VGA memory.
+ std::vector<char> buffer{};
+ buffer.resize(pageAlignedLength);
+ stream.read(buffer.data(), length);
+ memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
+ pageAlignedLength);
if (static_cast<uint32_t>(stream.gcount()) != length)
{
@@ -131,7 +142,8 @@
if (!upstream)
{
- std::ofstream stream(path.string());
+ std::ofstream stream(path.string(),
+ std::ios::in | std::ios::out | std::ios::binary);
stream.seekp(offset);
stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
@@ -148,7 +160,6 @@
uint32_t offset = 0;
uint32_t length = 0;
uint64_t address = 0;
- fs::path path("");
Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -163,7 +174,24 @@
decode_rw_file_memory_req(request->payload, payloadLength, &fileHandle,
&offset, &length, &address);
- if (!fs::exists(path))
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(FILE_TABLE_JSON);
+ FileEntry value{};
+
+ try
+ {
+ value = table.at(fileHandle);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("File handle does not exist in the file table",
+ entry("HANDLE=%d", fileHandle));
+ encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+ PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
+ return response;
+ }
+
+ if (!fs::exists(value.fsPath))
{
log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
@@ -171,7 +199,7 @@
return response;
}
- auto fileSize = fs::file_size(path);
+ auto fileSize = fs::file_size(value.fsPath);
if (offset >= fileSize)
{
log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
@@ -197,8 +225,8 @@
using namespace dma;
DMA intf;
- return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, path, offset,
- length, address, true);
+ return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
+ offset, length, address, true);
}
Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength)
@@ -207,7 +235,6 @@
uint32_t offset = 0;
uint32_t length = 0;
uint64_t address = 0;
- fs::path path("");
Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -231,7 +258,24 @@
return response;
}
- if (!fs::exists(path))
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(FILE_TABLE_JSON);
+ FileEntry value{};
+
+ try
+ {
+ value = table.at(fileHandle);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("File handle does not exist in the file table",
+ entry("HANDLE=%d", fileHandle));
+ encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+ PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
+ return response;
+ }
+
+ if (!fs::exists(value.fsPath))
{
log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
@@ -239,7 +283,7 @@
return response;
}
- auto fileSize = fs::file_size(path);
+ auto fileSize = fs::file_size(value.fsPath);
if (offset >= fileSize)
{
log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
@@ -251,8 +295,59 @@
using namespace dma;
DMA intf;
- return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, path, offset,
- length, address, false);
+ return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
+ offset, length, address, false);
+}
+
+Response getFileTable(const pldm_msg* request, size_t payloadLength)
+{
+ uint32_t transferHandle = 0;
+ uint8_t transferFlag = 0;
+ uint8_t tableType = 0;
+
+ Response response(sizeof(pldm_msg_hdr) +
+ PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
+ {
+ encode_get_file_table_resp(0, PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
+ 0, responsePtr);
+ return response;
+ }
+
+ auto rc =
+ decode_get_file_table_req(request->payload, payloadLength,
+ &transferHandle, &transferFlag, &tableType);
+ if (rc)
+ {
+ encode_get_file_table_resp(0, rc, 0, 0, nullptr, 0, responsePtr);
+ return response;
+ }
+
+ if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
+ {
+ encode_get_file_table_resp(0, PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
+ nullptr, 0, responsePtr);
+ return response;
+ }
+
+ using namespace pldm::filetable;
+ auto table = buildFileTable(FILE_TABLE_JSON);
+ auto attrTable = table();
+ response.resize(response.size() + attrTable.size());
+ responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ if (attrTable.empty())
+ {
+ encode_get_file_table_resp(0, PLDM_FILE_TABLE_UNAVAILABLE, 0, 0,
+ nullptr, 0, responsePtr);
+ return response;
+ }
+
+ encode_get_file_table_resp(0, PLDM_SUCCESS, 0, PLDM_START_AND_END,
+ attrTable.data(), attrTable.size(), responsePtr);
+ return response;
}
} // namespace responder
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index 9f01782..106e2b2 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -134,5 +134,14 @@
* @return PLDM response message
*/
Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
+
+/** @brief Handler for GetFileTable command
+ *
+ * @param[in] request - pointer to PLDM request payload
+ * @param[in] payloadLength - length of the message payload
+ *
+ * @return PLDM response message
+ */
+Response getFileTable(const pldm_msg* request, size_t payloadLength);
} // namespace responder
} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_table.cpp b/oem/ibm/libpldmresponder/file_table.cpp
new file mode 100644
index 0000000..9264f21
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_table.cpp
@@ -0,0 +1,129 @@
+#include "file_table.hpp"
+
+#include <boost/crc.hpp>
+#include <fstream>
+#include <phosphor-logging/log.hpp>
+
+namespace pldm
+{
+
+namespace filetable
+{
+
+using namespace phosphor::logging;
+
+FileTable::FileTable(const std::string& fileTableConfigPath)
+{
+ std::ifstream jsonFile(fileTableConfigPath);
+ if (!jsonFile.is_open())
+ {
+ log<level::ERR>("File table config file does not exist",
+ entry("FILE=%s", fileTableConfigPath.c_str()));
+ return;
+ }
+
+ auto data = Json::parse(jsonFile, nullptr, false);
+ if (data.is_discarded())
+ {
+ log<level::ERR>("Parsing config file failed");
+ return;
+ }
+
+ uint16_t fileNameLength = 0;
+ uint32_t fileSize = 0;
+ uint32_t traits = 0;
+ size_t tableSize = 0;
+ Handle handle = 0;
+ auto iter = fileTable.begin();
+
+ // Iterate through each JSON object in the config file
+ for (const auto& record : data)
+ {
+ constexpr auto path = "path";
+ constexpr auto fileTraits = "file_traits";
+
+ std::string filepath = record.value(path, "");
+ traits = static_cast<uint32_t>(record.value(fileTraits, 0));
+
+ fs::path fsPath(filepath);
+ if (!fs::is_regular_file(fsPath))
+ {
+ continue;
+ }
+
+ fileNameLength =
+ static_cast<uint16_t>(fsPath.filename().string().size());
+ fileSize = static_cast<uint32_t>(fs::file_size(fsPath));
+ tableSize = fileTable.size();
+
+ fileTable.resize(tableSize + sizeof(handle) + sizeof(fileNameLength) +
+ fileNameLength + sizeof(fileSize) + sizeof(traits));
+ iter = fileTable.begin() + tableSize;
+
+ // Populate the file table with the contents of the JSON entry
+ std::copy_n(reinterpret_cast<uint8_t*>(&handle), sizeof(handle), iter);
+ std::advance(iter, sizeof(handle));
+
+ std::copy_n(reinterpret_cast<uint8_t*>(&fileNameLength),
+ sizeof(fileNameLength), iter);
+ std::advance(iter, sizeof(fileNameLength));
+
+ std::copy_n(reinterpret_cast<const uint8_t*>(fsPath.filename().c_str()),
+ fileNameLength, iter);
+ std::advance(iter, fileNameLength);
+
+ std::copy_n(reinterpret_cast<uint8_t*>(&fileSize), sizeof(fileSize),
+ iter);
+ std::advance(iter, sizeof(fileSize));
+
+ std::copy_n(reinterpret_cast<uint8_t*>(&traits), sizeof(traits), iter);
+ std::advance(iter, sizeof(traits));
+
+ // Create the file entry for the JSON entry
+ FileEntry entry{};
+ entry.handle = handle;
+ entry.fsPath = std::move(fsPath);
+ entry.traits.value = traits;
+
+ // Insert the file entries in the map
+ tableEntries.emplace(handle, std::move(entry));
+ handle++;
+ }
+
+ constexpr uint8_t padWidth = 4;
+ tableSize = fileTable.size();
+ // Add pad bytes
+ if ((tableSize % padWidth) != 0)
+ {
+ padCount = padWidth - (tableSize % padWidth);
+ fileTable.resize(tableSize + padCount, 0);
+ }
+
+ // Calculate the checksum
+ boost::crc_32_type result;
+ result.process_bytes(fileTable.data(), fileTable.size());
+ checkSum = result.checksum();
+}
+
+Table FileTable::operator()() const
+{
+ Table table(fileTable);
+ table.resize(fileTable.size() + sizeof(checkSum));
+ auto iter = table.begin() + fileTable.size();
+ std::copy_n(reinterpret_cast<const uint8_t*>(&checkSum), sizeof(checkSum),
+ iter);
+ return table;
+}
+
+FileTable& buildFileTable(const std::string& fileTablePath)
+{
+ static FileTable table;
+ if (table.isEmpty())
+ {
+ table = std::move(FileTable(fileTablePath));
+ }
+ return table;
+}
+
+} // namespace filetable
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_table.hpp b/oem/ibm/libpldmresponder/file_table.hpp
new file mode 100644
index 0000000..4b82f29
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_table.hpp
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <filesystem>
+#include <nlohmann/json.hpp>
+#include <vector>
+
+#include "libpldm/pldm_types.h"
+
+namespace pldm
+{
+
+namespace filetable
+{
+
+namespace fs = std::filesystem;
+using Handle = uint32_t;
+using Json = nlohmann::json;
+using Table = std::vector<uint8_t>;
+
+/** @struct FileEntry
+ *
+ * Data structure for storing information regarding the files supported by
+ * PLDM File I/O. The file handle is used to uniquely identify the file. The
+ * traits provide information whether the file is Read only, Read/Write and
+ * preserved across firmware upgrades.
+ */
+struct FileEntry
+{
+ Handle handle; //!< File handle
+ fs::path fsPath; //!< File path
+ bitfield32_t traits; //!< File traits
+};
+
+/** @class FileTable
+ *
+ * FileTable class encapsulates the data related to files supported by PLDM
+ * File I/O and provides interfaces to lookup files information based on the
+ * file handle and extract the file attribute table. The file attribute table
+ * comprises of metadata for files. Metadata includes the file handle, file
+ * name, current file size and file traits.
+ */
+class FileTable
+{
+ public:
+ /** @brief The file table is initialised by parsing the config file
+ * containing information about the files.
+ *
+ * @param[in] fileTableConfigPath - path to the json file containing
+ * information
+ */
+ FileTable(const std::string& fileTableConfigPath);
+ FileTable() = default;
+ ~FileTable() = default;
+ FileTable(const FileTable&) = default;
+ FileTable& operator=(const FileTable&) = default;
+ FileTable(FileTable&&) = default;
+ FileTable& operator=(FileTable&&) = default;
+
+ /** @brief Get the file attribute table
+ *
+ * @return Table- contents of the file attribute table
+ */
+ Table operator()() const;
+
+ /** @brief Get the FileEntry at the file handle
+ *
+ * @param[in] handle - file handle
+ *
+ * @return FileEntry - file entry at the handle
+ */
+ FileEntry at(Handle handle) const
+ {
+ return tableEntries.at(handle);
+ }
+
+ /** @brief Check is file attribute table is empty
+ *
+ * @return bool - true if file attribute table is empty, false otherwise.
+ */
+ bool isEmpty() const
+ {
+ return fileTable.empty();
+ }
+
+ /** @brief Clear the file table contents
+ *
+ */
+ void clear()
+ {
+ tableEntries.clear();
+ fileTable.clear();
+ padCount = 0;
+ checkSum = 0;
+ }
+
+ private:
+ /** @brief handle to FileEntry mappings for lookups based on file handle */
+ std::unordered_map<Handle, FileEntry> tableEntries;
+
+ /** @brief file attribute table including the pad bytes, except the checksum
+ */
+ std::vector<uint8_t> fileTable;
+
+ /** @brief the pad count of the file attribute table, the number of pad
+ * bytes is between 0 and 3 */
+ uint8_t padCount = 0;
+
+ /** @brief the checksum of the file attribute table */
+ uint32_t checkSum = 0;
+};
+
+/** @brief Build the file attribute table if not already built using the
+ * file table config.
+ *
+ * @param[in] fileTablePath - path of the file table config
+ *
+ * @return FileTable& - Reference to instance of file table
+ */
+
+FileTable& buildFileTable(const std::string& fileTablePath);
+
+} // namespace filetable
+} // namespace pldm
diff --git a/oem/ibm/test/libpldm_fileio_test.cpp b/oem/ibm/test/libpldm_fileio_test.cpp
index e9fa325..2a96742 100644
--- a/oem/ibm/test/libpldm_fileio_test.cpp
+++ b/oem/ibm/test/libpldm_fileio_test.cpp
@@ -130,3 +130,120 @@
ASSERT_EQ(response->hdr.command, PLDM_WRITE_FILE_FROM_MEMORY);
ASSERT_EQ(response->payload[0], PLDM_ERROR);
}
+
+TEST(GetFileTable, GoodDecodeRequest)
+{
+ std::array<uint8_t, PLDM_GET_FILE_TABLE_REQ_BYTES> requestMsg{};
+
+ // Random value for DataTransferHandle, TransferOperationFlag, TableType
+ uint32_t transferHandle = 0x12345678;
+ uint8_t transferOpFlag = 1;
+ uint8_t tableType = 1;
+
+ memcpy(requestMsg.data(), &transferHandle, sizeof(transferHandle));
+ memcpy(requestMsg.data() + sizeof(transferHandle), &transferOpFlag,
+ sizeof(transferOpFlag));
+ memcpy(requestMsg.data() + sizeof(transferHandle) + sizeof(transferOpFlag),
+ &tableType, sizeof(tableType));
+
+ uint32_t retTransferHandle = 0;
+ uint8_t retTransferOpFlag = 0;
+ uint8_t retTableType = 0;
+
+ // Invoke decode get file table request
+ auto rc = decode_get_file_table_req(requestMsg.data(), requestMsg.size(),
+ &retTransferHandle, &retTransferOpFlag,
+ &retTableType);
+
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+ ASSERT_EQ(transferHandle, retTransferHandle);
+ ASSERT_EQ(transferOpFlag, retTransferOpFlag);
+ ASSERT_EQ(tableType, retTableType);
+}
+
+TEST(GetFileTable, BadDecodeRequest)
+{
+ uint32_t transferHandle = 0;
+ uint8_t transferOpFlag = 0;
+ uint8_t tableType = 0;
+
+ // Request payload message is missing
+ auto rc = decode_get_file_table_req(nullptr, 0, &transferHandle,
+ &transferOpFlag, &tableType);
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ std::array<uint8_t, PLDM_GET_FILE_TABLE_REQ_BYTES> requestMsg{};
+
+ // TableType is NULL
+ rc = decode_get_file_table_req(requestMsg.data(), requestMsg.size(),
+ &transferHandle, &transferOpFlag, nullptr);
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Payload length is invalid
+ rc = decode_get_file_table_req(requestMsg.data(), 0, &transferHandle,
+ &transferOpFlag, &tableType);
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetFileTable, GoodEncodeResponse)
+{
+ // Random value for NextDataTransferHandle and TransferFlag
+ uint8_t completionCode = 0;
+ uint32_t nextTransferHandle = 0x87654321;
+ uint8_t transferFlag = 5;
+ // Mock file table contents of size 5
+ std::array<uint8_t, 5> fileTable = {1, 2, 3, 4, 5};
+ constexpr size_t responseSize = sizeof(completionCode) +
+ sizeof(nextTransferHandle) +
+ sizeof(transferFlag) + fileTable.size();
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + responseSize> responseMsg{};
+ pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ // GetFileTable
+ auto rc = encode_get_file_table_resp(0, PLDM_SUCCESS, nextTransferHandle,
+ transferFlag, fileTable.data(),
+ fileTable.size(), response);
+
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+ ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
+ ASSERT_EQ(response->hdr.instance_id, 0);
+ ASSERT_EQ(response->hdr.type, PLDM_OEM);
+ ASSERT_EQ(response->hdr.command, PLDM_GET_FILE_TABLE);
+ ASSERT_EQ(response->payload[0], PLDM_SUCCESS);
+ ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
+ &nextTransferHandle, sizeof(nextTransferHandle)));
+ ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+ sizeof(nextTransferHandle),
+ &transferFlag, sizeof(transferFlag)));
+ ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+ sizeof(nextTransferHandle),
+ &transferFlag, sizeof(transferFlag)));
+ ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+ sizeof(nextTransferHandle) + sizeof(transferFlag),
+ fileTable.data(), fileTable.size()));
+}
+
+TEST(GetFileTable, BadEncodeResponse)
+{
+ uint8_t completionCode = 0;
+ uint32_t nextTransferHandle = 0;
+ uint8_t transferFlag = 0;
+ constexpr size_t responseSize = sizeof(completionCode) +
+ sizeof(nextTransferHandle) +
+ sizeof(transferFlag);
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + responseSize> responseMsg{};
+ pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ // GetFileTable
+ auto rc = encode_get_file_table_resp(0, PLDM_ERROR, nextTransferHandle,
+ transferFlag, nullptr, 0, response);
+
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+ ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
+ ASSERT_EQ(response->hdr.instance_id, 0);
+ ASSERT_EQ(response->hdr.type, PLDM_OEM);
+ ASSERT_EQ(response->hdr.command, PLDM_GET_FILE_TABLE);
+ ASSERT_EQ(response->payload[0], PLDM_ERROR);
+}
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index 1338713..7c0c129 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -1,4 +1,9 @@
#include "libpldmresponder/file_io.hpp"
+#include "libpldmresponder/file_table.hpp"
+
+#include <filesystem>
+#include <fstream>
+#include <nlohmann/json.hpp>
#include "libpldm/base.h"
#include "libpldm/file_io.h"
@@ -6,6 +11,7 @@
#include <gmock/gmock-matchers.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+
#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal.h>
@@ -28,6 +34,72 @@
}
}
+namespace fs = std::filesystem;
+using Json = nlohmann::json;
+using namespace pldm::filetable;
+
+class TestFileTable : public testing::Test
+{
+ public:
+ void SetUp() override
+ {
+ // Create a temporary directory to hold the config file and files to
+ // populate the file table.
+ char tmppldm[] = "/tmp/pldm_fileio_table.XXXXXX";
+ dir = fs::path(mkdtemp(tmppldm));
+
+ // Copy the sample image files to the directory
+ fs::copy("./files", dir);
+
+ imageFile = dir / "NVRAM-IMAGE";
+ auto jsonObjects = Json::array();
+ auto obj = Json::object();
+ obj["path"] = imageFile.c_str();
+ obj["file_traits"] = 1;
+
+ jsonObjects.push_back(obj);
+ obj.clear();
+ cksumFile = dir / "NVRAM-IMAGE-CKSUM";
+ obj["path"] = cksumFile.c_str();
+ obj["file_traits"] = 4;
+ jsonObjects.push_back(obj);
+
+ fileTableConfig = dir / "configFile.json";
+ std::ofstream file(fileTableConfig.c_str());
+ file << std::setw(4) << jsonObjects << std::endl;
+ }
+
+ void TearDown() override
+ {
+ fs::remove_all(dir);
+ }
+
+ fs::path dir;
+ fs::path imageFile;
+ fs::path cksumFile;
+ fs::path fileTableConfig;
+
+ // <4 bytes - File handle - 0 (0x00 0x00 0x00 0x00)>,
+ // <2 bytes - Filename length - 11 (0x0b 0x00>
+ // <11 bytes - Filename - ASCII for NVRAM-IMAGE>
+ // <4 bytes - File size - 1024 (0x00 0x04 0x00 0x00)>
+ // <4 bytes - File traits - 1 (0x01 0x00 0x00 0x00)>
+ // <4 bytes - File handle - 1 (0x01 0x00 0x00 0x00)>,
+ // <2 bytes - Filename length - 17 (0x11 0x00>
+ // <17 bytes - Filename - ASCII for NVRAM-IMAGE-CKSUM>
+ // <4 bytes - File size - 16 (0x0f 0x00 0x00 0x00)>
+ // <4 bytes - File traits - 4 (0x04 0x00 0x00 0x00)>
+ // No pad bytes added since the length for both the file entries in the
+ // table is 56, which is a multiple of 4.
+ // <4 bytes - Checksum - 2088303182(0x4e 0xfa 0x78 0x7c)>
+ Table attrTable = {
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d, 0x2d,
+ 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d,
+ 0x2d, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x2d, 0x43, 0x4b, 0x53, 0x55, 0x4d,
+ 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0xfa, 0x78, 0x7c};
+};
+
namespace pldm
{
@@ -163,6 +235,130 @@
ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
}
+TEST_F(TestFileTable, ReadFileInvalidFileHandle)
+{
+ // Invalid file handle in the file table
+ uint32_t fileHandle = 2;
+ uint32_t offset = 0;
+ uint32_t length = 0;
+ uint64_t address = 0;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+ memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ // Initialise the file table with 2 valid file handles 0 & 1.
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileInvalidOffset)
+{
+ uint32_t fileHandle = 0;
+ // The file size is 1024, so the offset is invalid
+ uint32_t offset = 1024;
+ uint32_t length = 0;
+ uint64_t address = 0;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+ memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileInvalidLength)
+{
+ uint32_t fileHandle = 0;
+ uint32_t offset = 100;
+ // Length should be a multiple of dma min size(16)
+ uint32_t length = 10;
+ uint64_t address = 0;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+ memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileInvalidEffectiveLength)
+{
+ uint32_t fileHandle = 0;
+ // valid offset
+ uint32_t offset = 100;
+ // length + offset exceeds the size, so effective length is
+ // filesize(1024) - offset(100). The effective length is not a multiple of
+ // DMA min size(16)
+ uint32_t length = 1024;
+ uint64_t address = 0;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+ memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
+ // Clear the file table contents.
+ table.clear();
+}
+
TEST(WriteFileFromMemory, BadPath)
{
uint32_t fileHandle = 0;
@@ -192,3 +388,175 @@
responsePtr = reinterpret_cast<pldm_msg*>(response.data());
ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
}
+
+TEST_F(TestFileTable, WriteFileInvalidFileHandle)
+{
+ // Invalid file handle in the file table
+ uint32_t fileHandle = 2;
+ uint32_t offset = 0;
+ uint32_t length = 16;
+ uint64_t address = 0;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+ memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ // Initialise the file table with 2 valid file handles 0 & 1.
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = writeFileFromMemory(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, WriteFileInvalidOffset)
+{
+ uint32_t fileHandle = 0;
+ // The file size is 1024, so the offset is invalid
+ uint32_t offset = 1024;
+ uint32_t length = 16;
+ uint64_t address = 0;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+ memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ // Initialise the file table with 2 valid file handles 0 & 1.
+ auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str());
+
+ auto response = writeFileFromMemory(request, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST(FileTable, ConfigNotExist)
+{
+ logs.clear();
+ FileTable tableObj("");
+ EXPECT_EQ(logs.size(), 1);
+}
+
+TEST_F(TestFileTable, ValidateFileEntry)
+{
+ FileTable tableObj(fileTableConfig.c_str());
+
+ // Test file handle 0, the file size is 1K bytes.
+ auto value = tableObj.at(0);
+ ASSERT_EQ(value.handle, 0);
+ ASSERT_EQ(strcmp(value.fsPath.c_str(), imageFile.c_str()), 0);
+ ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value.fsPath)), 1024);
+ ASSERT_EQ(value.traits.value, 1);
+ ASSERT_EQ(true, fs::exists(value.fsPath));
+
+ // Test file handle 1, the file size is 16 bytes
+ auto value1 = tableObj.at(1);
+ ASSERT_EQ(value1.handle, 1);
+ ASSERT_EQ(strcmp(value1.fsPath.c_str(), cksumFile.c_str()), 0);
+ ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value1.fsPath)), 16);
+ ASSERT_EQ(value1.traits.value, 4);
+ ASSERT_EQ(true, fs::exists(value1.fsPath));
+
+ // Test invalid file handle
+ ASSERT_THROW(tableObj.at(2), std::out_of_range);
+}
+
+TEST_F(TestFileTable, ValidateFileTable)
+{
+ FileTable tableObj(fileTableConfig.c_str());
+
+ // Validate file attribute table
+ auto table = tableObj();
+ ASSERT_EQ(true,
+ std::equal(attrTable.begin(), attrTable.end(), table.begin()));
+}
+
+TEST_F(TestFileTable, GetFileTableCommand)
+{
+ // Initialise the file table with a valid handle of 0 & 1
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ uint32_t transferHandle = 0;
+ uint8_t opFlag = 0;
+ uint8_t type = PLDM_FILE_ATTRIBUTE_TABLE;
+ uint32_t nextTransferHandle = 0;
+ uint8_t transferFlag = PLDM_START_AND_END;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES>
+ requestMsg{};
+ auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ auto request = reinterpret_cast<pldm_get_file_table_req*>(
+ requestMsg.data() + sizeof(pldm_msg_hdr));
+ request->transfer_handle = transferHandle;
+ request->operation_flag = opFlag;
+ request->table_type = type;
+
+ auto response = getFileTable(requestMsgPtr, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
+ size_t offsetSize = sizeof(responsePtr->payload[0]);
+ ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &nextTransferHandle,
+ sizeof(nextTransferHandle)));
+ offsetSize += sizeof(nextTransferHandle);
+ ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &transferFlag,
+ sizeof(transferFlag)));
+ offsetSize += sizeof(transferFlag);
+ ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, attrTable.data(),
+ attrTable.size()));
+ table.clear();
+}
+
+TEST_F(TestFileTable, GetFileTableCommandReqLengthMismatch)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ // Pass invalid command payload length
+ auto response = getFileTable(request, 0);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST_F(TestFileTable, GetFileTableCommandOEMAttrTable)
+{
+ uint32_t transferHandle = 0;
+ uint8_t opFlag = 0;
+ uint8_t type = PLDM_OEM_FILE_ATTRIBUTE_TABLE;
+
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES>
+ requestMsg{};
+ auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+ auto request = reinterpret_cast<pldm_get_file_table_req*>(
+ requestMsg.data() + sizeof(pldm_msg_hdr));
+ request->transfer_handle = transferHandle;
+ request->operation_flag = opFlag;
+ request->table_type = type;
+
+ auto response = getFileTable(requestMsgPtr, requestPayloadLength);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE);
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index d580416..fef5f96 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -113,7 +113,8 @@
$(top_builddir)/pldmd-registration.o \
$(top_builddir)/libpldm/libpldm_la-base.o \
$(top_builddir)/oem/ibm/libpldm/libpldm_la-file_io.o \
- $(top_builddir)/oem/ibm/libpldmresponder/libpldmresponder_la-file_io.o
+ $(top_builddir)/oem/ibm/libpldmresponder/libpldmresponder_la-file_io.o\
+ $(top_builddir)/oem/ibm/libpldmresponder/libpldmresponder_la-file_table.o
libpldmoemresponder_fileio_test_SOURCES = $(top_builddir)/oem/ibm/test/libpldmresponder_fileio_test.cpp
endif
diff --git a/test/files/NVRAM-IMAGE b/test/files/NVRAM-IMAGE
new file mode 100644
index 0000000..06d7405
--- /dev/null
+++ b/test/files/NVRAM-IMAGE
Binary files differ
diff --git a/test/files/NVRAM-IMAGE-CKSUM b/test/files/NVRAM-IMAGE-CKSUM
new file mode 100644
index 0000000..01d633b
--- /dev/null
+++ b/test/files/NVRAM-IMAGE-CKSUM
Binary files differ