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 <limits> 20 21 #include "pw_assert/assert.h" 22 #include "pw_kvs/alignment.h" 23 #include "pw_polyfill/standard.h" 24 #include "pw_span/span.h" 25 #include "pw_status/status.h" 26 #include "pw_status/status_with_size.h" 27 28 #if PW_CXX_STANDARD_IS_SUPPORTED(17) // Requires C++17 for pw::Result 29 #include "pw_stream/seek.h" 30 #include "pw_stream/stream.h" 31 #endif // PW_CXX_STANDARD_IS_SUPPORTED(17) 32 33 namespace pw { 34 namespace kvs { 35 36 enum class PartitionPermission : bool { 37 kReadOnly, 38 kReadAndWrite, 39 }; 40 41 class FlashMemory { 42 public: 43 // The flash address is in the range of: 0 to FlashSize. 44 typedef uint32_t Address; 45 46 // TODO: b/235149326 - This can be constexpr when tokenized asserts are fixed. 47 FlashMemory(size_t sector_size, 48 size_t sector_count, 49 size_t alignment, 50 uint32_t start_address = 0, 51 uint32_t sector_start = 0, 52 std::byte erased_memory_content = std::byte(0xFF)) sector_size_(sector_size)53 : sector_size_(sector_size), 54 flash_sector_count_(sector_count), 55 alignment_(alignment), 56 start_address_(start_address), 57 start_sector_(sector_start), 58 erased_memory_content_(erased_memory_content) { 59 PW_ASSERT(alignment_ != 0u); 60 } 61 62 virtual ~FlashMemory() = default; 63 64 virtual Status Enable() = 0; 65 66 virtual Status Disable() = 0; 67 68 virtual bool IsEnabled() const = 0; 69 SelfTest()70 virtual Status SelfTest() { return Status::Unimplemented(); } 71 72 // Erase num_sectors starting at a given address. Blocking call. 73 // Address should be on a sector boundary. Returns: 74 // 75 // OK - success 76 // DEADLINE_EXCEEDED - timeout 77 // INVALID_ARGUMENT - address is not sector-aligned 78 // OUT_OF_RANGE - erases past the end of the memory 79 virtual Status Erase(Address flash_address, size_t num_sectors) = 0; 80 81 // Reads bytes from flash into buffer. Blocking call. Returns: 82 // 83 // OK - success 84 // DEADLINE_EXCEEDED - timeout 85 // OUT_OF_RANGE - write does not fit in the flash memory 86 virtual StatusWithSize Read(Address address, span<std::byte> output) = 0; 87 Read(Address address,void * buffer,size_t len)88 StatusWithSize Read(Address address, void* buffer, size_t len) { 89 return Read(address, span<std::byte>(static_cast<std::byte*>(buffer), len)); 90 } 91 92 // Writes bytes to flash. Blocking call. Returns: 93 // 94 // OK - success 95 // DEADLINE_EXCEEDED - timeout 96 // INVALID_ARGUMENT - address or data size are not aligned 97 // OUT_OF_RANGE - write does not fit in the memory 98 virtual StatusWithSize Write(Address destination_flash_address, 99 span<const std::byte> data) = 0; 100 Write(Address destination_flash_address,const void * data,size_t len)101 StatusWithSize Write(Address destination_flash_address, 102 const void* data, 103 size_t len) { 104 return Write( 105 destination_flash_address, 106 span<const std::byte>(static_cast<const std::byte*>(data), len)); 107 } 108 109 // Convert an Address to an MCU pointer, this can be used for memory 110 // mapped reads. Return NULL if the memory is not memory mapped. FlashAddressToMcuAddress(Address)111 virtual std::byte* FlashAddressToMcuAddress(Address) const { return nullptr; } 112 113 // start_sector() is useful for FlashMemory instances where the 114 // sector start is not 0. (ex.: cases where there are portions of flash 115 // that should be handled independently). start_sector()116 constexpr uint32_t start_sector() const { return start_sector_; } 117 sector_size_bytes()118 constexpr size_t sector_size_bytes() const { return sector_size_; } 119 sector_count()120 constexpr size_t sector_count() const { return flash_sector_count_; } 121 alignment_bytes()122 constexpr size_t alignment_bytes() const { return alignment_; } 123 size_bytes()124 constexpr size_t size_bytes() const { 125 return sector_size_ * flash_sector_count_; 126 } 127 128 // Address of the start of flash (the address of sector 0) start_address()129 constexpr uint32_t start_address() const { return start_address_; } 130 erased_memory_content()131 constexpr std::byte erased_memory_content() const { 132 return erased_memory_content_; 133 } 134 135 private: 136 const uint32_t sector_size_; 137 const uint32_t flash_sector_count_; 138 const uint32_t alignment_; 139 const uint32_t start_address_; 140 const uint32_t start_sector_; 141 const std::byte erased_memory_content_; 142 }; 143 144 class FlashPartition { 145 public: 146 // The flash address is in the range of: 0 to PartitionSize. 147 using Address = uint32_t; 148 149 #if PW_CXX_STANDARD_IS_SUPPORTED(17) // Requires C++17 for pw::Result 150 class Writer final : public stream::NonSeekableWriter { 151 public: Writer(kvs::FlashPartition & partition)152 constexpr Writer(kvs::FlashPartition& partition) 153 : partition_(partition), position_(0) {} 154 155 private: 156 Status DoWrite(ConstByteSpan data) override; 157 DoTell()158 size_t DoTell() override { return position_; } 159 ConservativeLimit(LimitType type)160 size_t ConservativeLimit(LimitType type) const override { 161 return type == LimitType::kWrite ? partition_.size_bytes() - position_ 162 : 0; 163 } 164 165 FlashPartition& partition_; 166 size_t position_; 167 }; 168 169 class Reader final : public stream::SeekableReader { 170 public: 171 /// @brief Stream seekable reader for FlashPartitions. 172 /// 173 /// @param partition The partiion to read. 174 /// @param read_limit_bytes Optional limit to read less than the full 175 /// FlashPartition. Reader will use the lesser of read_limit_bytes and 176 /// partition size. Situations needing a subset that starts somewhere other 177 /// than 0 can seek to the desired start point. 178 Reader(kvs::FlashPartition& partition, 179 size_t read_limit_bytes = std::numeric_limits<size_t>::max()) partition_(partition)180 : partition_(partition), 181 read_limit_(std::min(read_limit_bytes, partition_.size_bytes())), 182 position_(0) {} 183 184 Reader(const Reader&) = delete; 185 Reader& operator=(const Reader&) = delete; 186 SetReadLimit(size_t read_limit_bytes)187 void SetReadLimit(size_t read_limit_bytes) { 188 read_limit_ = std::min(read_limit_bytes, partition_.size_bytes()); 189 position_ = std::min(position_, read_limit_); 190 } 191 192 private: 193 StatusWithSize DoRead(ByteSpan data) override; 194 DoTell()195 size_t DoTell() override { return position_; } 196 DoSeek(ptrdiff_t offset,Whence origin)197 Status DoSeek(ptrdiff_t offset, Whence origin) override { 198 return CalculateSeek(offset, origin, read_limit_, position_); 199 } 200 ConservativeLimit(LimitType type)201 size_t ConservativeLimit(LimitType type) const override { 202 return type == LimitType::kRead ? read_limit_ - position_ : 0; 203 } 204 205 FlashPartition& partition_; 206 size_t read_limit_; 207 size_t position_; 208 }; 209 #endif // PW_CXX_STANDARD_IS_SUPPORTED(17) 210 211 // Implement Output for the Write method. 212 class Output final : public pw::Output { 213 public: Output(FlashPartition & flash,FlashPartition::Address address)214 constexpr Output(FlashPartition& flash, FlashPartition::Address address) 215 : flash_(flash), address_(address) {} 216 217 private: 218 StatusWithSize DoWrite(span<const std::byte> data) override; 219 220 FlashPartition& flash_; 221 FlashPartition::Address address_; 222 }; 223 224 // Implement Input for the Read method. 225 class Input final : public pw::Input { 226 public: Input(FlashPartition & flash,FlashPartition::Address address)227 constexpr Input(FlashPartition& flash, FlashPartition::Address address) 228 : flash_(flash), address_(address) {} 229 230 private: 231 StatusWithSize DoRead(span<std::byte> data) override; 232 233 FlashPartition& flash_; 234 FlashPartition::Address address_; 235 }; 236 237 FlashPartition( 238 FlashMemory* flash, 239 uint32_t flash_start_sector_index, 240 uint32_t flash_sector_count, 241 uint32_t alignment_bytes = 0, // Defaults to flash alignment 242 PartitionPermission permission = PartitionPermission::kReadAndWrite); 243 244 // Creates a FlashPartition that uses the entire flash with its alignment. FlashPartition(FlashMemory * flash)245 FlashPartition(FlashMemory* flash) 246 : FlashPartition( 247 flash, 0, flash->sector_count(), flash->alignment_bytes()) {} 248 249 FlashPartition(FlashPartition&&) = default; 250 FlashPartition(const FlashPartition&) = delete; 251 FlashPartition& operator=(const FlashPartition&) = delete; 252 253 virtual ~FlashPartition() = default; 254 255 // Performs any required partition or flash-level initialization. Init()256 virtual Status Init() { return OkStatus(); } 257 258 // Erase num_sectors starting at a given address. Blocking call. 259 // Address must be on a sector boundary. Returns: 260 // 261 // OK - success. 262 // TIMEOUT - on timeout. 263 // INVALID_ARGUMENT - address or sector count is invalid. 264 // PERMISSION_DENIED - partition is read only. 265 // UNKNOWN - HAL error 266 virtual Status Erase(Address address, size_t num_sectors); 267 Erase()268 Status Erase() { return Erase(0, this->sector_count()); } 269 270 // Reads bytes from flash into buffer. Blocking call. Returns: 271 // 272 // OK - success. 273 // TIMEOUT - on timeout. 274 // INVALID_ARGUMENT - address or length is invalid. 275 // UNKNOWN - HAL error 276 virtual StatusWithSize Read(Address address, span<std::byte> output); 277 Read(Address address,size_t length,void * output)278 StatusWithSize Read(Address address, size_t length, void* output) { 279 return Read(address, 280 span<std::byte>(static_cast<std::byte*>(output), length)); 281 } 282 283 // Writes bytes to flash. Address and data.size_bytes() must both be a 284 // multiple of alignment_bytes(). Blocking call. Returns: 285 // 286 // OK - success. 287 // TIMEOUT - on timeout. 288 // INVALID_ARGUMENT - address or length is invalid. 289 // PERMISSION_DENIED - partition is read only. 290 // UNKNOWN - HAL error 291 virtual StatusWithSize Write(Address address, span<const std::byte> data); 292 293 // Check to see if chunk of flash partition is erased. Address and len need to 294 // be aligned with FlashMemory. Returns: 295 // 296 // OK - success. 297 // TIMEOUT - on timeout. 298 // INVALID_ARGUMENT - address or length is invalid. 299 // UNKNOWN - HAL error 300 // TODO(hepler): Result<bool> 301 virtual Status IsRegionErased(Address source_flash_address, 302 size_t length, 303 bool* is_erased); 304 305 // Check if the entire partition is erased. 306 // Returns: same as IsRegionErased(). IsErased(bool * is_erased)307 Status IsErased(bool* is_erased) { 308 return IsRegionErased(0, this->size_bytes(), is_erased); 309 } 310 311 // Returns the address of the first byte of erased flash that has no more 312 // written bytes to the end of the partition. If no erased bytes at end of 313 // partition, then size_bytes of partition is returned. 314 // 315 // OK - success with number of bytes to end of written data. 316 // Other - error code from flash read operation. 317 StatusWithSize EndOfWrittenData(); 318 319 // Checks to see if the data appears to be erased. No reads or writes occur; 320 // the FlashPartition simply compares the data to 321 // flash_.erased_memory_content(). 322 bool AppearsErased(span<const std::byte> data) const; 323 324 // Optionally overridden by derived classes. The reported sector size is space 325 // available to users of FlashPartition. This reported size can be smaller or 326 // larger than the sector size of the backing FlashMemory. 327 // 328 // Possible reasons for size to be different from the backing FlashMemory 329 // could be due to space reserved in the sector for FlashPartition to store 330 // metadata or due to logical FlashPartition sectors that combine several 331 // FlashMemory sectors. sector_size_bytes()332 virtual size_t sector_size_bytes() const { 333 return flash_.sector_size_bytes(); 334 } 335 336 // Optionally overridden by derived classes. The reported sector count is 337 // sectors available to users of FlashPartition. This reported count can be 338 // same or smaller than the given flash_sector_count of the backing 339 // FlashMemory for the same region of flash. 340 // 341 // Possible reasons for count to be different from the backing FlashMemory 342 // could be due to space reserved in the FlashPartition to store metadata or 343 // due to logical FlashPartition sectors that combine several FlashMemory 344 // sectors. sector_count()345 virtual size_t sector_count() const { return flash_sector_count_; } 346 size_bytes()347 size_t size_bytes() const { return sector_count() * sector_size_bytes(); } 348 349 // Alignment required for write address and write size. alignment_bytes()350 size_t alignment_bytes() const { return alignment_bytes_; } 351 352 // Convert a FlashMemory::Address to an MCU pointer, this can be used for 353 // memory mapped reads. Return NULL if the memory is not memory mapped. PartitionAddressToMcuAddress(Address address)354 std::byte* PartitionAddressToMcuAddress(Address address) const { 355 return flash_.FlashAddressToMcuAddress(PartitionToFlashAddress(address)); 356 } 357 358 // Converts an address from the partition address space to the flash address 359 // space. If the partition reserves additional space in the sector, the flash 360 // address space may not be contiguous, and this conversion accounts for that. PartitionToFlashAddress(Address address)361 virtual FlashMemory::Address PartitionToFlashAddress(Address address) const { 362 return flash_.start_address() + 363 (flash_start_sector_index_ - flash_.start_sector()) * 364 flash_.sector_size_bytes() + 365 address; 366 } 367 writable()368 bool writable() const { 369 return permission_ == PartitionPermission::kReadAndWrite; 370 } 371 erased_memory_content()372 constexpr std::byte erased_memory_content() const { 373 return flash_.erased_memory_content(); 374 } 375 start_sector_index()376 uint32_t start_sector_index() const { return flash_start_sector_index_; } 377 378 protected: 379 Status CheckBounds(Address address, size_t len) const; 380 flash()381 FlashMemory& flash() const { return flash_; } 382 383 FlashMemory& flash_; 384 const uint32_t flash_sector_count_; 385 386 private: 387 const uint32_t flash_start_sector_index_; 388 const uint32_t alignment_bytes_; 389 const PartitionPermission permission_; 390 }; 391 392 } // namespace kvs 393 } // namespace pw 394