-
Notifications
You must be signed in to change notification settings - Fork 346
Description
I've encountered a storage error: OutOfBounds. I think this might be because the bounds check in the ease implementation differs from the read/write operations. My NVS partition is 16KB, but I have to use only 12KB to avoid the OutOfBounds error when calling the erase_all_nvs function.
Here's my code:
use core::str;
extern crate alloc;
use alloc::{string::String, vec, vec::Vec};
use embassy_embedded_hal::adapter::BlockingAsync;
use esp_bootloader_esp_idf::partitions::{
read_partition_table, DataPartitionSubType, Error as PartitionError, PartitionType,
PARTITION_TABLE_MAX_LEN,
};
use esp_storage::FlashStorage;
use sequential_storage::cache::NoCache;
use sequential_storage::map::{fetch_item, store_item};
type KvError = sequential_storage::Error<PartitionError>;
#[inline]
fn nvs_range(len: u32) -> core::ops::Range<u32> {
let sector_size = esp_storage::FlashStorage::SECTOR_SIZE as u32;
0..(len & !(sector_size - 1))
}
macro_rules! with_nvs {
($af:ident, $range:ident, $cache:ident, $body:block) => {{
let mut flash = FlashStorage::new();
let mut pt_buf = [0u8; PARTITION_TABLE_MAX_LEN];
let pt = read_partition_table(&mut flash, &mut pt_buf)
.map_err(|e| KvError::Storage { value: e })?;
let nvs = pt
.find_partition(PartitionType::Data(DataPartitionSubType::Nvs))
.map_err(|e| KvError::Storage { value: e })?
.ok_or(PartitionError::Invalid)
.map_err(|e| KvError::Storage { value: e })?;
let mut region = nvs.as_embedded_storage(&mut flash);
let mut $af = BlockingAsync::new(&mut region);
let mut $cache = NoCache::new();
let $range = nvs_range(nvs.len());
$body
}};
}
pub async fn erase_all_nvs() -> Result<(), KvError> {
with_nvs!(async_flash, range, _cache, {
sequential_storage::erase_all(&mut async_flash, range.clone()).await
})
}
pub async fn write_kv(key: u16, value: &[u8]) -> Result<(), KvError> {
with_nvs!(async_flash, range, cache, {
// Buffer must be large enough to serialize key + value
let mut data_buffer: Vec<u8> = vec![0; 2 + value.len()];
store_item(
&mut async_flash,
range,
&mut cache,
&mut data_buffer,
&key,
&value,
)
.await
})
}
/// Read raw bytes from NVS for the given 16-bit key.
pub async fn read_kv(key: u16) -> Result<Option<Vec<u8>>, KvError> {
with_nvs!(async_flash, range, cache, {
let mut buf: Vec<u8> = vec![0; 256];
loop {
match fetch_item::<u16, &'_ [u8], _>(
&mut async_flash,
range.clone(),
&mut cache,
&mut buf,
&key,
)
.await
{
Ok(Some(s)) => return Ok(Some(s.to_vec())),
Ok(None) => return Ok(None),
Err(KvError::BufferTooSmall(needed)) => {
let new_len = core::cmp::max(buf.len() * 2, needed);
buf.resize(new_len, 0);
}
Err(e) => return Err(e),
}
}
})
}
esp-hal/esp-bootloader-esp-idf/src/partitions.rs
Lines 537 to 543 in 6f03366
| fn range(&self) -> core::ops::Range<u32> { | |
| self.raw.offset()..self.raw.offset() + self.raw.len() | |
| } | |
| fn in_range(&self, start: u32, len: usize) -> bool { | |
| self.range().contains(&start) && (start + len as u32 <= self.range().end) | |
| } |
ease function use range() which is end-exclusive
esp-hal/esp-bootloader-esp-idf/src/partitions.rs
Lines 640 to 659 in 6f03366
| fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | |
| let address_from = from + self.raw.offset(); | |
| let address_to = to + self.raw.offset(); | |
| if self.raw.is_read_only() { | |
| return Err(Error::WriteProtected); | |
| } | |
| if !self.range().contains(&address_from) { | |
| return Err(Error::OutOfBounds); | |
| } | |
| if !self.range().contains(&address_to) { | |
| return Err(Error::OutOfBounds); | |
| } | |
| self.flash | |
| .erase(address_from, address_to) | |
| .map_err(|_e| Error::StorageError) | |
| } |
but read/write function use in_range() which is end-inclusive
esp-hal/esp-bootloader-esp-idf/src/partitions.rs
Lines 558 to 568 in 6f03366
| fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | |
| let address = offset + self.raw.offset(); | |
| if !self.in_range(address, bytes.len()) { | |
| return Err(Error::OutOfBounds); | |
| } | |
| self.flash | |
| .read(address, bytes) | |
| .map_err(|_e| Error::StorageError) | |
| } |
Metadata
Metadata
Assignees
Type
Projects
Status