diff --git a/.github/workflows/boards_build.yml b/.github/workflows/boards_build.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ef71f425d2bf929f569e2932838d7f6ea2be30c0
--- /dev/null
+++ b/.github/workflows/boards_build.yml
@@ -0,0 +1,35 @@
+---
+name: Build supported boards
+on:
+  push:
+    paths:
+     - 'patches/tock/*'
+     - 'third_party/tock/**'
+  pull_request:
+    types: [opened, synchronize, reopened]
+
+jobs:
+  build_boards:
+    strategy:
+      matrix:
+        os: [ubuntu-18.04, macos-10.15]
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          target: thumbv7em-none-eabi
+      - uses: actions/setup-python@v1
+        with:
+          python-version: 3.7
+      - name: Install Python dependencies
+        run: python -m pip install --upgrade pip setuptools wheel
+      - name: Set up OpenSK
+        run: ./setup.sh
+      - name: Create a long build directory
+        run: mkdir this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz && mv third_party this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz/
+
+      - name: Building board nrf52840dk
+        run: make -C this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz/third_party/tock/boards/nordic/nrf52840dk
+      - name: Building board nrf52840_dongle
+        run: make -C this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz/third_party/tock/boards/nordic/nrf52840_dongle
diff --git a/.github/workflows/cargo_check.yml b/.github/workflows/cargo_check.yml
index 60b96d19ab21563dcadf78964f408ac81998e7d3..a6c4c4696cca73994152d3ee1422399374e7f768 100644
--- a/.github/workflows/cargo_check.yml
+++ b/.github/workflows/cargo_check.yml
@@ -58,6 +58,12 @@ jobs:
           command: check
           args: --target thumbv7em-none-eabi --release --features debug_allocations
 
+      - name: Check OpenSK ram_storage
+        uses: actions-rs/cargo@v1
+        with:
+          command: check
+          args: --target thumbv7em-none-eabi --release --features ram_storage
+
       - name: Check OpenSK debug_ctap,with_ctap1
         uses: actions-rs/cargo@v1
         with:
diff --git a/Cargo.toml b/Cargo.toml
index 03dc0349d493bf75828a645f6828688665a1d8ca..3155106e9d79fc478ea7c9669c79fefd6124b884 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,6 +23,7 @@ debug_ctap = ["crypto/derive_debug"]
 with_ctap1 = ["crypto/with_ctap1"]
 panic_console = ["libtock/panic_console"]
 debug_allocations = ["libtock/debug_allocations"]
+ram_storage = []
 
 [dev-dependencies]
 elf2tab = "0.4.0"
diff --git a/deploy.py b/deploy.py
index ee7f54f083eeface34e00352e0a99cb052c64fd0..dc69c24ea4921d73e03577649edbcbdf995d677b 100755
--- a/deploy.py
+++ b/deploy.py
@@ -405,6 +405,14 @@ if __name__ == "__main__":
             "(i.e. more debug messages will be sent over the console port "
             "such as hexdumps of packets)."),
   )
