diff options
-rw-r--r-- | Makefile.am | 43 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | mboxd.c | 5 | ||||
-rw-r--r-- | mboxd_pnor_partition_table.h | 2 | ||||
-rw-r--r-- | pnor_partition.cpp | 187 | ||||
-rw-r--r-- | pnor_partition.hpp | 162 | ||||
-rw-r--r-- | pnor_partition_table.cpp | 2 | ||||
-rw-r--r-- | test/create_read_window_vpnor.cpp | 2 |
8 files changed, 397 insertions, 11 deletions
diff --git a/Makefile.am b/Makefile.am index 5614256..4f49644 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,7 +16,8 @@ mboxd_CFLAGS = $(LIBSYSTEMD_CFLAGS) if VIRTUAL_PNOR_ENABLED mboxd_SOURCES += pnor_partition_table.cpp \ mboxd_pnor_partition_table.cpp \ - mboxd_flash_virtual.cpp + mboxd_flash_virtual.cpp \ + pnor_partition.cpp mboxd_LDFLAGS += -lstdc++fs \ $(SDBUSPLUS_LIBS) \ @@ -39,13 +40,35 @@ AM_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) test_sanity_SOURCES = test/sanity.c -test_copy_flash_SOURCES = test/copy_flash.c mboxd_flash.c mboxd_flash_physical.c common.c mtd.c test/tmpf.c +test_copy_flash_SOURCES = \ + test/copy_flash.c \ + mboxd_flash.c \ + mboxd_flash_physical.c \ + common.c mtd.c \ + test/tmpf.c -test_erase_flash_SOURCES = test/erase_flash.c mboxd_flash.c common.c test/tmpf.c +test_erase_flash_SOURCES = \ + test/erase_flash.c \ + mboxd_flash.c \ + mboxd_flash_physical.c \ + common.c \ + test/tmpf.c -test_write_flash_SOURCES = test/write_flash.c mboxd_flash.c common.c test/tmpf.c +test_write_flash_SOURCES = \ + test/write_flash.c \ + mboxd_flash.c \ + mboxd_flash_physical.c \ + common.c \ + test/tmpf.c + +TEST_MBOX_SRCS = \ + mboxd_msg.c \ + mboxd_windows.c \ + mboxd_lpc.c \ + mboxd_flash.c \ + common.c \ + mboxd_flash_physical.c -TEST_MBOX_SRCS = mboxd_msg.c mboxd_windows.c mboxd_lpc.c mboxd_flash.c common.c mboxd_flash_physical.c TEST_MOCK_SRCS = test/tmpf.c test/mbox.c test/system.c test_get_mbox_info_v2_SOURCES = test/get_mbox_info_v2.c \ @@ -133,9 +156,13 @@ test_create_read_window_vpnor_SOURCES = \ mboxd_flash.c \ mboxd_pnor_partition_table.cpp \ mboxd_flash_virtual.cpp \ + pnor_partition.cpp \ test/create_read_window_vpnor.cpp test_create_read_window_vpnor_LDFLAGS = $(OESDK_TESTCASE_FLAGS) -test_create_read_window_vpnor_LDADD = -lstdc++fs +test_create_read_window_vpnor_LDADD = -lstdc++fs \ + $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_LOGGING_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) check_PROGRAMS = test/sanity \ test/copy_flash \ @@ -166,7 +193,9 @@ check_PROGRAMS = test/sanity \ test/get_mbox_info_v2_timeout if VIRTUAL_PNOR_ENABLED -check_PROGRAMS += test/create_pnor_partition_table test/create_read_window_vpnor +check_PROGRAMS += \ + test/create_pnor_partition_table \ + test/create_read_window_vpnor endif TESTS = $(check_PROGRAMS) diff --git a/configure.ac b/configure.ac index 2f51e2b..94047da 100644 --- a/configure.ac +++ b/configure.ac @@ -76,8 +76,9 @@ AC_SUBST([LIBSYSTEMD_CFLAGS]) AC_SUBST([LIBSYSTEMD_LIBS]) AC_DEFINE(PARTITION_TOC_FILE, "pnor.toc", [The basename of the PNOR Table of contents file.]) -AC_DEFINE(PARTITION_FILES_LOC, "/var/lib/phosphor-software-manager/pnor/ro", [The path to the directory containing PNOR partition files.]) - +AC_DEFINE(PARTITION_FILES_RO_LOC, "/var/lib/phosphor-software-manager/pnor/ro", [The path to the directory containing PNOR read only partition files.]) +AC_DEFINE(PARTITION_FILES_RW_LOC, "/var/lib/phosphor-software-manager/pnor/rw", [The path to the directory containing PNOR read write partition files.]) +AC_DEFINE(PARTITION_FILES_PRSV_LOC, "/var/lib/phosphor-software-manager/pnor/prsv", [The path to the directory containing PNOR preserve partition files.]) # Create configured output AC_CONFIG_FILES([Makefile]) AC_OUTPUT @@ -314,7 +314,10 @@ int main(int argc, char **argv) #ifdef VIRTUAL_PNOR_ENABLED vpnor_create_partition_table(context); - strcpy(context->paths.ro_loc, PARTITION_FILES_LOC); + + strcpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC); + strcpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC); + strcpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC); #endif rc = init_signals(context, &set); diff --git a/mboxd_pnor_partition_table.h b/mboxd_pnor_partition_table.h index f494830..e6c899b 100644 --- a/mboxd_pnor_partition_table.h +++ b/mboxd_pnor_partition_table.h @@ -11,6 +11,8 @@ struct vpnor_partition_table; struct vpnor_partition_paths { char ro_loc[PATH_MAX]; + char rw_loc[PATH_MAX]; + char prsv_loc[PATH_MAX]; }; #ifdef __cplusplus diff --git a/pnor_partition.cpp b/pnor_partition.cpp new file mode 100644 index 0000000..3f4fd02 --- /dev/null +++ b/pnor_partition.cpp @@ -0,0 +1,187 @@ +#include "pnor_partition.hpp" +#include "config.h" +#include "mboxd_flash.h" +#include "mboxd_pnor_partition_table.h" +#include "xyz/openbmc_project/Common/error.hpp" +#include <phosphor-logging/log.hpp> +#include <phosphor-logging/elog-errors.hpp> + +#include <stdint.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include "common.h" + +#include <string> +#include <exception> +#include <stdexcept> +#include <iostream> + +namespace openpower +{ +namespace virtual_pnor +{ + +using namespace phosphor::logging; +using namespace sdbusplus::xyz::openbmc_project::Common::Error; +using namespace std::string_literals; + +ReturnCode Request::open(const std::string& path, + int mode) +{ + if (mode == O_RDWR && + partition->data.user.data[1] & PARTITION_READONLY) + { + MSG_ERR("Can't open the RO partition for write"); + return ReturnCode::PARTITION_READ_ONLY; + } + + fs::path partitionFilePath = path; + + if (!fs::exists(partitionFilePath)) + { + return ReturnCode::FILE_NOT_FOUND; + } + + auto descriptor = ::open(partitionFilePath.c_str(), mode); + if (descriptor < 0) + { + return ReturnCode::FILE_OPEN_FAILURE; + } + + fd.set(descriptor); + descriptor = -1; + + return ReturnCode::SUCCESS; +} + +std::string Request::getPartitionFilePath(struct mbox_context* context, + uint32_t offset) +{ + partition = vpnor_get_partition(context, offset); + if (!partition) + { + MSG_ERR("Couldn't get the partition info for offset[0x%.8x]",offset); + elog<InternalFailure>(); + } + + fs::path partitionFilePath; + + switch (partition->data.user.data[1] & + (PARTITION_PRESERVED | PARTITION_READONLY)) + { + case PARTITION_PRESERVED: + partitionFilePath = context->paths.prsv_loc; + break; + + case PARTITION_READONLY: + partitionFilePath = context->paths.ro_loc; + break; + + default: + partitionFilePath = context->paths.rw_loc; + } + partitionFilePath /= partition->data.name; + return partitionFilePath.string(); +} + +const pnor_partition* RORequest::getPartitionInfo(struct mbox_context* context, + uint32_t offset) +{ + std::string path = getPartitionFilePath(context, offset); + + ReturnCode rc = Request::open(path, O_RDONLY); + if (rc == ReturnCode::SUCCESS) + { + return partition; + } + // not interested in any other error except FILE_NOT_FOUND + if (rc != ReturnCode::FILE_NOT_FOUND) + { + elog<InternalFailure>(); + } + + // if the offset lies in read only partition then throw error. + if (partition->data.user.data[1] & PARTITION_READONLY) + { + MSG_ERR("Can't open the partition file"); + elog<InternalFailure>(); + } + + MSG_DBG("Couldn't open the file[%s]", path.c_str()); + // we don't get the file in the respective partition(RW/PSRV) + // try to open it from RO location. + + fs::path partitionFilePath = context->paths.ro_loc; + partitionFilePath /= partition->data.name; + + rc = Request::open(path, O_RDONLY); + if (rc != ReturnCode::SUCCESS) + { + elog<InternalFailure>(); + } + + return partition; + +} + +const pnor_partition* RWRequest::getPartitionInfo(struct mbox_context* context, + uint32_t offset) +{ + std::string path = getPartitionFilePath(context, offset); + + ReturnCode rc = Request::open(path, O_RDWR); + if (rc == ReturnCode::SUCCESS) + { + return partition; + } + // not interested in any other error except FILE_NOT_FOUND + if (rc != ReturnCode::FILE_NOT_FOUND) + { + elog<InternalFailure>(); + } + + // if the file is not available in the respective(RW/PSRV) partition + // then copy the file from RO to the respective(RW/PSRV) partition + // and open it for writing. + + fs::path fromPath = context->paths.ro_loc; + fromPath /= partition->data.name; + if (!fs::exists(fromPath)) + { + MSG_ERR("Couldn't find the file[%s]",fromPath.c_str()); + elog<InternalFailure>(); + } + //copy the file from ro to respective partition + fs::path toPath = context->paths.rw_loc; + + if (partition->data.user.data[1] & PARTITION_PRESERVED) + { + toPath = context->paths.prsv_loc; + } + + toPath /= partition->data.name; + + MSG_DBG("Didn't find the file in the desired partition so copying[%s]\n", + toPath.c_str()); + + if (fs::copy_file(fromPath, toPath)) + { + MSG_DBG("File copied from[%s] to [%s]\n", + fromPath.c_str(), toPath.c_str()); + } + + rc = Request::open(toPath.c_str(), O_RDWR); + + if (rc != ReturnCode::SUCCESS) + { + elog<InternalFailure>(); + } + + return partition; +} + +}// namespace virtual_pnor +}// namespace openpower diff --git a/pnor_partition.hpp b/pnor_partition.hpp new file mode 100644 index 0000000..004dca6 --- /dev/null +++ b/pnor_partition.hpp @@ -0,0 +1,162 @@ +#pragma once + +#include "mboxd_pnor_partition_table.h" +#include <fcntl.h> +#include <string> +#include <unistd.h> +#include <experimental/filesystem> + +namespace openpower +{ +namespace file +{ + +class Descriptor +{ + private: + /** default value */ + int fd = -1; + + public: + Descriptor() = default; + Descriptor(const Descriptor&) = delete; + Descriptor& operator=(const Descriptor&) = delete; + Descriptor(Descriptor&&) = delete; + Descriptor& operator=(Descriptor &&) = delete; + + Descriptor(int fd) : fd(fd) {} + + ~Descriptor() + { + if (fd >= 0) + { + close(fd); + } + } + + int operator()() const + { + return fd; + } + + void set(int descriptor) + { + fd = descriptor; + } +}; + +}// namespace file + +namespace virtual_pnor +{ + +namespace fs = std::experimental::filesystem; + +enum class ReturnCode : uint8_t +{ + FILE_NOT_FOUND = 0, + PARTITION_NOT_FOUND = 1, + PARTITION_READ_ONLY = 2, + FILE_OPEN_FAILURE = 3, + SUCCESS = 4, +}; + +class Request +{ + public: + + Request() = default; + Request(const Request&) = delete; + Request& operator=(const Request&) = delete; + Request(Request&&) = default; + Request& operator=(Request&&) = default; + ~Request() = default; + + openpower::file::Descriptor fd; + + protected: + /** @brief opens the partition file + * + * @param[in] filePath - Absolute file path. + * @param[in] mode - File open mode. + */ + ReturnCode open(const std::string& filePath, int mode); + + /** @brief returns the partition file path associated with the offset. + * + * @param[in] context - The mbox context pointer. + * @param[in] offset - The pnor offset(bytes). + */ + + std::string getPartitionFilePath(struct mbox_context* context, + uint32_t offset); + + const pnor_partition* partition = nullptr; +}; + +/** @class RORequest + * @brief Represent the read request of the partition. + * Stores the partition meta data. + */ +class RORequest : public Request +{ + public: + RORequest() = default; + RORequest(const RORequest&) = delete; + RORequest& operator=(const RORequest&) = delete; + RORequest(RORequest&&) = default; + RORequest& operator=(RORequest&&) = default; + ~RORequest(){}; + + /** @brief opens the partition file associated with the offset + * in read only mode and gets the partition details. + * + * 1. Depending on the partition type,tries to open the file + * from the associated partition(RW/PRSV/RO). + * 1a. if file not found in the corresponding + * partition(RW/PRSV/RO) then tries to read the file from + * the read only partition. + * 1b. if the file not found in the read only partition then + * throw exception. + * + * @param[in] context - The mbox context pointer. + * @param[in] offset - The pnor offset(bytes). + */ + const pnor_partition* getPartitionInfo(struct mbox_context* context, + uint32_t offset); +}; + +/** @class RWRequest + * @brief Represent the write request of the partition. + * Stores the partition meta data. + */ +class RWRequest : public Request +{ + public: + + RWRequest() = default; + RWRequest(const RWRequest&) = delete; + RWRequest& operator=(const RWRequest&) = delete; + RWRequest(RWRequest&&) = default; + RWRequest& operator=(RWRequest&&) = default; + ~RWRequest() {}; + + /** @brief opens the partition file associated with the offset + * in write mode and gets the parttition details. + * + * 1. Depending on the partition type tries to open the file + * from the associated partition. + * 1a. if file not found in the corresponding partition(RW/PRSV) + * then copy the file from the read only partition to the (RW/PRSV) + * partition depending on the partition type. + * 1b. if the file not found in the read only partition then throw exception. + * + * @param[in] context - The mbox context pointer. + * @param[in] offset - The pnor offset(bytes). + */ + const pnor_partition* getPartitionInfo(struct mbox_context* context, + uint32_t offset); +}; + +}// namespace virtual_pnor +}// namespace openpower diff --git a/pnor_partition_table.cpp b/pnor_partition_table.cpp index 17f5011..d20b44c 100644 --- a/pnor_partition_table.cpp +++ b/pnor_partition_table.cpp @@ -23,7 +23,7 @@ constexpr size_t size = 4096; } // namespace block Table::Table(): - Table(fs::path(PARTITION_FILES_LOC)) + Table(fs::path(PARTITION_FILES_RO_LOC)) { } diff --git a/test/create_read_window_vpnor.cpp b/test/create_read_window_vpnor.cpp index 855d88d..8121498 100644 --- a/test/create_read_window_vpnor.cpp +++ b/test/create_read_window_vpnor.cpp @@ -66,6 +66,8 @@ int main() struct mbox_context *ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE); strcpy(ctx->paths.ro_loc,tmpdir); + strcpy(ctx->paths.rw_loc,tmpdir); + strcpy(ctx->paths.prsv_loc,tmpdir); vpnor_create_partition_table_from_path(ctx, tmpdir); |