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

@@ -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)
+ }
+