1 /* SPDX-License-Identifier: Apache-2.0 */ 2 /* Copyright (C) 2018 IBM Corp. */ 3 #pragma once 4 5 extern "C" { 6 #include "mbox.h" 7 }; 8 9 #include "mboxd_pnor_partition_table.h" 10 #include "pnor_partition_table.hpp" 11 #include <fcntl.h> 12 #include <string> 13 #include <unistd.h> 14 #include <experimental/filesystem> 15 16 namespace openpower 17 { 18 namespace virtual_pnor 19 { 20 21 namespace fs = std::experimental::filesystem; 22 23 class Request 24 { 25 public: 26 /** @brief Construct a flash access request 27 * 28 * @param[in] ctx - The mbox context used to process the request 29 * @param[in] offset - The absolute offset into the flash device as 30 * provided by the mbox message associated with the 31 * request 32 * 33 * The class does not take ownership of the ctx pointer. The lifetime of 34 * the ctx pointer must strictly exceed the lifetime of the class 35 * instance. 36 */ 37 Request(struct mbox_context* ctx, size_t offset) : 38 ctx(ctx), partition(ctx->vpnor->table->partition(offset)), 39 base(partition.data.base << ctx->block_size_shift), 40 offset(offset - base) 41 { 42 } 43 Request(const Request&) = delete; 44 Request& operator=(const Request&) = delete; 45 Request(Request&&) = default; 46 Request& operator=(Request&&) = default; 47 ~Request() = default; 48 49 ssize_t read(void* dst, size_t len) 50 { 51 len = clamp(len); 52 constexpr auto flags = O_RDONLY; 53 fs::path path = getPartitionFilePath(flags); 54 return fulfil(path, flags, dst, len); 55 } 56 57 ssize_t write(void* dst, size_t len) 58 { 59 if (len != clamp(len)) 60 { 61 std::stringstream err; 62 err << "Request size 0x" << std::hex << len << " from offset 0x" 63 << std::hex << offset << " exceeds the partition size 0x" 64 << std::hex << (partition.data.size << ctx->block_size_shift); 65 throw OutOfBoundsOffset(err.str()); 66 } 67 constexpr auto flags = O_RDWR; 68 /* Ensure file is at least the size of the maximum access */ 69 fs::path path = getPartitionFilePath(flags); 70 resize(path, len); 71 return fulfil(path, flags, dst, len); 72 } 73 74 private: 75 /** @brief Clamp the access length to the maximum supported by the ToC */ 76 size_t clamp(size_t len); 77 78 /** @brief Ensure the backing file is sized appropriately for the access 79 * 80 * We need to ensure the file is big enough to satisfy the request so that 81 * mmap() will succeed for the required size. 82 * 83 * @return The valid access length 84 * 85 * Throws: std::system_error 86 */ 87 void resize(const std::experimental::filesystem::path& path, size_t len); 88 89 /** @brief Returns the partition file path associated with the offset. 90 * 91 * The search strategy for the partition file depends on the value of the 92 * flags parameter. 93 * 94 * For the O_RDONLY case: 95 * 96 * 1. Depending on the partition type,tries to open the file 97 * from the associated partition(RW/PRSV/RO). 98 * 1a. if file not found in the corresponding 99 * partition(RW/PRSV/RO) then tries to read the file from 100 * the read only partition. 101 * 1b. if the file not found in the read only partition then 102 * throw exception. 103 * 104 * For the O_RDWR case: 105 * 106 * 1. Depending on the partition type tries to open the file 107 * from the associated partition. 108 * 1a. if file not found in the corresponding partition(RW/PRSV) 109 * then copy the file from the read only partition to the (RW/PRSV) 110 * partition depending on the partition type. 111 * 1b. if the file not found in the read only partition then throw 112 * exception. 113 * 114 * @param[in] flags - The flags that will be used to open the file. Must 115 * be one of O_RDONLY or O_RDWR. 116 * 117 * Post-condition: The file described by the returned path exists 118 * 119 * Throws: std::filesystem_error, std::bad_alloc 120 */ 121 std::experimental::filesystem::path getPartitionFilePath(int flags); 122 123 /** @brief Fill dst with the content of the partition relative to offset. 124 * 125 * @param[in] offset - The pnor offset(bytes). 126 * @param[out] dst - The buffer to fill with partition data 127 * @param[in] len - The length of the destination buffer 128 */ 129 size_t fulfil(const std::experimental::filesystem::path& path, int flags, 130 void* dst, size_t len); 131 132 struct mbox_context* ctx; 133 const pnor_partition& partition; 134 size_t base; 135 size_t offset; 136 }; 137 138 } // namespace virtual_pnor 139 } // namespace openpower 140