ibm-oem: add handler to read PELs
Extend ReadFileByType* commands to let the host firmware read PELs off
of the BMC.
Signed-off-by: vkaverap <vkaverap@in.ibm.com>
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I3721e1ffe61a66d0f011535504a6915e0c16764b
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 6f65b97..d191d3d 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -49,8 +49,8 @@
constexpr auto xdmaDev = "/dev/aspeed-xdma";
-int DMA::transferDataHost(const fs::path& path, uint32_t offset,
- uint32_t length, uint64_t address, bool upstream)
+int DMA::transferDataHost(int fd, uint32_t offset, uint32_t length,
+ uint64_t address, bool upstream)
{
static const size_t pageSize = getpagesize();
uint32_t numPages = length / pageSize;
@@ -65,17 +65,17 @@
munmap(vgaMem, pageAlignedLength);
};
- int fd = -1;
+ int dmaFd = -1;
int rc = 0;
- fd = open(xdmaDev, O_RDWR);
- if (fd < 0)
+ dmaFd = open(xdmaDev, O_RDWR);
+ if (dmaFd < 0)
{
rc = -errno;
std::cerr << "Failed to open the XDMA device, RC=" << rc << "\n";
return rc;
}
- utils::CustomFD xdmaFd(fd);
+ utils::CustomFD xdmaFd(dmaFd);
void* vgaMem;
vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
@@ -91,25 +91,37 @@
if (upstream)
{
- std::ifstream stream(path.string(), std::ios::in | std::ios::binary);
- stream.seekg(offset);
+ rc = lseek(fd, offset, SEEK_SET);
+ if (rc == -1)
+ {
+ std::cerr << "lseek failed, ERROR=" << errno
+ << ", UPSTREAM=" << upstream << ", OFFSET=" << offset
+ << "\n";
+ return rc;
+ }
// 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)
+ rc = read(fd, buffer.data(), length);
+ if (rc == -1)
+ {
+ std::cerr << "file read failed, ERROR=" << errno
+ << ", UPSTREAM=" << upstream << ", LENGTH=" << length
+ << ", OFFSET=" << offset << "\n";
+ return rc;
+ }
+ if (rc != static_cast<int>(length))
{
std::cerr << "mismatch between number of characters to read and "
- << "the length read, LENGTH=" << length
- << " COUNT=" << stream.gcount() << "\n";
+ << "the length read, LENGTH=" << length << " COUNT=" << rc
+ << "\n";
return -1;
}
+ memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
+ pageAlignedLength);
}
AspeedXdmaOp xdmaOp;
@@ -129,15 +141,22 @@
if (!upstream)
{
- std::ios_base::openmode mode = std::ios::out | std::ios::binary;
- if (fs::exists(path))
+ rc = lseek(fd, offset, SEEK_SET);
+ if (rc == -1)
{
- mode |= std::ios::in;
+ std::cerr << "lseek failed, ERROR=" << errno
+ << ", UPSTREAM=" << upstream << ", OFFSET=" << offset
+ << "\n";
+ return rc;
}
- std::ofstream stream(path.string(), mode);
-
- stream.seekp(offset);
- stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
+ rc = write(fd, static_cast<const char*>(vgaMemPtr.get()), length);
+ if (rc == -1)
+ {
+ std::cerr << "file write failed, ERROR=" << errno
+ << ", UPSTREAM=" << upstream << ", LENGTH=" << length
+ << ", OFFSET=" << offset << "\n";
+ return rc;
+ }
}
return 0;
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index 231222c..5c357d5 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -1,11 +1,16 @@
#pragma once
#include "handler.hpp"
+#include "libpldmresponder/utils.hpp"
+#include <fcntl.h>
#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <filesystem>
+#include <iostream>
#include <vector>
#include "libpldm/base.h"
@@ -49,7 +54,7 @@
*
* @return returns 0 on success, negative errno on failure
*/
- int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length,
+ int transferDataHost(int fd, uint32_t offset, uint32_t length,
uint64_t address, bool upstream);
};
@@ -81,9 +86,32 @@
Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ int flags{};
+ if (upstream)
+ {
+ flags = O_RDONLY;
+ }
+ else if (fs::exists(path))
+ {
+ flags = O_RDWR;
+ }
+ else
+ {
+ flags = O_WRONLY;
+ }
+ int file = open(path.string().c_str(), flags);
+ if (file == -1)
+ {
+ std::cerr << "File does not exist, path = " << path.string() << "\n";
+ encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
+ responsePtr);
+ return response;
+ }
+ utils::CustomFD fd(file);
+
while (length > dma::maxSize)
{
- auto rc = intf->transferDataHost(path, offset, dma::maxSize, address,
+ auto rc = intf->transferDataHost(fd(), offset, dma::maxSize, address,
upstream);
if (rc < 0)
{
@@ -97,7 +125,7 @@
address += dma::maxSize;
}
- auto rc = intf->transferDataHost(path, offset, length, address, upstream);
+ auto rc = intf->transferDataHost(fd(), offset, length, address, upstream);
if (rc < 0)
{
encode_rw_file_memory_resp(instanceId, command, PLDM_ERROR, 0,
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.cpp b/oem/ibm/libpldmresponder/file_io_by_type.cpp
index 7a95a6d..7d001b9 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.cpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.cpp
@@ -27,13 +27,36 @@
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+int FileHandler::transferFileData(int32_t fd, bool upstream, uint32_t offset,
+ uint32_t& length, uint64_t address)
+{
+ dma::DMA xdmaInterface;
+ while (length > dma::maxSize)
+ {
+ auto rc = xdmaInterface.transferDataHost(fd, offset, dma::maxSize,
+ address, upstream);
+ if (rc < 0)
+ {
+ return PLDM_ERROR;
+ }
+ offset += dma::maxSize;
+ length -= dma::maxSize;
+ address += dma::maxSize;
+ }
+ auto rc =
+ xdmaInterface.transferDataHost(fd, offset, length, address, upstream);
+ return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
+}
+
int FileHandler::transferFileData(const fs::path& path, bool upstream,
uint32_t offset, uint32_t& length,
uint64_t address)
{
+ bool fileExists = false;
if (upstream)
{
- if (!fs::exists(path))
+ fileExists = fs::exists(path);
+ if (!fileExists)
{
std::cerr << "File does not exist. PATH=" << path.c_str() << "\n";
return PLDM_INVALID_FILE_HANDLE;
@@ -52,23 +75,29 @@
}
}
- dma::DMA xdmaInterface;
-
- while (length > dma::maxSize)
+ int flags{};
+ if (upstream)
{
- auto rc = xdmaInterface.transferDataHost(path, offset, dma::maxSize,
- address, upstream);
- if (rc < 0)
- {
- return PLDM_ERROR;
- }
- offset += dma::maxSize;
- length -= dma::maxSize;
- address += dma::maxSize;
+ flags = O_RDONLY;
}
- auto rc =
- xdmaInterface.transferDataHost(path, offset, length, address, upstream);
- return rc < 0 ? PLDM_ERROR : PLDM_SUCCESS;
+ else if (fileExists)
+ {
+ flags = O_RDWR;
+ }
+ else
+ {
+ flags = O_WRONLY;
+ }
+ int file = open(path.string().c_str(), flags);
+ if (file == -1)
+ {
+ std::cerr << "File does not exist, PATH = " << path.string() << "\n";
+ ;
+ return PLDM_ERROR;
+ }
+ utils::CustomFD fd(file);
+
+ return transferFileData(fd(), upstream, offset, length, address);
}
std::unique_ptr<FileHandler> getHandlerByType(uint16_t fileType,
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.hpp b/oem/ibm/libpldmresponder/file_io_by_type.hpp
index 779eaef..b8621f5 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.hpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.hpp
@@ -75,6 +75,9 @@
uint32_t offset, uint32_t& length,
uint64_t address);
+ virtual int transferFileData(int fd, bool upstream, uint32_t offset,
+ uint32_t& length, uint64_t address);
+
/** @brief Constructor to create a FileHandler object
*/
FileHandler(uint32_t fileHandle) : fileHandle(fileHandle)
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.cpp b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
index c919c27..06ced26 100644
--- a/oem/ibm/libpldmresponder/file_io_type_pel.cpp
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
@@ -24,16 +24,98 @@
namespace responder
{
-int PelHandler::readIntoMemory(uint32_t /*offset*/, uint32_t& /*length*/,
- uint64_t /*address*/)
+int PelHandler::readIntoMemory(uint32_t offset, uint32_t& length,
+ uint64_t address)
{
- return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+ static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
+ static constexpr auto logInterface = "org.open_power.Logging.PEL";
+
+ static sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
+
+ try
+ {
+ auto service = getService(bus, logObjPath, logInterface);
+ auto method = bus.new_method_call(service.c_str(), logObjPath,
+ logInterface, "GetPEL");
+ method.append(fileHandle);
+ auto reply = bus.call(method);
+ sdbusplus::message::unix_fd fd{};
+ reply.read(fd);
+ auto rc = transferFileData(fd, true, offset, length, address);
+ return rc;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "GetPEL D-Bus call failed, PEL id = " << fileHandle
+ << ", error = " << e.what() << "\n";
+ return PLDM_ERROR;
+ }
+
+ return PLDM_SUCCESS;
}
-int PelHandler::read(uint32_t /*offset*/, uint32_t& /*length*/,
- Response& /*response*/)
+int PelHandler::read(uint32_t offset, uint32_t& length, Response& response)
{
- return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+ static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
+ static constexpr auto logInterface = "org.open_power.Logging.PEL";
+ static sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
+
+ try
+ {
+ auto service = getService(bus, logObjPath, logInterface);
+ auto method = bus.new_method_call(service.c_str(), logObjPath,
+ logInterface, "GetPEL");
+ method.append(fileHandle);
+ auto reply = bus.call(method);
+ sdbusplus::message::unix_fd fd{};
+ reply.read(fd);
+ std::cerr << "GetPEL D-Bus call done\n";
+ off_t fileSize = lseek(fd, 0, SEEK_END);
+ if (fileSize == -1)
+ {
+ std::cerr << "file seek failed";
+ return PLDM_ERROR;
+ }
+ if (offset >= fileSize)
+ {
+ std::cerr << "Offset exceeds file size, OFFSET=" << offset
+ << " FILE_SIZE=" << fileSize << std::endl;
+ return PLDM_DATA_OUT_OF_RANGE;
+ }
+ if (offset + length > fileSize)
+ {
+ length = fileSize - offset;
+ }
+ auto rc = lseek(fd, offset, SEEK_SET);
+ if (rc == -1)
+ {
+ std::cerr << "file seek failed";
+ return PLDM_ERROR;
+ }
+ size_t currSize = response.size();
+ response.resize(currSize + length);
+ auto filePos = reinterpret_cast<char*>(response.data());
+ filePos += currSize;
+ rc = ::read(fd, filePos, length);
+ if (rc == -1)
+ {
+ std::cerr << "file read failed";
+ return PLDM_ERROR;
+ }
+ if (rc != length)
+ {
+ std::cerr << "mismatch between number of characters to read and "
+ << "the length read, LENGTH=" << length << " COUNT=" << rc
+ << std::endl;
+ return PLDM_ERROR;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "GetPEL D-Bus call failed";
+ return PLDM_ERROR;
+ }
+ return PLDM_SUCCESS;
}
int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index e62e8e1..86df25e 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -96,9 +96,8 @@
class MockDMA
{
public:
- MOCK_METHOD5(transferDataHost,
- int(const fs::path& file, uint32_t offset, uint32_t length,
- uint64_t address, bool upstream));
+ MOCK_METHOD5(transferDataHost, int(int fd, uint32_t offset, uint32_t length,
+ uint64_t address, bool upstream));
};
} // namespace dma
@@ -113,13 +112,16 @@
using namespace pldm::responder::dma;
MockDMA dmaObj;
- fs::path path("");
+ char tmpfile[] = "/tmp/pldm_fileio_table.XXXXXX";
+ int fd = mkstemp(tmpfile);
+ close(fd);
+ fs::path path(tmpfile);
// Minimum length of 16 and expect transferDataHost to be called once
// returns the default value of 0 (the return type of transferDataHost is
// int, the default value for int is 0)
uint32_t length = minSize;
- EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1);
+ EXPECT_CALL(dmaObj, transferDataHost(_, 0, length, 0, true)).Times(1);
auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY,
path, 0, length, 0, true, 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -129,7 +131,7 @@
// maxsize of DMA
length = maxSize;
- EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1);
+ EXPECT_CALL(dmaObj, transferDataHost(_, 0, length, 0, true)).Times(1);
response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
0, length, 0, true, 0);
responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -139,8 +141,8 @@
// length greater than maxsize of DMA
length = maxSize + minSize;
- EXPECT_CALL(dmaObj, transferDataHost(path, 0, maxSize, 0, true)).Times(1);
- EXPECT_CALL(dmaObj, transferDataHost(path, maxSize, minSize, maxSize, true))
+ EXPECT_CALL(dmaObj, transferDataHost(_, 0, maxSize, 0, true)).Times(1);
+ EXPECT_CALL(dmaObj, transferDataHost(_, maxSize, minSize, maxSize, true))
.Times(1);
response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
0, length, 0, true, 0);
@@ -161,7 +163,7 @@
// check for downstream(copy data from host to BMC) parameter
length = minSize;
- EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, false)).Times(1);
+ EXPECT_CALL(dmaObj, transferDataHost(_, 0, length, 0, false)).Times(1);
response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
0, length, 0, false, 0);
responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -175,7 +177,10 @@
using namespace pldm::responder::dma;
MockDMA dmaObj;
- fs::path path("");
+ char tmpfile[] = "/tmp/pldm_fileio_table.XXXXXX";
+ int fd = mkstemp(tmpfile);
+ close(fd);
+ fs::path path(tmpfile);
// Minimum length of 16 and transferDataHost returning a negative errno
uint32_t length = minSize;