Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_kvs / public / pw_kvs / flash_memory.h
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <cstddef>
17 #include <cstdint>
18 #include <initializer_list>
19 #include <span>
20
21 #include "pw_assert/light.h"
22 #include "pw_kvs/alignment.h"
23 #include "pw_status/status.h"
24 #include "pw_status/status_with_size.h"
25
26 namespace pw {
27 namespace kvs {
28
29 enum class PartitionPermission : bool {
30   kReadOnly,
31   kReadAndWrite,
32 };
33
34 class FlashMemory {
35  public:
36   // The flash address is in the range of: 0 to FlashSize.
37   typedef uint32_t Address;
38
39   // TODO(pwbug/246): This can be constexpr when tokenized asserts are fixed.
40   FlashMemory(size_t sector_size,
41               size_t sector_count,
42               size_t alignment,
43               uint32_t start_address = 0,
44               uint32_t sector_start = 0,
45               std::byte erased_memory_content = std::byte(0xFF))
46       : sector_size_(sector_size),
47         flash_sector_count_(sector_count),
48         alignment_(alignment),
49         start_address_(start_address),
50         start_sector_(sector_start),
51         erased_memory_content_(erased_memory_content) {
52     PW_ASSERT(alignment_ != 0u);
53   }
54
55   virtual ~FlashMemory() = default;
56
57   virtual Status Enable() = 0;
58
59   virtual Status Disable() = 0;
60
61   virtual bool IsEnabled() const = 0;
62
63   virtual Status SelfTest() { return Status::Unimplemented(); }
64
65   // Erase num_sectors starting at a given address. Blocking call.
66   // Address should be on a sector boundary. Returns:
67   //
68   // OK - success
69   // DEADLINE_EXCEEDED - timeout
70   // INVALID_ARGUMENT - address is not sector-aligned
71   // OUT_OF_RANGE - erases past the end of the memory
72   virtual Status Erase(Address flash_address, size_t num_sectors) = 0;
73
74   // Reads bytes from flash into buffer. Blocking call. Returns:
75   //
76   // OK - success
77   // DEADLINE_EXCEEDED - timeout
78   // OUT_OF_RANGE - write does not fit in the flash memory
79   virtual StatusWithSize Read(Address address, std::span<std::byte> output) = 0;
80
81   StatusWithSize Read(Address address, void* buffer, size_t len) {
82     return Read(address,
83                 std::span<std::byte>(static_cast<std::byte*>(buffer), len));
84   }
85
86   // Writes bytes to flash. Blocking call. Returns:
87   //
88   // OK - success
89   // DEADLINE_EXCEEDED - timeout
90   // INVALID_ARGUMENT - address or data size are not aligned
91   // OUT_OF_RANGE - write does not fit in the memory
92   virtual StatusWithSize Write(Address destination_flash_address,
93                                std::span<const std::byte> data) = 0;
94
95   StatusWithSize Write(Address destination_flash_address,
96                        const void* data,
97                        size_t len) {
98     return Write(
99         destination_flash_address,
100         std::span<const std::byte>(static_cast<const std::byte*>(data), len));
101   }
102
103   // Convert an Address to an MCU pointer, this can be used for memory
104   // mapped reads. Return NULL if the memory is not memory mapped.
105   virtual std::byte* FlashAddressToMcuAddress(Address) const { return nullptr; }
106
107   // start_sector() is useful for FlashMemory instances where the
108   // sector start is not 0. (ex.: cases where there are portions of flash
109   // that should be handled independently).
110   constexpr uint32_t start_sector() const { return start_sector_; }
111
112   constexpr size_t sector_size_bytes() const { return sector_size_; }
113
114   constexpr size_t sector_count() const { return flash_sector_count_; }
115
116   constexpr size_t alignment_bytes() const { return alignment_; }
117
118   constexpr size_t size_bytes() const {
119     return sector_size_ * flash_sector_count_;
120   }
121
122   // Address of the start of flash (the address of sector 0)
123   constexpr uint32_t start_address() const { return start_address_; }
124
125   constexpr std::byte erased_memory_content() const {
126     return erased_memory_content_;
127   }
128
129  private:
130   const uint32_t sector_size_;
131   const uint32_t flash_sector_count_;
132   const uint32_t alignment_;
133   const uint32_t start_address_;
134   const uint32_t start_sector_;
135   const std::byte erased_memory_content_;
136 };
137
138 class FlashPartition {
139  public:
140   // The flash address is in the range of: 0 to PartitionSize.
141   using Address = uint32_t;
142
143   // Implement Output for the Write method.
144   class Output final : public pw::Output {
145    public:
146     constexpr Output(FlashPartition& flash, FlashPartition::Address address)
147         : flash_(flash), address_(address) {}
148
149    private:
150     StatusWithSize DoWrite(std::span<const std::byte> data) override;
151
152     FlashPartition& flash_;
153     FlashPartition::Address address_;
154   };
155
156   // Implement Input for the Read method.
157   class Input final : public pw::Input {
158    public:
159     constexpr Input(FlashPartition& flash, FlashPartition::Address address)
160         : flash_(flash), address_(address) {}
161
162    private:
163     StatusWithSize DoRead(std::span<std::byte> data) override;
164
165     FlashPartition& flash_;
166     FlashPartition::Address address_;
167   };
168
169   // TODO(pwbug/246): This can be constexpr when tokenized asserts are fixed.
170   FlashPartition(
171       FlashMemory* flash,
172       uint32_t start_sector_index,
173       uint32_t sector_count,
174       uint32_t alignment_bytes = 0,  // Defaults to flash alignment
175       PartitionPermission permission = PartitionPermission::kReadAndWrite);
176
177   // Creates a FlashPartition that uses the entire flash with its alignment.
178   // TODO(pwbug/246): This can be constexpr when tokenized asserts are fixed.
179   FlashPartition(FlashMemory* flash)
180       : FlashPartition(
181             flash, 0, flash->sector_count(), flash->alignment_bytes()) {}
182
183   FlashPartition(FlashPartition&&) = default;
184   FlashPartition(const FlashPartition&) = delete;
185   FlashPartition& operator=(const FlashPartition&) = delete;
186
187   virtual ~FlashPartition() = default;
188
189   // Performs any required partition or flash-level initialization.
190   virtual Status Init() { return OkStatus(); }
191
192   // Erase num_sectors starting at a given address. Blocking call.
193   // Address must be on a sector boundary. Returns:
194   //
195   // OK - success.
196   // TIMEOUT - on timeout.
197   // INVALID_ARGUMENT - address or sector count is invalid.
198   // PERMISSION_DENIED - partition is read only.
199   // UNKNOWN - HAL error
200   virtual Status Erase(Address address, size_t num_sectors);
201
202   Status Erase() { return Erase(0, this->sector_count()); }
203
204   // Reads bytes from flash into buffer. Blocking call. Returns:
205   //
206   // OK - success.
207   // TIMEOUT - on timeout.
208   // INVALID_ARGUMENT - address or length is invalid.
209   // UNKNOWN - HAL error
210   virtual StatusWithSize Read(Address address, std::span<std::byte> output);
211
212   StatusWithSize Read(Address address, size_t length, void* output) {
213     return Read(address,
214                 std::span<std::byte>(static_cast<std::byte*>(output), length));
215   }
216
217   // Writes bytes to flash. Address and data.size_bytes() must both be a
218   // multiple of alignment_bytes(). Blocking call. Returns:
219   //
220   // OK - success.
221   // TIMEOUT - on timeout.
222   // INVALID_ARGUMENT - address or length is invalid.
223   // PERMISSION_DENIED - partition is read only.
224   // UNKNOWN - HAL error
225   virtual StatusWithSize Write(Address address,
226                                std::span<const std::byte> data);
227
228   // Check to see if chunk of flash partition is erased. Address and len need to
229   // be aligned with FlashMemory. Returns:
230   //
231   // OK - success.
232   // TIMEOUT - on timeout.
233   // INVALID_ARGUMENT - address or length is invalid.
234   // UNKNOWN - HAL error
235   // TODO: Result<bool>
236   virtual Status IsRegionErased(Address source_flash_address,
237                                 size_t len,
238                                 bool* is_erased);
239
240   // Check if the entire partition is erased.
241   // Returns: same as IsRegionErased().
242   Status IsErased(bool* is_erased) {
243     return IsRegionErased(0, this->size_bytes(), is_erased);
244   }
245
246   // Checks to see if the data appears to be erased. No reads or writes occur;
247   // the FlashPartition simply compares the data to
248   // flash_.erased_memory_content().
249   bool AppearsErased(std::span<const std::byte> data) const;
250
251   // Overridden by derived classes. The reported sector size is space available
252   // to users of FlashPartition. It accounts for space reserved in the sector
253   // for FlashPartition to store metadata.
254   virtual size_t sector_size_bytes() const {
255     return flash_.sector_size_bytes();
256   }
257
258   size_t size_bytes() const { return sector_count() * sector_size_bytes(); }
259
260   // Alignment required for write address and write size.
261   size_t alignment_bytes() const { return alignment_bytes_; }
262
263   size_t sector_count() const { return sector_count_; }
264
265   // Convert a FlashMemory::Address to an MCU pointer, this can be used for
266   // memory mapped reads. Return NULL if the memory is not memory mapped.
267   std::byte* PartitionAddressToMcuAddress(Address address) const {
268     return flash_.FlashAddressToMcuAddress(PartitionToFlashAddress(address));
269   }
270
271   // Converts an address from the partition address space to the flash address
272   // space. If the partition reserves additional space in the sector, the flash
273   // address space may not be contiguous, and this conversion accounts for that.
274   virtual FlashMemory::Address PartitionToFlashAddress(Address address) const {
275     return flash_.start_address() +
276            (start_sector_index_ - flash_.start_sector()) * sector_size_bytes() +
277            address;
278   }
279
280   bool writable() const {
281     return permission_ == PartitionPermission::kReadAndWrite;
282   }
283
284   constexpr std::byte erased_memory_content() const {
285     return flash_.erased_memory_content();
286   }
287
288   uint32_t start_sector_index() const { return start_sector_index_; }
289
290  protected:
291   Status CheckBounds(Address address, size_t len) const;
292
293   FlashMemory& flash() const { return flash_; }
294
295  private:
296   FlashMemory& flash_;
297   const uint32_t start_sector_index_;
298   const uint32_t sector_count_;
299   const uint32_t alignment_bytes_;
300   const PartitionPermission permission_;
301 };
302
303 }  // namespace kvs
304 }  // namespace pw