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