+  app_commands.add_argument(
+      "--no-persistent-storage",
+      action="append_const",
+      const="ram_storage",
+      dest="features",
+      help=("Compiles and installs the OpenSK application without persistent "
+            "storage (i.e. unplugging the key will reset the key)."),
+  )
   apps_group = app_commands.add_mutually_exclusive_group()
   apps_group.add_argument(
       "--opensk",
diff --git a/patches/tock/01-persistent-storage.patch b/patches/tock/01-persistent-storage.patch
index 5aaec063d52d18dcb77d17af092a6500812a5828..ecfb0b0b0f01847f7735d9b3a0d015d137d81242 100644
--- a/patches/tock/01-persistent-storage.patch
+++ b/patches/tock/01-persistent-storage.patch
@@ -295,7 +295,7 @@ index ece4a443..9a1afc84 100644
      }
 +
 +    pub fn in_writeable_flash_region(&self, ptr: usize, len: usize) -> bool {
-+        self.kernel.process_map_or(false, self.idx, |process| {
++        self.kernel.process_map_or(false, *self, |process| {
 +            let ptr = match ptr.checked_sub(process.flash_start() as usize) {
 +                None => return false,
 +                Some(ptr) => ptr,
diff --git a/patches/tock/04-fix-dynamic-deferred-call.patch b/patches/tock/04-fix-dynamic-deferred-call.patch
deleted file mode 100644
index 4e29004ecfa049b815a79884aeb96c6acf605d8e..0000000000000000000000000000000000000000
--- a/patches/tock/04-fix-dynamic-deferred-call.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-diff --git a/kernel/src/common/dynamic_deferred_call.rs b/kernel/src/common/dynamic_deferred_call.rs
-index 53f5143d..ca349972 100644
---- a/kernel/src/common/dynamic_deferred_call.rs
-+++ b/kernel/src/common/dynamic_deferred_call.rs
-@@ -226,23 +226,25 @@ impl DynamicDeferredCall {
-     /// `call_global_instance_while`.
-     pub(self) fn call_while<F: Fn() -> bool>(&self, f: F) {
-         if self.call_pending.get() {
--            // Reset call_pending here, as it may be set again in the deferred calls
--            self.call_pending.set(false);
-+            for (i, client_state) in self.client_states.iter().enumerate() {
-+                if !f() {
-+                    break;
-+                }
-+                if client_state.scheduled.get() {
-+                    client_state.client.map(|client| {
-+                        client_state.scheduled.set(false);
-+                        client.call(DeferredCallHandle(i));
-+                    });
-+                }
-+            }
- 
--            self.client_states
--                .iter()
--                .enumerate()
--                .filter(|(_i, client_state)| client_state.scheduled.get())
--                .filter_map(|(i, client_state)| {
--                    client_state
--                        .client
--                        .map(|c| (i, &client_state.scheduled, *c))
--                })
--                .take_while(|_| f())
--                .for_each(|(i, call_reqd, client)| {
--                    call_reqd.set(false);
--                    client.call(DeferredCallHandle(i));
--                });
-+            // Recompute call_pending here, as some deferred calls may have been skipped due to the
-+            // `f` predicate becoming false.
-+            self.call_pending.set(
-+                self.client_states
-+                    .iter()
-+                    .any(|client_state| client_state.scheduled.get()),
-+            );
-         }
-     }
- }
diff --git a/patches/tock/04-increase-rom-nordic.patch b/patches/tock/04-increase-rom-nordic.patch
new file mode 100644
index 0000000000000000000000000000000000000000..83948f80007be9fd12cd351ff27cfe5c50182c26
--- /dev/null
+++ b/patches/tock/04-increase-rom-nordic.patch
@@ -0,0 +1,24 @@
+diff --git a/boards/nordic/nrf52840_dongle/layout.ld b/boards/nordic/nrf52840_dongle/layout.ld
+index 657b0d26..f86b2321 100644
+--- a/boards/nordic/nrf52840_dongle/layout.ld
++++ b/boards/nordic/nrf52840_dongle/layout.ld
+@@ -1,6 +1,6 @@
+ MEMORY
+ {
+-  rom (rx)  : ORIGIN = 0x00000000, LENGTH = 128K
++  rom (rx)  : ORIGIN = 0x00000000, LENGTH = 192K
+   prog (rx) : ORIGIN = 0x00030000, LENGTH = 832K
+   ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
+ }
+diff --git a/boards/nordic/nrf52840dk/layout.ld b/boards/nordic/nrf52840dk/layout.ld
+index 657b0d26..f86b2321 100644
+--- a/boards/nordic/nrf52840dk/layout.ld
++++ b/boards/nordic/nrf52840dk/layout.ld
+@@ -1,6 +1,6 @@
+ MEMORY
+ {
+-  rom (rx)  : ORIGIN = 0x00000000, LENGTH = 128K
++  rom (rx)  : ORIGIN = 0x00000000, LENGTH = 192K
+   prog (rx) : ORIGIN = 0x00030000, LENGTH = 832K
+   ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
+ }
diff --git a/run_desktop_tests.sh b/run_desktop_tests.sh
index e3f2b1ef9ad1442008977d683199c715e6db426d..33b209014900702be46cf0026d99d9d7b929e41c 100755
--- a/run_desktop_tests.sh
+++ b/run_desktop_tests.sh
@@ -30,6 +30,7 @@ cargo check --release --target=thumbv7em-none-eabi --features with_ctap1
 cargo check --release --target=thumbv7em-none-eabi --features debug_ctap
 cargo check --release --target=thumbv7em-none-eabi --features panic_console
 cargo check --release --target=thumbv7em-none-eabi --features debug_allocations
+cargo check --release --target=thumbv7em-none-eabi --features ram_storage
 cargo check --release --target=thumbv7em-none-eabi --features debug_ctap,with_ctap1
 cargo check --release --target=thumbv7em-none-eabi --features debug_ctap,with_ctap1,panic_console,debug_allocations
 
@@ -39,6 +40,10 @@ cargo check --release --target=thumbv7em-none-eabi --examples
 echo "Checking that CTAP2 builds and links properly (1 set of features)..."
 cargo build --release --target=thumbv7em-none-eabi --features with_ctap1
 
+echo "Checking that supported boards build properly..."
+make -C third_party/tock/boards/nordic/nrf52840dk
+make -C third_party/tock/boards/nordic/nrf52840_dongle
+
 if [ -z "${TRAVIS_OS_NAME}" -o "${TRAVIS_OS_NAME}" = "linux" ]
 then
   echo "Running unit tests on the desktop (release mode)..."
diff --git a/src/ctap/storage.rs b/src/ctap/storage.rs
index e693a136aa18edc7ab5ad72c7a18fc9728f5f802..7569c1b0fc956474b933ba90cf10e2549af0914a 100644
--- a/src/ctap/storage.rs
+++ b/src/ctap/storage.rs
@@ -21,9 +21,9 @@ use alloc::vec::Vec;
 use core::convert::TryInto;
 use ctap2::embedded_flash::{self, StoreConfig, StoreEntry, StoreError, StoreIndex};
 
-#[cfg(test)]
+#[cfg(any(test, feature = "ram_storage"))]
 type Storage = embedded_flash::BufferStorage;
-#[cfg(not(test))]
+#[cfg(not(any(test, feature = "ram_storage")))]
 type Storage = embedded_flash::SyscallStorage;
 
 // Those constants may be modified before compilation to tune the behavior of the key.
@@ -44,6 +44,9 @@ type Storage = embedded_flash::SyscallStorage;
 // We have: I = ((P - 1) * 4092 - K * S) / 12 * C
 //
 // With P=20 and K=150, we have I > 2M which is enough for 500 increments per day for 10 years.
+#[cfg(feature = "ram_storage")]
+const NUM_PAGES: usize = 2;
+#[cfg(not(feature = "ram_storage"))]
 const NUM_PAGES: usize = 20;
 const MAX_SUPPORTED_RESIDENTIAL_KEYS: usize = 150;
 
@@ -130,10 +133,14 @@ 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;
+
 const STORE_SIZE: usize = NUM_PAGES * PAGE_SIZE;
 
-#[cfg(not(test))]
+#[cfg(not(any(test, feature = "ram_storage")))]
 #[link_section = ".app_state"]
 static STORE: [u8; STORE_SIZE] = [0xff; STORE_SIZE];
 
@@ -144,9 +151,9 @@ impl PersistentStore {
     ///
     /// This should be at most one instance of persistent store per program lifetime.
     pub fn new(rng: &mut impl Rng256) -> PersistentStore {
-        #[cfg(not(test))]
+        #[cfg(not(any(test, feature = "ram_storage")))]
         let storage = PersistentStore::new_prod_storage();
-        #[cfg(test)]
+        #[cfg(any(test, feature = "ram_storage"))]
         let storage = PersistentStore::new_test_storage();
         let mut store = PersistentStore {
             store: embedded_flash::Store::new(storage, Config).unwrap(),
@@ -155,7 +162,7 @@ impl PersistentStore {
         store
     }
 
-    #[cfg(not(test))]
+    #[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.
@@ -167,7 +174,7 @@ impl PersistentStore {
         }
     }
 
-    #[cfg(test)]
+    #[cfg(any(test, feature = "ram_storage"))]
     fn new_test_storage() -> Storage {
         let store = vec![0xff; STORE_SIZE].into_boxed_slice();
         let options = embedded_flash::BufferOptions {
diff --git a/src/embedded_flash/buffer.rs b/src/embedded_flash/buffer.rs
index b7cf3f1ea89775a64739ef02707bf484d4be5a95..4fcd80fe8d50d0a312fca6bb4ec170c5b7613228 100644
--- a/src/embedded_flash/buffer.rs
+++ b/src/embedded_flash/buffer.rs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 use super::{Index, Storage, StorageError, StorageResult};
+use alloc::boxed::Box;
 
 pub struct BufferStorage {
     storage: Box<[u8]>,
@@ -230,7 +231,7 @@ impl Snapshot {
 
     fn get(&mut self) -> Result<Box<[u8]>, usize> {
         let mut snapshot = Snapshot::Ready;
-        std::mem::swap(self, &mut snapshot);
+        core::mem::swap(self, &mut snapshot);
         match snapshot {
             Snapshot::Armed { delay } => Err(delay),
             Snapshot::Taken { storage } => Ok(storage),
diff --git a/src/embedded_flash/mod.rs b/src/embedded_flash/mod.rs
index 5e54059e2e2c65301a5292411cf48ca2510b1f9c..8551a52721dce1342d70f414974e21f246079285 100644
--- a/src/embedded_flash/mod.rs
+++ b/src/embedded_flash/mod.rs
@@ -12,13 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#[cfg(feature = "std")]
 mod buffer;
 mod storage;
 mod store;
 mod syscall;
 
-#[cfg(feature = "std")]
 pub use self::buffer::{BufferOptions, BufferStorage};
 pub use self::storage::{Index, Storage, StorageError, StorageResult};
 pub use self::store::{Store, StoreConfig, StoreEntry, StoreError, StoreIndex};
diff --git a/third_party/tock b/third_party/tock
index 3a7d6b775d972798bfd731cba8365b58fab27175..fbc863faf0c9615537ee52dcdccdfcb9204d2467 160000
--- a/third_party/tock
+++ b/third_party/tock
@@ -1 +1 @@
-Subproject commit 3a7d6b775d972798bfd731cba8365b58fab27175
+Subproject commit fbc863faf0c9615537ee52dcdccdfcb9204d2467