diff --git a/examples/store_latency.rs b/examples/store_latency.rs index 1c575e5..b6d0156 100644 --- a/examples/store_latency.rs +++ b/examples/store_latency.rs @@ -182,10 +182,10 @@ fn main() { // Results on nrf52840dk_opensk: // Pages Overwrite Length Boot Compaction Insert Remove - // 3 no 50 words 4.7 ms 135.5 ms 6.9 ms 2.7 ms - // 20 no 50 words 16.7 ms 141.7 ms 18.6 ms 8.5 ms - // 3 yes 1 words 33.7 ms 97.7 ms 9.5 ms 4.8 ms - // 20 yes 1 words 338.3 ms 97.7 ms 9.7 ms 4.8 ms + // 3 no 50 words 5.3 ms 141.9 ms 8.0 ms 3.3 ms + // 20 no 50 words 18.7 ms 148.6 ms 21.0 ms 9.8 ms + // 3 yes 1 words 37.8 ms 100.2 ms 11.3 ms 5.5 ms + // 20 yes 1 words 336.5 ms 100.3 ms 11.5 ms 5.6 ms } fn align(x: &str, n: usize) { diff --git a/patches/tock/01-persistent-storage.patch b/patches/tock/01-persistent-storage.patch index 86e1833..99a1c54 100644 --- a/patches/tock/01-persistent-storage.patch +++ b/patches/tock/01-persistent-storage.patch @@ -89,7 +89,7 @@ index e0e292a7e..b485a0997 100644 }; diff --git a/boards/nordic/nrf52840dk_opensk/src/main.rs b/boards/nordic/nrf52840dk_opensk/src/main.rs -index 8e4238018..ebee8704b 100644 +index 8e4238018..c80732f8d 100644 --- a/boards/nordic/nrf52840dk_opensk/src/main.rs +++ b/boards/nordic/nrf52840dk_opensk/src/main.rs @@ -114,6 +114,11 @@ const NUM_PROCS: usize = 8; @@ -155,7 +155,7 @@ index 8e4238018..ebee8704b 100644 let gpio = components::gpio::GpioComponent::new( board_kernel, -@@ -334,6 +363,14 @@ pub unsafe fn reset_handler() { +@@ -334,6 +363,20 @@ pub unsafe fn reset_handler() { nrf52840::acomp::Comparator )); @@ -164,13 +164,19 @@ index 8e4238018..ebee8704b 100644 + nrf52840::nvmc::SyscallDriver::new( + &nrf52840::nvmc::NVMC, + board_kernel.create_grant(&memory_allocation_capability), ++ dynamic_deferred_caller, + ) + ); ++ nvmc.set_deferred_handle( ++ dynamic_deferred_caller ++ .register(nvmc) ++ .expect("no deferred call slot available for nvmc"), ++ ); + nrf52_components::NrfClockComponent::new().finalize(()); let platform = Platform { -@@ -345,6 +382,7 @@ pub unsafe fn reset_handler() { +@@ -345,6 +388,7 @@ pub unsafe fn reset_handler() { rng, alarm, analog_comparator, @@ -179,10 +185,10 @@ index 8e4238018..ebee8704b 100644 }; diff --git a/chips/nrf52/src/nvmc.rs b/chips/nrf52/src/nvmc.rs -index b70162cae..9dcb82b07 100644 +index b70162cae..9934f3a31 100644 --- a/chips/nrf52/src/nvmc.rs +++ b/chips/nrf52/src/nvmc.rs -@@ -3,6 +3,7 @@ +@@ -3,15 +3,19 @@ //! Used in order read and write to internal flash. use core::cell::Cell; @@ -190,7 +196,11 @@ index b70162cae..9dcb82b07 100644 use core::ops::{Index, IndexMut}; use kernel::common::cells::OptionalCell; use kernel::common::cells::TakeCell; -@@ -11,7 +12,7 @@ use kernel::common::deferred_call::DeferredCall; + use kernel::common::cells::VolatileCell; + use kernel::common::deferred_call::DeferredCall; ++use kernel::common::dynamic_deferred_call::{ ++ DeferredCallHandle, DynamicDeferredCall, DynamicDeferredCallClient, ++}; use kernel::common::registers::{register_bitfields, ReadOnly, ReadWrite}; use kernel::common::StaticRef; use kernel::hil; @@ -199,7 +209,7 @@ index b70162cae..9dcb82b07 100644 use crate::deferred_call_tasks::DeferredCallTask; -@@ -141,7 +142,13 @@ register_bitfields! [u32, +@@ -141,7 +145,13 @@ register_bitfields! [u32, static DEFERRED_CALL: DeferredCall = unsafe { DeferredCall::new(DeferredCallTask::Nvmc) }; @@ -213,7 +223,7 @@ index b70162cae..9dcb82b07 100644 /// This is a wrapper around a u8 array that is sized to a single page for the /// nrf. Users of this module must pass an object of this type to use the -@@ -219,6 +226,11 @@ impl Nvmc { +@@ -219,6 +229,11 @@ impl Nvmc { } } @@ -225,7 +235,7 @@ index b70162cae..9dcb82b07 100644 /// Configure the NVMC to allow writes to flash. pub fn configure_writeable(&self) { let regs = &*self.registers; -@@ -234,7 +246,7 @@ impl Nvmc { +@@ -234,7 +249,7 @@ impl Nvmc { let regs = &*self.registers; regs.config.write(Configuration::WEN::Een); while !self.is_ready() {} @@ -234,7 +244,7 @@ index b70162cae..9dcb82b07 100644 while !self.is_ready() {} } -@@ -326,7 +338,7 @@ impl Nvmc { +@@ -326,7 +341,7 @@ impl Nvmc { // Put the NVMC in write mode. regs.config.write(Configuration::WEN::Wen); @@ -243,7 +253,7 @@ index b70162cae..9dcb82b07 100644 let word: u32 = (data[i + 0] as u32) << 0 | (data[i + 1] as u32) << 8 | (data[i + 2] as u32) << 16 -@@ -394,3 +406,180 @@ impl hil::flash::Flash for Nvmc { +@@ -394,3 +409,236 @@ impl hil::flash::Flash for Nvmc { self.erase_page(page_number) } } @@ -269,6 +279,7 @@ index b70162cae..9dcb82b07 100644 +/// +/// # Syscalls +/// ++/// - SUBSCRIBE(0, done): The callback for COMMAND(2) and COMMAND(3). +/// - COMMAND(0): Check the driver. +/// - COMMAND(1, 0): Get the word size (always 4). +/// - COMMAND(1, 1): Get the page size (always 4096). @@ -287,28 +298,45 @@ index b70162cae..9dcb82b07 100644 +pub struct SyscallDriver { + nvmc: &'static Nvmc, + apps: Grant, ++ waiting: OptionalCell, ++ deferred_caller: &'static DynamicDeferredCall, ++ deferred_handle: OptionalCell, +} + +pub const DRIVER_NUM: usize = 0x50003; + +#[derive(Default)] +pub struct App { ++ /// The callback for COMMAND(2) and COMMAND(3). ++ callback: Option, + /// The allow slice for COMMAND(2). + slice: Option>, +} + -+impl SyscallDriver { -+ pub fn new(nvmc: &'static Nvmc, apps: Grant) -> SyscallDriver { -+ SyscallDriver { nvmc, apps } -+ } -+} -+ +fn is_write_needed(old: u32, new: u32) -> bool { + // No need to write if it would not modify the current value. + old & new != old +} + +impl SyscallDriver { ++ pub fn new( ++ nvmc: &'static Nvmc, ++ apps: Grant, ++ deferred_caller: &'static DynamicDeferredCall, ++ ) -> SyscallDriver { ++ SyscallDriver { ++ nvmc, ++ apps, ++ waiting: OptionalCell::empty(), ++ deferred_caller, ++ deferred_handle: OptionalCell::empty(), ++ } ++ } ++ ++ pub fn set_deferred_handle(&self, handle: DeferredCallHandle) { ++ self.deferred_handle.replace(handle); ++ } ++ + /// Writes a word-aligned slice at a word-aligned address. + /// + /// Words are written only if necessary, i.e. if writing the new value would change the current @@ -342,6 +370,8 @@ index b70162cae..9dcb82b07 100644 + } + while !self.nvmc.is_ready() {} + self.nvmc.configure_readonly(); ++ self.deferred_handle ++ .map(|handle| self.deferred_caller.set(*handle)); + ReturnCode::SUCCESS + } + @@ -358,13 +388,41 @@ index b70162cae..9dcb82b07 100644 + } + self.nvmc.erase_page_helper(ptr / PAGE_SIZE); + self.nvmc.configure_readonly(); ++ self.deferred_handle ++ .map(|handle| self.deferred_caller.set(*handle)); + ReturnCode::SUCCESS + } +} + ++impl DynamicDeferredCallClient for SyscallDriver { ++ fn call(&self, _handle: DeferredCallHandle) { ++ self.waiting.take().map(|appid| { ++ self.apps.enter(appid, |app, _| { ++ app.callback.map(|mut cb| { ++ cb.schedule(0, 0, 0); ++ }); ++ }) ++ }); ++ } ++} ++ +impl Driver for SyscallDriver { -+ fn subscribe(&self, _: usize, _: Option, _: AppId) -> ReturnCode { -+ ReturnCode::ENOSUPPORT ++ fn subscribe( ++ &self, ++ subscribe_num: usize, ++ callback: Option, ++ appid: AppId, ++ ) -> ReturnCode { ++ match subscribe_num { ++ 0 => self ++ .apps ++ .enter(appid, |app, _| { ++ app.callback = callback; ++ ReturnCode::SUCCESS ++ }) ++ .unwrap_or_else(|err| err.into()), ++ _ => ReturnCode::ENOSUPPORT, ++ } + } + + fn command(&self, cmd: usize, arg0: usize, arg1: usize, appid: AppId) -> ReturnCode { @@ -391,6 +449,10 @@ index b70162cae..9dcb82b07 100644 + if len != slice.len() { + return ReturnCode::EINVAL; + } ++ if self.waiting.is_some() { ++ return ReturnCode::EBUSY; ++ } ++ self.waiting.set(appid); + self.write_slice(ptr, slice.as_ref()) + }) + .unwrap_or_else(|err| err.into()), @@ -399,6 +461,10 @@ index b70162cae..9dcb82b07 100644 + if len != PAGE_SIZE { + return ReturnCode::EINVAL; + } ++ if self.waiting.is_some() { ++ return ReturnCode::EBUSY; ++ } ++ self.waiting.set(appid); + self.erase_page(ptr) + } + diff --git a/patches/tock/02-usb.patch b/patches/tock/02-usb.patch index 958ae8c..779d1d4 100644 --- a/patches/tock/02-usb.patch +++ b/patches/tock/02-usb.patch @@ -174,7 +174,7 @@ index b485a0997..f5d29d025 100644 }; diff --git a/boards/nordic/nrf52840dk_opensk/src/main.rs b/boards/nordic/nrf52840dk_opensk/src/main.rs -index ebee8704b..6a2f8715b 100644 +index c80732f8d..41047a390 100644 --- a/boards/nordic/nrf52840dk_opensk/src/main.rs +++ b/boards/nordic/nrf52840dk_opensk/src/main.rs @@ -104,6 +104,17 @@ pub mod io; @@ -215,8 +215,8 @@ index ebee8704b..6a2f8715b 100644 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), _ => f(None), } -@@ -371,6 +388,21 @@ pub unsafe fn reset_handler() { - ) +@@ -377,6 +394,21 @@ pub unsafe fn reset_handler() { + .expect("no deferred call slot available for nvmc"), ); + // Enable power events to be sent to USB controller @@ -237,7 +237,7 @@ index ebee8704b..6a2f8715b 100644 nrf52_components::NrfClockComponent::new().finalize(()); let platform = Platform { -@@ -383,6 +415,7 @@ pub unsafe fn reset_handler() { +@@ -389,6 +421,7 @@ pub unsafe fn reset_handler() { alarm, analog_comparator, nvmc, diff --git a/patches/tock/06-firmware-protect.patch b/patches/tock/06-firmware-protect.patch index 84562e4..cc4339c 100644 --- a/patches/tock/06-firmware-protect.patch +++ b/patches/tock/06-firmware-protect.patch @@ -130,7 +130,7 @@ index f5d29d025..051943867 100644 }; diff --git a/boards/nordic/nrf52840dk_opensk/src/main.rs b/boards/nordic/nrf52840dk_opensk/src/main.rs -index 6a2f8715b..7898562dd 100644 +index 41047a390..05e19b821 100644 --- a/boards/nordic/nrf52840dk_opensk/src/main.rs +++ b/boards/nordic/nrf52840dk_opensk/src/main.rs @@ -163,6 +163,7 @@ pub struct Platform { @@ -149,7 +149,7 @@ index 6a2f8715b..7898562dd 100644 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), _ => f(None), } -@@ -403,6 +405,14 @@ pub unsafe fn reset_handler() { +@@ -409,6 +411,14 @@ pub unsafe fn reset_handler() { ) .finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd)); @@ -164,7 +164,7 @@ index 6a2f8715b..7898562dd 100644 nrf52_components::NrfClockComponent::new().finalize(()); let platform = Platform { -@@ -416,6 +426,7 @@ pub unsafe fn reset_handler() { +@@ -422,6 +432,7 @@ pub unsafe fn reset_handler() { analog_comparator, nvmc, usb, diff --git a/patches/tock/07-upgrade-partitions.patch b/patches/tock/07-upgrade-partitions.patch index ba27ea6..7cec670 100644 --- a/patches/tock/07-upgrade-partitions.patch +++ b/patches/tock/07-upgrade-partitions.patch @@ -23,7 +23,7 @@ index daaeaedc7..c4b0afee9 100644 // Static reference to chip for panic dumps diff --git a/boards/nordic/nrf52840dk_opensk/src/main.rs b/boards/nordic/nrf52840dk_opensk/src/main.rs -index 7898562dd..2443cae8a 100644 +index 05e19b821..47b27bf0a 100644 --- a/boards/nordic/nrf52840dk_opensk/src/main.rs +++ b/boards/nordic/nrf52840dk_opensk/src/main.rs @@ -128,6 +128,7 @@ static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROC diff --git a/src/embedded_flash/syscall.rs b/src/embedded_flash/syscall.rs index 5902ca9..eac0947 100644 --- a/src/embedded_flash/syscall.rs +++ b/src/embedded_flash/syscall.rs @@ -15,11 +15,16 @@ use super::helper::{find_slice, is_aligned, ModRange}; use super::upgrade_storage::UpgradeStorage; use alloc::vec::Vec; -use libtock_core::syscalls; +use core::cell::Cell; +use libtock_core::{callback, syscalls}; use persistent_store::{Storage, StorageError, StorageIndex, StorageResult}; const DRIVER_NUMBER: usize = 0x50003; +mod subscribe_nr { + pub const DONE: usize = 0; +} + mod command_nr { pub const GET_INFO: usize = 1; pub mod get_info_nr { @@ -63,6 +68,31 @@ fn memop(nr: u32, arg: usize) -> StorageResult { } } +fn block_command(driver: usize, cmd: usize, arg1: usize, arg2: usize) -> StorageResult<()> { + let done = Cell::new(None); + let mut alarm = |status| done.set(Some(status)); + let subscription = syscalls::subscribe::( + DRIVER_NUMBER, + subscribe_nr::DONE, + &mut alarm, + ); + if subscription.is_err() { + return Err(StorageError::CustomError); + } + + let code = syscalls::command(driver, cmd, arg1, arg2); + if code.is_err() { + return Err(StorageError::CustomError); + } + + libtock_drivers::util::yieldk_for(|| done.get().is_some()); + if done.get().unwrap() == 0 { + Ok(()) + } else { + Err(StorageError::CustomError) + } +} + fn write_slice(ptr: usize, value: &[u8]) -> StorageResult<()> { let code = unsafe { syscalls::raw::allow( @@ -78,20 +108,11 @@ fn write_slice(ptr: usize, value: &[u8]) -> StorageResult<()> { return Err(StorageError::CustomError); } - let code = syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len()); - if code.is_err() { - return Err(StorageError::CustomError); - } - - Ok(()) + block_command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len()) } fn erase_page(ptr: usize, page_length: usize) -> StorageResult<()> { - let code = syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, page_length); - if code.is_err() { - return Err(StorageError::CustomError); - } - Ok(()) + block_command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, page_length) } pub struct SyscallStorage {