1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
18 #include <initializer_list>
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"
29 enum class PartitionPermission : bool {
36 // The flash address is in the range of: 0 to FlashSize.
37 typedef uint32_t Address;
39 // TODO(pwbug/246): This can be constexpr when tokenized asserts are fixed.
40 FlashMemory(size_t sector_size,
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);
55 virtual ~FlashMemory() = default;
57 virtual Status Enable() = 0;
59 virtual Status Disable() = 0;
61 virtual bool IsEnabled() const = 0;
63 virtual Status SelfTest() { return Status::Unimplemented(); }
65 // Erase num_sectors starting at a given address. Blocking call.
66 // Address should be on a sector boundary. Returns:
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;
74 // Reads bytes from flash into buffer. Blocking call. Returns:
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;
81 StatusWithSize Read(Address address, void* buffer, size_t len) {
83 std::span<std::byte>(static_cast<std::byte*>(buffer), len));
86 // Writes bytes to flash. Blocking call. Returns:
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;
95 StatusWithSize Write(Address destination_flash_address,
99 destination_flash_address,
100 std::span<const std::byte>(static_cast<const std::byte*>(data), len));
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; }
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_; }
112 constexpr size_t sector_size_bytes() const { return sector_size_; }
114 constexpr size_t sector_count() const { return flash_sector_count_; }
116 constexpr size_t alignment_bytes() const { return alignment_; }
118 constexpr size_t size_bytes() const {
119 return sector_size_ * flash_sector_count_;
122 // Address of the start of flash (the address of sector 0)
123 constexpr uint32_t start_address() const { return start_address_; }
125 constexpr std::byte erased_memory_content() const {
126 return erased_memory_content_;
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_;
138 class FlashPartition {
140 // The flash address is in the range of: 0 to PartitionSize.
141 using Address = uint32_t;
143 // Implement Output for the Write method.
144 class Output final : public pw::Output {
146 constexpr Output(FlashPartition& flash, FlashPartition::Address address)
147 : flash_(flash), address_(address) {}
150 StatusWithSize DoWrite(std::span<const std::byte> data) override;
152 FlashPartition& flash_;
153 FlashPartition::Address address_;
156 // Implement Input for the Read method.
157 class Input final : public pw::Input {
159 constexpr Input(FlashPartition& flash, FlashPartition::Address address)
160 : flash_(flash), address_(address) {}
163 StatusWithSize DoRead(std::span<std::byte> data) override;
165 FlashPartition& flash_;
166 FlashPartition::Address address_;
169 // TODO(pwbug/246): This can be constexpr when tokenized asserts are fixed.
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);
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)
181 flash, 0, flash->sector_count(), flash->alignment_bytes()) {}
183 FlashPartition(FlashPartition&&) = default;
184 FlashPartition(const FlashPartition&) = delete;
185 FlashPartition& operator=(const FlashPartition&) = delete;
187 virtual ~FlashPartition() = default;
189 // Performs any required partition or flash-level initialization.
190 virtual Status Init() { return OkStatus(); }
192 // Erase num_sectors starting at a given address. Blocking call.
193 // Address must be on a sector boundary. Returns:
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);
202 Status Erase() { return Erase(0, this->sector_count()); }
204 // Reads bytes from flash into buffer. Blocking call. Returns:
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);
212 StatusWithSize Read(Address address, size_t length, void* output) {
214 std::span<std::byte>(static_cast<std::byte*>(output), length));
217 // Writes bytes to flash. Address and data.size_bytes() must both be a
218 // multiple of alignment_bytes(). Blocking call. Returns:
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);
228 // Check to see if chunk of flash partition is erased. Address and len need to
229 // be aligned with FlashMemory. Returns:
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,
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);
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;
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();
258 size_t size_bytes() const { return sector_count() * sector_size_bytes(); }
260 // Alignment required for write address and write size.
261 size_t alignment_bytes() const { return alignment_bytes_; }
263 size_t sector_count() const { return sector_count_; }
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));
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() +
280 bool writable() const {
281 return permission_ == PartitionPermission::kReadAndWrite;
284 constexpr std::byte erased_memory_content() const {
285 return flash_.erased_memory_content();
288 uint32_t start_sector_index() const { return start_sector_index_; }
291 Status CheckBounds(Address address, size_t len) const;
293 FlashMemory& flash() const { return flash_; }
297 const uint32_t start_sector_index_;
298 const uint32_t sector_count_;
299 const uint32_t alignment_bytes_;
300 const PartitionPermission permission_;