Make flash syscall interface async

This commit is contained in:
Julien Cretin
2021-08-05 15:14:58 +02:00
committed by Julien Cretin
parent 3d4b652e12
commit ad0605c2fa
6 changed files with 130 additions and 43 deletions

View File

@@ -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) {

View File

@@ -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<DeferredCallTask> =
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<App>,
+ waiting: OptionalCell<AppId>,
+ deferred_caller: &'static DynamicDeferredCall,
+ deferred_handle: OptionalCell<DeferredCallHandle>,
+}
+
+pub const DRIVER_NUM: usize = 0x50003;
+
+#[derive(Default)]
+pub struct App {
+ /// The callback for COMMAND(2) and COMMAND(3).
+ callback: Option<Callback>,
+ /// The allow slice for COMMAND(2).
+ slice: Option<AppSlice<Shared, u8>>,
+}
+
+impl SyscallDriver {
+ pub fn new(nvmc: &'static Nvmc, apps: Grant<App>) -> 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<App>,
+ 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<Callback>, _: AppId) -> ReturnCode {
+ ReturnCode::ENOSUPPORT
+ fn subscribe(
+ &self,
+ subscribe_num: usize,
+ callback: Option<Callback>,
+ 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)
+ }
+

View File

@@ -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,

View File

@@ -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,

View File

@@ -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

View File

@@ -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<usize> {
}
}
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::<callback::Identity1Consumer, _>(
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 {