| #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; |
| |
| // Check if partition exists in patch location |
| partitionFilePath = context->paths.patch_loc; |
| partitionFilePath /= partition->data.name; |
| if (fs::is_regular_file(partitionFilePath)) |
| { |
| return partitionFilePath.string(); |
| } |
| |
| 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>(); |
| } |
| |
| // 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(partitionFilePath, 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 |