diff options
Diffstat (limited to 'vpnor/pnor_partition.cpp')
-rw-r--r-- | vpnor/pnor_partition.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/vpnor/pnor_partition.cpp b/vpnor/pnor_partition.cpp new file mode 100644 index 0000000..84aeb3f --- /dev/null +++ b/vpnor/pnor_partition.cpp @@ -0,0 +1,163 @@ +// 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" +#include "xyz/openbmc_project/Common/error.hpp" +#include <phosphor-logging/log.hpp> +#include <phosphor-logging/elog-errors.hpp> + +#include <assert.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "common.h" + +#include <string> +#include <exception> +#include <stdexcept> +#include <iostream> + +namespace openpower +{ +namespace virtual_pnor +{ + +namespace fs = std::experimental::filesystem; + +fs::path Request::getPartitionFilePath(int flags) +{ + // Check if partition exists in patch location + auto dst = fs::path(ctx->paths.patch_loc) / partition.data.name; + if (fs::is_regular_file(dst)) + { + return dst; + } + + switch (partition.data.user.data[1] & + (PARTITION_PRESERVED | PARTITION_READONLY)) + { + case PARTITION_PRESERVED: + dst = ctx->paths.prsv_loc; + break; + + case PARTITION_READONLY: + dst = ctx->paths.ro_loc; + break; + + default: + dst = ctx->paths.rw_loc; + } + dst /= partition.data.name; + + if (fs::exists(dst)) + { + return dst; + } + + if (flags == O_RDONLY) + { + dst = fs::path(ctx->paths.ro_loc) / partition.data.name; + assert(fs::exists(dst)); + return dst; + } + + assert(flags == O_RDWR); + auto src = fs::path(ctx->paths.ro_loc) / partition.data.name; + assert(fs::exists(src)); + + MSG_DBG("RWRequest: Didn't find '%s' under '%s', copying from '%s'\n", + partition.data.name, dst.c_str(), src.c_str()); + + dst = ctx->paths.rw_loc; + if (partition.data.user.data[1] & PARTITION_PRESERVED) + { + dst = ctx->paths.prsv_loc; + } + + dst /= partition.data.name; + fs::copy_file(src, dst); + + return dst; +} + +size_t Request::clamp(size_t len) +{ + size_t maxAccess = offset + len; + size_t partSize = partition.data.size << ctx->block_size_shift; + return std::min(maxAccess, partSize) - offset; +} + +void Request::resize(const fs::path &path, size_t len) +{ + size_t maxAccess = offset + len; + size_t fileSize = fs::file_size(path); + if (maxAccess < fileSize) + { + return; + } + MSG_DBG("Resizing %s to %zu bytes\n", path.c_str(), maxAccess); + int rc = truncate(path.c_str(), maxAccess); + if (rc == -1) + { + MSG_ERR("Failed to resize %s: %d\n", path.c_str(), errno); + throw std::system_error(errno, std::system_category()); + } +} + +size_t Request::fulfil(const fs::path &path, int flags, void *buf, size_t len) +{ + if (!(flags == O_RDONLY || flags == O_RDWR)) + { + 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()); + } + + int fd = ::open(path.c_str(), flags); + if (fd == -1) + { + MSG_ERR("Failed to open backing file at '%s': %d\n", + path.c_str(), errno); + throw std::system_error(errno, std::system_category()); + } + + size_t fileSize = fs::file_size(path); + int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0); + auto map = mmap(NULL, fileSize, mprot, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + close(fd); + MSG_ERR("Failed to map backing file '%s' for %zd bytes: %d\n", + path.c_str(), fileSize, errno); + throw std::system_error(errno, std::system_category()); + } + + // copy to the reserved memory area + if (flags == O_RDONLY) + { + memset(buf, 0xff, len); + memcpy(buf, (char *)map + offset, std::min(len, fileSize)); + } + else + { + memcpy((char *)map + offset, buf, len); + set_flash_bytemap(ctx, base + offset, len, FLASH_DIRTY); + } + munmap(map, fileSize); + close(fd); + + return len; +} + +} // namespace virtual_pnor +} // namespace openpower |