blob: 8fe6076c337ce4d3a428aeaa993eaf92dff650fa [file] [log] [blame]
Wyatt Heplerb7609542020-01-24 10:29:54 -08001// 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
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080016#include <cstddef>
17#include <cstdint>
18#include <initializer_list>
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070019#include <span>
Wyatt Heplerb7609542020-01-24 10:29:54 -080020
Wyatt Heplerf298de42021-03-19 15:06:36 -070021#include "pw_assert/assert.h"
Wyatt Hepler1927c282020-02-11 16:45:02 -080022#include "pw_kvs/alignment.h"
Wyatt Hepler2ad60672020-01-21 08:00:16 -080023#include "pw_status/status.h"
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080024#include "pw_status/status_with_size.h"
25
Rob Oliverf61adbd2020-12-09 13:46:46 -050026namespace pw {
27namespace kvs {
Wyatt Hepler2ad60672020-01-21 08:00:16 -080028
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080029enum class PartitionPermission : bool {
30 kReadOnly,
31 kReadAndWrite,
32};
33
Wyatt Heplerb7609542020-01-24 10:29:54 -080034class FlashMemory {
35 public:
36 // The flash address is in the range of: 0 to FlashSize.
37 typedef uint32_t Address;
Armando Montanez28ec2372020-08-17 16:31:41 -070038
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,
Rob Oliverf61adbd2020-12-09 13:46:46 -050045 std::byte erased_memory_content = std::byte(0xFF))
Wyatt Heplerb7609542020-01-24 10:29:54 -080046 : sector_size_(sector_size),
47 flash_sector_count_(sector_count),
48 alignment_(alignment),
49 start_address_(start_address),
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080050 start_sector_(sector_start),
Wyatt Hepler116d1162020-02-06 09:42:59 -080051 erased_memory_content_(erased_memory_content) {
Wyatt Heplerae222dc2020-10-14 10:46:27 -070052 PW_ASSERT(alignment_ != 0u);
Wyatt Hepler116d1162020-02-06 09:42:59 -080053 }
Wyatt Heplerb7609542020-01-24 10:29:54 -080054
Wyatt Hepler2ad60672020-01-21 08:00:16 -080055 virtual ~FlashMemory() = default;
56
Wyatt Heplerb7609542020-01-24 10:29:54 -080057 virtual Status Enable() = 0;
David Rogers907570b2020-08-06 12:44:27 -070058
Wyatt Heplerb7609542020-01-24 10:29:54 -080059 virtual Status Disable() = 0;
David Rogers907570b2020-08-06 12:44:27 -070060
Wyatt Heplerb7609542020-01-24 10:29:54 -080061 virtual bool IsEnabled() const = 0;
David Rogers907570b2020-08-06 12:44:27 -070062
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070063 virtual Status SelfTest() { return Status::Unimplemented(); }
Wyatt Heplerb7609542020-01-24 10:29:54 -080064
65 // Erase num_sectors starting at a given address. Blocking call.
David Rogers907570b2020-08-06 12:44:27 -070066 // Address should be on a sector boundary. Returns:
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080067 //
David Rogers907570b2020-08-06 12:44:27 -070068 // 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
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080072 virtual Status Erase(Address flash_address, size_t num_sectors) = 0;
Wyatt Heplerb7609542020-01-24 10:29:54 -080073
David Rogers907570b2020-08-06 12:44:27 -070074 // Reads bytes from flash into buffer. Blocking call. Returns:
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080075 //
David Rogers907570b2020-08-06 12:44:27 -070076 // OK - success
77 // DEADLINE_EXCEEDED - timeout
78 // OUT_OF_RANGE - write does not fit in the flash memory
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070079 virtual StatusWithSize Read(Address address, std::span<std::byte> output) = 0;
Wyatt Heplerb7609542020-01-24 10:29:54 -080080
Wyatt Heplerbab0e202020-02-04 07:40:08 -080081 StatusWithSize Read(Address address, void* buffer, size_t len) {
Rob Oliverf61adbd2020-12-09 13:46:46 -050082 return Read(address,
83 std::span<std::byte>(static_cast<std::byte*>(buffer), len));
Wyatt Heplerbab0e202020-02-04 07:40:08 -080084 }
85
David Rogers907570b2020-08-06 12:44:27 -070086 // Writes bytes to flash. Blocking call. Returns:
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -080087 //
David Rogers907570b2020-08-06 12:44:27 -070088 // 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
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -080092 virtual StatusWithSize Write(Address destination_flash_address,
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070093 std::span<const std::byte> data) = 0;
Wyatt Heplerb7609542020-01-24 10:29:54 -080094
Alexei Frolovf0c2cdd2020-02-03 15:44:04 -080095 StatusWithSize Write(Address destination_flash_address,
96 const void* data,
97 size_t len) {
Rob Oliverf61adbd2020-12-09 13:46:46 -050098 return Write(
99 destination_flash_address,
100 std::span<const std::byte>(static_cast<const std::byte*>(data), len));
Alexei Frolovf0c2cdd2020-02-03 15:44:04 -0800101 }
102
Wyatt Heplerb7609542020-01-24 10:29:54 -0800103 // 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.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800105 virtual std::byte* FlashAddressToMcuAddress(Address) const { return nullptr; }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800106
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800107 // start_sector() is useful for FlashMemory instances where the
Wyatt Heplerb7609542020-01-24 10:29:54 -0800108 // sector start is not 0. (ex.: cases where there are portions of flash
109 // that should be handled independently).
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800110 constexpr uint32_t start_sector() const { return start_sector_; }
David Rogers907570b2020-08-06 12:44:27 -0700111
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800112 constexpr size_t sector_size_bytes() const { return sector_size_; }
David Rogers907570b2020-08-06 12:44:27 -0700113
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800114 constexpr size_t sector_count() const { return flash_sector_count_; }
David Rogers907570b2020-08-06 12:44:27 -0700115
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800116 constexpr size_t alignment_bytes() const { return alignment_; }
David Rogers907570b2020-08-06 12:44:27 -0700117
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800118 constexpr size_t size_bytes() const {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800119 return sector_size_ * flash_sector_count_;
120 }
David Rogers907570b2020-08-06 12:44:27 -0700121
Wyatt Heplerb7609542020-01-24 10:29:54 -0800122 // Address of the start of flash (the address of sector 0)
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800123 constexpr uint32_t start_address() const { return start_address_; }
David Rogers907570b2020-08-06 12:44:27 -0700124
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800125 constexpr std::byte erased_memory_content() const {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800126 return erased_memory_content_;
127 }
128
129 private:
130 const uint32_t sector_size_;
131 const uint32_t flash_sector_count_;
David Rogersca592962020-07-01 09:21:54 -0700132 const uint32_t alignment_;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800133 const uint32_t start_address_;
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800134 const uint32_t start_sector_;
135 const std::byte erased_memory_content_;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800136};
137
Wyatt Heplerb7609542020-01-24 10:29:54 -0800138class FlashPartition {
139 public:
140 // The flash address is in the range of: 0 to PartitionSize.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800141 using Address = uint32_t;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800142
Wyatt Hepler1927c282020-02-11 16:45:02 -0800143 // 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
Wyatt Hepleree6fd762020-03-09 08:32:19 -0700149 private:
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700150 StatusWithSize DoWrite(std::span<const std::byte> data) override;
Wyatt Hepleree6fd762020-03-09 08:32:19 -0700151
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) {}
Wyatt Hepler1927c282020-02-11 16:45:02 -0800161
162 private:
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700163 StatusWithSize DoRead(std::span<std::byte> data) override;
Wyatt Hepleree6fd762020-03-09 08:32:19 -0700164
Wyatt Hepler1927c282020-02-11 16:45:02 -0800165 FlashPartition& flash_;
166 FlashPartition::Address address_;
167 };
168
Armando Montanez28ec2372020-08-17 16:31:41 -0700169 FlashPartition(
Wyatt Heplerb7609542020-01-24 10:29:54 -0800170 FlashMemory* flash,
171 uint32_t start_sector_index,
172 uint32_t sector_count,
Wyatt Hepler116d1162020-02-06 09:42:59 -0800173 uint32_t alignment_bytes = 0, // Defaults to flash alignment
Paul Mathieu9a9ed132020-10-12 19:15:34 -0700174 PartitionPermission permission = PartitionPermission::kReadAndWrite);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800175
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -0800176 // Creates a FlashPartition that uses the entire flash with its alignment.
Armando Montanez28ec2372020-08-17 16:31:41 -0700177 FlashPartition(FlashMemory* flash)
Wyatt Heplercdd6dfc2020-02-18 12:04:04 -0800178 : FlashPartition(
179 flash, 0, flash->sector_count(), flash->alignment_bytes()) {}
180
Ewout van Bekkum6ee135f2020-08-07 09:38:49 -0700181 FlashPartition(FlashPartition&&) = default;
Wyatt Heplere541e072020-02-14 09:10:53 -0800182 FlashPartition(const FlashPartition&) = delete;
183 FlashPartition& operator=(const FlashPartition&) = delete;
184
Wyatt Hepler2ad60672020-01-21 08:00:16 -0800185 virtual ~FlashPartition() = default;
186
Alexei Frolovd5aa1c02020-02-03 17:23:51 -0800187 // Performs any required partition or flash-level initialization.
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800188 virtual Status Init() { return OkStatus(); }
Alexei Frolovd5aa1c02020-02-03 17:23:51 -0800189
Wyatt Heplerb7609542020-01-24 10:29:54 -0800190 // Erase num_sectors starting at a given address. Blocking call.
David Rogers907570b2020-08-06 12:44:27 -0700191 // Address must be on a sector boundary. Returns:
192 //
193 // OK - success.
194 // TIMEOUT - on timeout.
195 // INVALID_ARGUMENT - address or sector count is invalid.
196 // PERMISSION_DENIED - partition is read only.
197 // UNKNOWN - HAL error
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800198 virtual Status Erase(Address address, size_t num_sectors);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800199
Keir Mierle8c352dc2020-02-02 13:58:19 -0800200 Status Erase() { return Erase(0, this->sector_count()); }
201
David Rogers907570b2020-08-06 12:44:27 -0700202 // Reads bytes from flash into buffer. Blocking call. Returns:
203 //
204 // OK - success.
205 // TIMEOUT - on timeout.
206 // INVALID_ARGUMENT - address or length is invalid.
207 // UNKNOWN - HAL error
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700208 virtual StatusWithSize Read(Address address, std::span<std::byte> output);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800209
210 StatusWithSize Read(Address address, size_t length, void* output) {
Rob Oliverf61adbd2020-12-09 13:46:46 -0500211 return Read(address,
212 std::span<std::byte>(static_cast<std::byte*>(output), length));
Wyatt Heplerb7609542020-01-24 10:29:54 -0800213 }
214
David Rogers907570b2020-08-06 12:44:27 -0700215 // Writes bytes to flash. Address and data.size_bytes() must both be a
216 // multiple of alignment_bytes(). Blocking call. Returns:
217 //
218 // OK - success.
219 // TIMEOUT - on timeout.
220 // INVALID_ARGUMENT - address or length is invalid.
221 // PERMISSION_DENIED - partition is read only.
222 // UNKNOWN - HAL error
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700223 virtual StatusWithSize Write(Address address,
224 std::span<const std::byte> data);
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800225
David Rogers6a6dae62020-07-10 01:13:38 -0700226 // Check to see if chunk of flash partition is erased. Address and len need to
David Rogers907570b2020-08-06 12:44:27 -0700227 // be aligned with FlashMemory. Returns:
228 //
229 // OK - success.
230 // TIMEOUT - on timeout.
231 // INVALID_ARGUMENT - address or length is invalid.
232 // UNKNOWN - HAL error
Wyatt Heplere3288e12020-02-26 13:05:07 -0800233 // TODO: Result<bool>
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800234 virtual Status IsRegionErased(Address source_flash_address,
David Rogers3f12bff2021-04-13 21:59:26 -0700235 size_t length,
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800236 bool* is_erased);
Wyatt Heplerb7609542020-01-24 10:29:54 -0800237
David Rogers6a6dae62020-07-10 01:13:38 -0700238 // Check if the entire partition is erased.
239 // Returns: same as IsRegionErased().
240 Status IsErased(bool* is_erased) {
241 return IsRegionErased(0, this->size_bytes(), is_erased);
242 }
243
Wyatt Heplere541e072020-02-14 09:10:53 -0800244 // Checks to see if the data appears to be erased. No reads or writes occur;
245 // the FlashPartition simply compares the data to
246 // flash_.erased_memory_content().
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700247 bool AppearsErased(std::span<const std::byte> data) const;
Wyatt Heplere541e072020-02-14 09:10:53 -0800248
David Rogersa12786b2020-01-31 16:02:33 -0800249 // Overridden by derived classes. The reported sector size is space available
250 // to users of FlashPartition. It accounts for space reserved in the sector
251 // for FlashPartition to store metadata.
Keir Mierle8c352dc2020-02-02 13:58:19 -0800252 virtual size_t sector_size_bytes() const {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800253 return flash_.sector_size_bytes();
Wyatt Heplerb7609542020-01-24 10:29:54 -0800254 }
255
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800256 size_t size_bytes() const { return sector_count() * sector_size_bytes(); }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800257
David Rogers907570b2020-08-06 12:44:27 -0700258 // Alignment required for write address and write size.
Wyatt Hepler116d1162020-02-06 09:42:59 -0800259 size_t alignment_bytes() const { return alignment_bytes_; }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800260
Wyatt Hepler116d1162020-02-06 09:42:59 -0800261 size_t sector_count() const { return sector_count_; }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800262
263 // Convert a FlashMemory::Address to an MCU pointer, this can be used for
264 // memory mapped reads. Return NULL if the memory is not memory mapped.
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800265 std::byte* PartitionAddressToMcuAddress(Address address) const {
Wyatt Heplerb7609542020-01-24 10:29:54 -0800266 return flash_.FlashAddressToMcuAddress(PartitionToFlashAddress(address));
267 }
268
Alexei Frolov82dae2d2020-01-31 17:36:41 -0800269 // Converts an address from the partition address space to the flash address
270 // space. If the partition reserves additional space in the sector, the flash
271 // address space may not be contiguous, and this conversion accounts for that.
272 virtual FlashMemory::Address PartitionToFlashAddress(Address address) const {
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800273 return flash_.start_address() +
274 (start_sector_index_ - flash_.start_sector()) * sector_size_bytes() +
Wyatt Heplerb7609542020-01-24 10:29:54 -0800275 address;
276 }
277
Alexei Frolovcb7ae1a2020-02-03 15:00:05 -0800278 bool writable() const {
279 return permission_ == PartitionPermission::kReadAndWrite;
280 }
281
David Rogersd833dff2020-09-22 13:10:25 -0700282 constexpr std::byte erased_memory_content() const {
283 return flash_.erased_memory_content();
284 }
285
Alexei Frolovda95eda2020-02-03 16:40:12 -0800286 uint32_t start_sector_index() const { return start_sector_index_; }
287
Wyatt Heplerb7609542020-01-24 10:29:54 -0800288 protected:
Wyatt Hepler4da1fcb2020-01-30 17:32:18 -0800289 Status CheckBounds(Address address, size_t len) const;
David Rogers907570b2020-08-06 12:44:27 -0700290
Alexei Frolovcb7ae1a2020-02-03 15:00:05 -0800291 FlashMemory& flash() const { return flash_; }
Wyatt Heplerb7609542020-01-24 10:29:54 -0800292
293 private:
294 FlashMemory& flash_;
295 const uint32_t start_sector_index_;
296 const uint32_t sector_count_;
Wyatt Hepler116d1162020-02-06 09:42:59 -0800297 const uint32_t alignment_bytes_;
Wyatt Heplerb7609542020-01-24 10:29:54 -0800298 const PartitionPermission permission_;
299};
300
Rob Oliverf61adbd2020-12-09 13:46:46 -0500301} // namespace kvs
Alexei Frolov5a0450d2020-10-28 21:10:47 -0700302} // namespace pw