diff --git a/patches/tock/01-persistent-storage.patch b/patches/tock/01-persistent-storage.patch index 73f8ef35ecd394d5aa74483bd603850c6f64d00a..1df57ae17663972e0c37afeac9ae988434681898 100644 --- a/patches/tock/01-persistent-storage.patch +++ b/patches/tock/01-persistent-storage.patch @@ -42,7 +42,7 @@ index fe493727..105f7120 100644 platform.pconsole.start(); diff --git a/chips/nrf52/src/nvmc.rs b/chips/nrf52/src/nvmc.rs -index 60fc2da8..77e7423d 100644 +index 60fc2da8..45c75f89 100644 --- a/chips/nrf52/src/nvmc.rs +++ b/chips/nrf52/src/nvmc.rs @@ -3,6 +3,7 @@ @@ -126,7 +126,7 @@ index 60fc2da8..77e7423d 100644 let word: u32 = (data[i + 0] as u32) << 0 | (data[i + 1] as u32) << 8 | (data[i + 2] as u32) << 16 -@@ -390,3 +422,178 @@ impl hil::flash::Flash for Nvmc { +@@ -390,3 +422,186 @@ impl hil::flash::Flash for Nvmc { self.erase_page(page_number) } } @@ -158,6 +158,8 @@ index 60fc2da8..77e7423d 100644 +/// - COMMAND(1, 2): Get the maximum number of word writes between page erasures (always 2). +/// - COMMAND(1, 3): Get the maximum number page erasures in the lifetime of the flash (always +/// 10000). ++/// - COMMAND(1, 4): Get the storage address (page-aligned). ++/// - COMMAND(1, 5): Get the storage length (page-aligned). +/// - COMMAND(2, ptr): Write the allow slice to the flash region starting at `ptr`. +/// - `ptr` must be word-aligned. +/// - The allow slice length must be word aligned. @@ -268,6 +270,12 @@ index 60fc2da8..77e7423d 100644 + (1, 3) => ReturnCode::SuccessWithValue { + value: MAX_PAGE_ERASES, + }, ++ (1, 4) => ReturnCode::SuccessWithValue { ++ value: STORAGE_PTR, ++ }, ++ (1, 5) => ReturnCode::SuccessWithValue { ++ value: STORAGE_LEN, ++ }, + (1, _) => ReturnCode::EINVAL, + + (2, ptr) => self diff --git a/src/ctap/storage.rs b/src/ctap/storage.rs index 2a6e52ebc8fa780dfa62d1593ee177baf3ec7c42..6fc398eec8e14c2740f7554e1d459c7013a1d872 100644 --- a/src/ctap/storage.rs +++ b/src/ctap/storage.rs @@ -133,20 +133,6 @@ pub struct PersistentStore { store: embedded_flash::Store<Storage, Config>, } -#[cfg(feature = "ram_storage")] -const PAGE_SIZE: usize = 0x100; -#[cfg(not(feature = "ram_storage"))] -const PAGE_SIZE: usize = 0x1000; - -// We have the following layout: -// 0x00000-0x2ffff: Tock -// 0x30000-0x3ffff: Padding -// 0x40000-0xbffff: App -// 0xc0000-0xfffff: Store -#[cfg(not(any(test, feature = "ram_storage")))] -const STORE_ADDR: usize = 0xC0000; -const STORE_SIZE: usize = NUM_PAGES * PAGE_SIZE; - impl PersistentStore { /// Gives access to the persistent store. /// @@ -167,19 +153,16 @@ impl PersistentStore { #[cfg(not(any(test, feature = "ram_storage")))] fn new_prod_storage() -> Storage { - let store = unsafe { - // Safety: The store cannot alias because this function is called only once. - core::slice::from_raw_parts_mut(STORE_ADDR as *mut u8, STORE_SIZE) - }; - unsafe { - // Safety: The store is in a writeable flash region. - Storage::new(store).unwrap() - } + Storage::new(NUM_PAGES).unwrap() } #[cfg(any(test, feature = "ram_storage"))] fn new_test_storage() -> Storage { - let store = vec![0xff; STORE_SIZE].into_boxed_slice(); + #[cfg(not(test))] + const PAGE_SIZE: usize = 0x100; + #[cfg(test)] + const PAGE_SIZE: usize = 0x1000; + let store = vec![0xff; NUM_PAGES * PAGE_SIZE].into_boxed_slice(); let options = embedded_flash::BufferOptions { word_size: 4, page_size: PAGE_SIZE, diff --git a/src/embedded_flash/syscall.rs b/src/embedded_flash/syscall.rs index b67a7c4aab74972e8eb10415c0403e5148b44e1c..09a7cddf7ae0c095ae4eaa1dc3bc95589507a72e 100644 --- a/src/embedded_flash/syscall.rs +++ b/src/embedded_flash/syscall.rs @@ -24,6 +24,8 @@ mod command_nr { pub const PAGE_SIZE: usize = 1; pub const MAX_WORD_WRITES: usize = 2; pub const MAX_PAGE_ERASES: usize = 3; + pub const STORAGE_PTR: usize = 4; + pub const STORAGE_LEN: usize = 5; } pub const WRITE_SLICE: usize = 2; pub const ERASE_PAGE: usize = 3; @@ -53,46 +55,31 @@ pub struct SyscallStorage { impl SyscallStorage { /// Provides access to the embedded flash if available. /// - /// # Safety - /// - /// The `storage` must be readable. - /// /// # Errors /// /// Returns `BadFlash` if any of the following conditions do not hold: - /// - The word size is not a power of two. - /// - The page size is not a power of two. - /// - The page size is not a multiple of the word size. - /// - /// Returns `NotAligned` if any of the following conditions do not hold: - /// - `storage` is page-aligned. - /// - `storage.len()` is a multiple of the page size. + /// - The word size is a power of two. + /// - The page size is a power of two. + /// - The page size is a multiple of the word size. + /// - The storage is page-aligned. /// - /// # Examples - /// - /// ```rust - /// # extern crate ctap2; - /// # use ctap2::embedded_flash::SyscallStorage; - /// # use ctap2::embedded_flash::StorageResult; - /// # const STORAGE_ADDR: usize = 0x1000; - /// # const STORAGE_SIZE: usize = 0x1000; - /// # fn foo() -> StorageResult<SyscallStorage> { - /// // This is safe because we create and use `storage` only once in the whole program. - /// let storage = unsafe { - /// core::slice::from_raw_parts_mut(STORAGE_ADDR as *mut u8, STORAGE_SIZE) - /// }; - /// // This is safe because `storage` is readable. - /// unsafe { SyscallStorage::new(storage) } - /// # } - /// ``` - pub unsafe fn new(storage: &'static mut [u8]) -> StorageResult<SyscallStorage> { + /// Returns `OutOfBounds` the number of pages does not fit in the storage. + pub fn new(num_pages: usize) -> StorageResult<SyscallStorage> { let word_size = get_info(command_nr::get_info_nr::WORD_SIZE)?; let page_size = get_info(command_nr::get_info_nr::PAGE_SIZE)?; let max_word_writes = get_info(command_nr::get_info_nr::MAX_WORD_WRITES)?; let max_page_erases = get_info(command_nr::get_info_nr::MAX_PAGE_ERASES)?; + let storage_ptr = get_info(command_nr::get_info_nr::STORAGE_PTR)?; + let max_storage_len = get_info(command_nr::get_info_nr::STORAGE_LEN)?; if !word_size.is_power_of_two() || !page_size.is_power_of_two() { return Err(StorageError::BadFlash); } + let storage_len = num_pages * page_size; + if storage_len > max_storage_len { + return Err(StorageError::OutOfBounds); + } + let storage = + unsafe { core::slice::from_raw_parts_mut(storage_ptr as *mut u8, storage_len) }; let syscall = SyscallStorage { word_size, page_size, @@ -100,16 +87,10 @@ impl SyscallStorage { max_page_erases, storage, }; - if !syscall.is_word_aligned(page_size) { + if !syscall.is_word_aligned(page_size) || !syscall.is_page_aligned(storage_ptr) { return Err(StorageError::BadFlash); } - if syscall.is_page_aligned(syscall.storage.as_ptr() as usize) - && syscall.is_page_aligned(syscall.storage.len()) - { - Ok(syscall) - } else { - Err(StorageError::NotAligned) - } + Ok(syscall) } fn is_word_aligned(&self, x: usize) -> bool {