| /* SPDX-License-Identifier: Apache-2.0 */ |
| /* Copyright (C) 2018 IBM Corp. */ |
| #pragma once |
| |
| extern "C" { |
| #include "backend.h" |
| #include "vpnor/backend.h" |
| }; |
| |
| #include "pnor_partition_table.hpp" |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include <experimental/filesystem> |
| #include <string> |
| |
| namespace openpower |
| { |
| namespace virtual_pnor |
| { |
| |
| namespace fs = std::experimental::filesystem; |
| |
| class Request |
| { |
| public: |
| /** @brief Construct a flash access request |
| * |
| * @param[in] backend - The backend context used to process the request |
| * @param[in] offset - The absolute offset into the flash device as |
| * provided by the mbox message associated with the |
| * request |
| * |
| * The class does not take ownership of the ctx pointer. The lifetime of |
| * the ctx pointer must strictly exceed the lifetime of the class |
| * instance. |
| */ |
| Request(struct backend* backend, size_t offset) : |
| backend(backend), partition(((struct vpnor_data*)backend->priv) |
| ->vpnor->table->partition(offset)), |
| base(partition.data.base << backend->block_size_shift), |
| offset(offset - base) |
| { |
| } |
| Request(const Request&) = delete; |
| Request& operator=(const Request&) = delete; |
| Request(Request&&) = default; |
| Request& operator=(Request&&) = default; |
| ~Request() = default; |
| |
| ssize_t read(void* dst, size_t len) |
| { |
| len = clamp(len); |
| constexpr auto flags = O_RDONLY; |
| fs::path path = getPartitionFilePath(flags); |
| return fulfil(path, flags, dst, len); |
| } |
| |
| ssize_t write(void* dst, size_t len) |
| { |
| if (len != clamp(len)) |
| { |
| 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.size << backend->block_size_shift); |
| throw OutOfBoundsOffset(err.str()); |
| } |
| constexpr auto flags = O_RDWR; |
| /* Ensure file is at least the size of the maximum access */ |
| fs::path path = getPartitionFilePath(flags); |
| resize(path, len); |
| return fulfil(path, flags, dst, len); |
| } |
| |
| private: |
| /** @brief Clamp the access length to the maximum supported by the ToC */ |
| size_t clamp(size_t len); |
| |
| /** @brief Ensure the backing file is sized appropriately for the access |
| * |
| * We need to ensure the file is big enough to satisfy the request so that |
| * mmap() will succeed for the required size. |
| * |
| * @return The valid access length |
| * |
| * Throws: std::system_error |
| */ |
| void resize(const std::experimental::filesystem::path& path, size_t len); |
| |
| /** @brief Returns the partition file path associated with the offset. |
| * |
| * The search strategy for the partition file depends on the value of the |
| * flags parameter. |
| * |
| * For the O_RDONLY case: |
| * |
| * 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. |
| * |
| * For the O_RDWR case: |
| * |
| * 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] flags - The flags that will be used to open the file. Must |
| * be one of O_RDONLY or O_RDWR. |
| * |
| * Post-condition: The file described by the returned path exists |
| * |
| * Throws: std::filesystem_error, std::bad_alloc |
| */ |
| std::experimental::filesystem::path getPartitionFilePath(int flags); |
| |
| /** @brief Fill dst with the content of the partition relative to offset. |
| * |
| * @param[in] offset - The pnor offset(bytes). |
| * @param[out] dst - The buffer to fill with partition data |
| * @param[in] len - The length of the destination buffer |
| */ |
| size_t fulfil(const std::experimental::filesystem::path& path, int flags, |
| void* dst, size_t len); |
| |
| struct backend* backend; |
| const pnor_partition& partition; |
| size_t base; |
| size_t offset; |
| }; |
| |
| } // namespace virtual_pnor |
| } // namespace openpower |