xref: /openbmc/phosphor-mboxd/vpnor/pnor_partition.hpp (revision 30bcf84c932a579532e5f8417af549494e11b6e9)
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