Sync ibm-pldm-oem repository changes to pldm repository
Change-Id: I6f30b39f483647ad84fe2fbe1c24298841040801
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
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