Make flash syscall interface async
This commit is contained in:
committed by
Julien Cretin
parent
3d4b652e12
commit
ad0605c2fa
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
+ }
|
||||
+
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user