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 {