ensure all flash writes are aligned

This commit is contained in:
2026-08-29 15:01:48 +00:00
committed by rhetenor
parent 704682b0ae
commit b63195b943
4 changed files with 65 additions and 37 deletions
+1 -1
View File
@@ -241,7 +241,7 @@ pub struct Card {
pub sprite: Sprite, pub sprite: Sprite,
} }
impl<'a> TryFrom<RawCard> for Card { impl TryFrom<RawCard> for Card {
type Error = &'static str; type Error = &'static str;
fn try_from(raw_card: RawCard) -> Result<Self, Self::Error> { fn try_from(raw_card: RawCard) -> Result<Self, Self::Error> {
+14 -11
View File
@@ -1,27 +1,30 @@
struct MemoryRegion { pub struct MemoryRegion {
offset: u32, offset: u32,
size: usize, size: usize,
} }
impl MemoryRegion { impl MemoryRegion {
const fn end(&self) -> usize { pub const fn new(offset: u32, size: usize) -> Self {
assert!(offset.is_multiple_of(4), "Flash requires 4 bytes alignment");
assert!(size.is_multiple_of(4), "Flash requires 4 bytes alignment");
Self { offset, size }
}
pub const fn end(&self) -> usize {
self.offset as usize + self.size self.offset as usize + self.size
} }
} }
const MAX_FLASH: usize = 16 * 1024 * 1024; const MAX_FLASH: usize = 16 * 1024 * 1024;
const MAGIC_REGION: MemoryRegion = MemoryRegion { offset: 0, size: 4 }; const MAGIC_REGION: MemoryRegion = MemoryRegion::new(0, 4);
const SETTINGS_REGION: MemoryRegion = MemoryRegion { const SETTINGS_REGION: MemoryRegion = MemoryRegion::new(MAGIC_REGION.end() as u32, 1024);
offset: MAGIC_REGION.end() as u32,
size: 1024,
};
const CARDSTORE_REGION: MemoryRegion = MemoryRegion { const CARDSTORE_REGION: MemoryRegion = MemoryRegion::new(
offset: SETTINGS_REGION.end() as u32, SETTINGS_REGION.end() as u32,
size: MAX_FLASH - SETTINGS_REGION.end(), MAX_FLASH - SETTINGS_REGION.end(),
}; );
pub mod cardstore; pub mod cardstore;
pub mod settings; pub mod settings;
+16 -14
View File
@@ -12,21 +12,17 @@ use crate::storage::{CARDSTORE_REGION, MemoryRegion};
const MAX_CARDS: usize = 20000; const MAX_CARDS: usize = 20000;
const COUNT_REGION: MemoryRegion = MemoryRegion { pub const COUNT_REGION: MemoryRegion = MemoryRegion::new(CARDSTORE_REGION.offset, size_of::<u32>());
offset: CARDSTORE_REGION.offset,
size: size_of::<u32>(),
};
const ALLOCATION_TABLE_REGION: MemoryRegion = MemoryRegion { const ALLOCATION_TABLE_REGION: MemoryRegion = MemoryRegion::new(
offset: COUNT_REGION.end() as u32, COUNT_REGION.end() as u32,
size: MAX_CARDS * AllocationTableEntry::SERIALIZED_SIZE, MAX_CARDS * AllocationTableEntry::SERIALIZED_SIZE,
}; );
const CARDS_REGION: MemoryRegion = MemoryRegion {
offset: ALLOCATION_TABLE_REGION.end() as u32,
size: CARDSTORE_REGION.size - ALLOCATION_TABLE_REGION.end(),
};
const CARDS_REGION: MemoryRegion = MemoryRegion::new(
ALLOCATION_TABLE_REGION.end() as u32,
CARDSTORE_REGION.size - ALLOCATION_TABLE_REGION.end(),
);
#[derive(Debug, BinarySerde, PartialEq, Eq, Clone)] #[derive(Debug, BinarySerde, PartialEq, Eq, Clone)]
#[repr(C)] #[repr(C)]
@@ -47,8 +43,11 @@ pub struct AllocationTableEntry {
deleted: bool, deleted: bool,
reserved: [u64; 4], reserved: [u64; 4],
_padding: [u8; 3],
} }
static_assertions::const_assert!(AllocationTableEntry::SERIALIZED_SIZE.is_multiple_of(4));
impl AllocationTableEntry { impl AllocationTableEntry {
fn new(uuid: u32, offset: u32, timestamp: u64) -> Self { fn new(uuid: u32, offset: u32, timestamp: u64) -> Self {
Self { Self {
@@ -58,7 +57,8 @@ impl AllocationTableEntry {
last_read_date: timestamp, last_read_date: timestamp,
read_count: 0, read_count: 0,
deleted: true, deleted: true,
reserved: [0; 4], reserved: Default::default(),
_padding: Default::default(),
} }
} }
} }
@@ -96,6 +96,8 @@ impl CardStore {
let count: u32 = u32::from_ne_bytes(count_bytes); let count: u32 = u32::from_ne_bytes(count_bytes);
log::info!("Found {count} cards in flash.");
let mut allocation_table_entries: Vec<u8> = let mut allocation_table_entries: Vec<u8> =
Vec::with_capacity(AllocationTableEntry::SERIALIZED_SIZE * count as usize); Vec::with_capacity(AllocationTableEntry::SERIALIZED_SIZE * count as usize);
+34 -11
View File
@@ -2,33 +2,33 @@ use embedded_storage::nor_flash::NorFlash;
use embedded_storage::nor_flash::ReadNorFlash; use embedded_storage::nor_flash::ReadNorFlash;
use esp_storage::{FlashStorage, FlashStorageError}; use esp_storage::{FlashStorage, FlashStorageError};
use crate::storage::MAGIC_REGION;
use crate::storage::cardstore::COUNT_REGION;
pub type StoreError = FlashStorageError; pub type StoreError = FlashStorageError;
const FLASH_ADDR: u32 = 0x9000; const FLASH_ADDR: u32 = 0x9000;
const INITIALIZATION_SIZE: usize = 0x1004; const INITIALIZATION_SIZE: usize = COUNT_REGION.end();
const FLASH_INITIALIZE_MAGIC: u32 = 0xde6de6de; const FLASH_INITIALIZE_MAGIC: u32 = 0xde6de6de;
pub struct Store { pub struct Store {
pub storage: FlashStorage<'static>, pub storage: FlashStorage<'static>,
} }
fn initialize_flash(storage: &mut FlashStorage) -> Result<(), StoreError> {
let zeros: [u8; INITIALIZATION_SIZE] = [0; INITIALIZATION_SIZE];
storage.write(FLASH_ADDR, &zeros)?;
storage.write(FLASH_ADDR, &FLASH_INITIALIZE_MAGIC.to_ne_bytes())?;
Ok(())
}
impl Store { impl Store {
pub fn new(flash: esp_hal::peripherals::FLASH<'static>) -> Result<Self, StoreError> { pub fn new(flash: esp_hal::peripherals::FLASH<'static>) -> Result<Self, StoreError> {
let mut storage = FlashStorage::new(flash); let mut storage = FlashStorage::new(flash);
let mut magic: [u8; 4] = [0, 0, 0, 0]; let mut magic: [u8; 4] = [0, 0, 0, 0];
storage.read(FLASH_ADDR, &mut magic)?; storage.read(FLASH_ADDR + MAGIC_REGION.offset, &mut magic)?;
log::debug!("Magic bytes are {magic:?}");
if (u32::from_ne_bytes(magic)) != FLASH_INITIALIZE_MAGIC { if Self::has_magic_bytes(&mut storage)? {
initialize_flash(&mut storage)?; log::info!("Skipped flash initialization, magic bytes already present.");
} else {
log::info!("Initializing flash because no magic bytes found.");
Self::initialize_flash(&mut storage)?;
} }
Ok(Self { storage }) Ok(Self { storage })
@@ -42,4 +42,27 @@ impl Store {
log::debug!("Writing {} bytes at offset 0x{offset:08x}", bytes.len()); log::debug!("Writing {} bytes at offset 0x{offset:08x}", bytes.len());
self.storage.write(FLASH_ADDR + offset, bytes) self.storage.write(FLASH_ADDR + offset, bytes)
} }
fn has_magic_bytes(storage: &mut FlashStorage) -> Result<bool, StoreError> {
let mut magic: [u8; 4] = [0, 0, 0, 0];
storage.read(FLASH_ADDR + MAGIC_REGION.offset, &mut magic)?;
log::debug!("Magic bytes are {magic:?}");
Ok(u32::from_ne_bytes(magic) == FLASH_INITIALIZE_MAGIC)
}
fn initialize_flash(storage: &mut FlashStorage) -> Result<(), StoreError> {
let zeros: [u8; INITIALIZATION_SIZE] = [0; INITIALIZATION_SIZE];
storage.write(FLASH_ADDR, &zeros)?;
storage.write(
FLASH_ADDR + MAGIC_REGION.offset,
&FLASH_INITIALIZE_MAGIC.to_ne_bytes(),
)?;
if Self::has_magic_bytes(storage)? {
Ok(())
} else {
Err(StoreError::Other(FLASH_INITIALIZE_MAGIC as i32))
}
}
} }