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