summaryrefslogtreecommitdiffstats
path: root/pnor_partition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pnor_partition.cpp')
-rw-r--r--pnor_partition.cpp209
1 files changed, 76 insertions, 133 deletions
diff --git a/pnor_partition.cpp b/pnor_partition.cpp
index cdb9633..390c4d5 100644
--- a/pnor_partition.cpp
+++ b/pnor_partition.cpp
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2018 IBM Corp.
#include "pnor_partition.hpp"
+#include "pnor_partition_table.hpp"
#include "config.h"
#include "mboxd_flash.h"
#include "mboxd_pnor_partition_table.h"
@@ -8,6 +9,7 @@
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog-errors.hpp>
+#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <syslog.h>
@@ -26,185 +28,126 @@ namespace openpower
namespace virtual_pnor
{
-using namespace phosphor::logging;
-using namespace sdbusplus::xyz::openbmc_project::Common::Error;
-using namespace std::string_literals;
+namespace fs = std::experimental::filesystem;
-ReturnCode Request::open(const std::string& path, int mode)
+fs::path Request::getPartitionFilePath(int flags)
{
- if (mode == O_RDWR && partition->data.user.data[1] & PARTITION_READONLY)
- {
- MSG_ERR("Can't open RO partition '%s' for write\n", path.c_str());
- 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%" PRIx32 "\n",
- 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))
+ auto dst = fs::path(ctx->paths.patch_loc) / partition.data.name;
+ if (fs::is_regular_file(dst))
{
- return partitionFilePath.string();
+ return dst;
}
- switch (partition->data.user.data[1] &
+ switch (partition.data.user.data[1] &
(PARTITION_PRESERVED | PARTITION_READONLY))
{
case PARTITION_PRESERVED:
- partitionFilePath = context->paths.prsv_loc;
+ dst = ctx->paths.prsv_loc;
break;
case PARTITION_READONLY:
- partitionFilePath = context->paths.ro_loc;
+ dst = ctx->paths.ro_loc;
break;
default:
- partitionFilePath = context->paths.rw_loc;
+ dst = ctx->paths.rw_loc;
}
- partitionFilePath /= partition->data.name;
- return partitionFilePath.string();
-}
+ dst /= partition.data.name;
-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)
+ if (fs::exists(dst))
{
- return partition;
- }
- // not interested in any other error except FILE_NOT_FOUND
- if (rc != ReturnCode::FILE_NOT_FOUND)
- {
- MSG_ERR(
- "RORequest: Error opening partition file '%s' (offset 0x%" PRIx32
- "): %u\n",
- path.c_str(), offset, static_cast<uint8_t>(rc));
- elog<InternalFailure>();
+ return dst;
}
- // if the offset lies in read only partition then throw error.
- if (partition->data.user.data[1] & PARTITION_READONLY)
+ if (flags == O_RDONLY)
{
- MSG_ERR("RORequest: Requested offset 0x%" PRIx32
- " is in a read-only partition (%s)\n",
- offset, path.c_str());
- elog<InternalFailure>();
+ dst = fs::path(ctx->paths.ro_loc) / partition.data.name;
+ assert(fs::exists(dst));
+ return dst;
}
- // we don't get the file in the respective partition(RW/PSRV)
- // try to open it from RO location.
+ assert(flags == O_RDWR);
+ auto src = fs::path(ctx->paths.ro_loc) / partition.data.name;
+ assert(fs::exists(src));
- fs::path partitionFilePath = context->paths.ro_loc;
- partitionFilePath /= partition->data.name;
+ MSG_DBG("RWRequest: Didn't find '%s' under '%s', copying from '%s'\n",
+ partition.data.name, dst.c_str(), src.c_str());
- rc = Request::open(partitionFilePath, O_RDONLY);
- if (rc != ReturnCode::SUCCESS)
+ dst = ctx->paths.rw_loc;
+ if (partition.data.user.data[1] & PARTITION_PRESERVED)
{
- MSG_ERR("RORequest: Failed to open partition file '%s' at RO fallback "
- "(offset 0x%" PRIx32 "): %u\n",
- partitionFilePath.c_str(), offset, static_cast<uint8_t>(rc));
- elog<InternalFailure>();
+ dst = ctx->paths.prsv_loc;
}
- return partition;
+ dst /= partition.data.name;
+ fs::copy_file(src, dst);
+
+ return dst;
}
-const pnor_partition* RWRequest::getPartitionInfo(struct mbox_context* context,
- uint32_t offset)
+ssize_t Request::fulfil(void *buf, size_t len, int flags)
{
- std::string path = getPartitionFilePath(context, offset);
- std::error_code ec;
-
- 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)
+ if (!(flags == O_RDONLY || flags == O_RDWR))
{
- MSG_ERR(
- "RWRequest: Error opening partition file '%s' (offset 0x%" PRIx32
- "): %d\n",
- path.c_str(), offset, static_cast<uint8_t>(rc));
- elog<InternalFailure>();
+ std::stringstream err;
+ err << "Require O_RDONLY (0x" << std::hex << O_RDONLY << " or O_RDWR "
+ << std::hex << O_RDWR << " for flags, got: 0x" << std::hex << flags;
+ throw std::invalid_argument(err.str());
}
- // 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 path = getPartitionFilePath(flags);
- fs::path fromPath = context->paths.ro_loc;
- fromPath /= partition->data.name;
- if (!fs::exists(fromPath))
+ int fd = ::open(path.c_str(), flags);
+ if (fd == -1)
{
- MSG_ERR("RWRequest: Partition '%s' for offset 0x%" PRIx32
- " not found in RO directory '%s'\n",
- partition->data.name, offset, context->paths.ro_loc);
- elog<InternalFailure>();
+ MSG_ERR("Failed to open backing file at '%s': %d\n",
+ path.c_str(), errno);
+ throw std::system_error(errno, std::system_category());
}
- // copy the file from ro to respective partition
- fs::path toPath = context->paths.rw_loc;
- if (partition->data.user.data[1] & PARTITION_PRESERVED)
+ int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0);
+ auto map = mmap(NULL, partition.data.actual, mprot, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED)
{
- toPath = context->paths.prsv_loc;
+ close(fd);
+ MSG_ERR("Failed to map backing file '%s' for %d bytes: %d\n",
+ path.c_str(), partition.data.actual, errno);
+ throw std::system_error(errno, std::system_category());
}
- MSG_DBG("RWRequest: Didn't find '%s' under '%s', copying from '%s'\n",
- partition->data.name, toPath.c_str(), fromPath.c_str());
-
- toPath /= partition->data.name;
- if (!fs::copy_file(fromPath, toPath, ec))
+ // copy to the reserved memory area
+ if (flags == O_RDONLY)
{
- MSG_ERR("RWRequest: Failed to copy file from '%s' to '%s': %d\n",
- fromPath.c_str(), toPath.c_str(), ec.value());
- elog<InternalFailure>();
+ len = std::min(partition.data.actual - offset, len);
+ memcpy(buf, (char *)map + offset, len);
}
-
- rc = Request::open(toPath.c_str(), O_RDWR);
-
- if (rc != ReturnCode::SUCCESS)
+ else
{
- MSG_ERR("RWRequest: Failed to open file at '%s': %d\n", toPath.c_str(),
- static_cast<uint8_t>(rc));
- elog<InternalFailure>();
+ // if the asked offset + no of bytes to read is greater
+ // then size of the partition file then throw error.
+ //
+ // FIXME: Don't use .actual, use (.size << ctx->block_size_shift),
+ // otherwise we can't grow the size of the data to fill the partition
+ if ((base + offset + len) > (base + partition.data.actual))
+ {
+ munmap(map, partition.data.actual);
+ close(fd);
+
+ /* FIXME: offset calculation */
+ std::stringstream err;
+ err << "Request size 0x" << std::hex << len << " from offset 0x"
+ << std::hex << offset << " exceeds the partition size 0x"
+ << std::hex << partition.data.actual;
+ throw OutOfBoundsOffset(err.str());
+ }
+ memcpy((char *)map + offset, buf, len);
+ set_flash_bytemap(ctx, base + offset, len, FLASH_DIRTY);
}
+ munmap(map, partition.data.actual);
+ close(fd);
- return partition;
+ return len;
}
} // namespace virtual_pnor
OpenPOWER on IntegriCloud