Move storage bound checking to driver
This commit is contained in:
@@ -42,7 +42,7 @@ index fe493727..105f7120 100644
|
|||||||
|
|
||||||
platform.pconsole.start();
|
platform.pconsole.start();
|
||||||
diff --git a/chips/nrf52/src/nvmc.rs b/chips/nrf52/src/nvmc.rs
|
diff --git a/chips/nrf52/src/nvmc.rs b/chips/nrf52/src/nvmc.rs
|
||||||
index 5abd2d84..5a726fdb 100644
|
index 60fc2da8..77e7423d 100644
|
||||||
--- a/chips/nrf52/src/nvmc.rs
|
--- a/chips/nrf52/src/nvmc.rs
|
||||||
+++ b/chips/nrf52/src/nvmc.rs
|
+++ b/chips/nrf52/src/nvmc.rs
|
||||||
@@ -3,6 +3,7 @@
|
@@ -3,6 +3,7 @@
|
||||||
@@ -62,7 +62,7 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
|
|
||||||
use crate::deferred_call_tasks::DeferredCallTask;
|
use crate::deferred_call_tasks::DeferredCallTask;
|
||||||
|
|
||||||
@@ -141,7 +142,13 @@ register_bitfields! [u32,
|
@@ -141,7 +142,33 @@ register_bitfields! [u32,
|
||||||
static DEFERRED_CALL: DeferredCall<DeferredCallTask> =
|
static DEFERRED_CALL: DeferredCall<DeferredCallTask> =
|
||||||
unsafe { DeferredCall::new(DeferredCallTask::Nvmc) };
|
unsafe { DeferredCall::new(DeferredCallTask::Nvmc) };
|
||||||
|
|
||||||
@@ -73,10 +73,30 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
+const MAX_PAGE_ERASES: usize = 10000;
|
+const MAX_PAGE_ERASES: usize = 10000;
|
||||||
+const WORD_MASK: usize = WORD_SIZE - 1;
|
+const WORD_MASK: usize = WORD_SIZE - 1;
|
||||||
+const PAGE_MASK: usize = PAGE_SIZE - 1;
|
+const PAGE_MASK: usize = PAGE_SIZE - 1;
|
||||||
|
+
|
||||||
|
+// The storage is currently static and readable by all processes. This will be fixed once Tock
|
||||||
|
+// supports persistent storage outside the application flash (i.e. not the current writeable flash
|
||||||
|
+// regions support).
|
||||||
|
+const STORAGE_PTR: usize = 0xc0000;
|
||||||
|
+const STORAGE_LEN: usize = 0x40000;
|
||||||
|
+
|
||||||
|
+fn in_storage(ptr: usize, len: usize) -> bool {
|
||||||
|
+ // We want to check the 2 following inequalities:
|
||||||
|
+ // (1) `STORAGE_PTR <= ptr`
|
||||||
|
+ // (2) `ptr + len <= STORAGE_PTR + STORAGE_LEN`
|
||||||
|
+ // However, the second one may overflow written as is. We introduce a third
|
||||||
|
+ // inequality to solve this issue:
|
||||||
|
+ // (3) `len <= STORAGE_LEN`
|
||||||
|
+ // Using this third inequality, we can rewrite the second one as:
|
||||||
|
+ // (4) `ptr - STORAGE_PTR <= STORAGE_LEN - len`
|
||||||
|
+ // This fourth inequality is equivalent to the second one but doesn't overflow when
|
||||||
|
+ // the first and third inequalities hold.
|
||||||
|
+ STORAGE_PTR <= ptr && len <= STORAGE_LEN && ptr - STORAGE_PTR <= STORAGE_LEN - len
|
||||||
|
+}
|
||||||
|
|
||||||
/// This is a wrapper around a u8 array that is sized to a single page for the
|
/// 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
|
/// nrf. Users of this module must pass an object of this type to use the
|
||||||
@@ -215,6 +222,11 @@ impl Nvmc {
|
@@ -215,6 +242,11 @@ impl Nvmc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +108,7 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
/// Configure the NVMC to allow writes to flash.
|
/// Configure the NVMC to allow writes to flash.
|
||||||
pub fn configure_writeable(&self) {
|
pub fn configure_writeable(&self) {
|
||||||
let regs = &*self.registers;
|
let regs = &*self.registers;
|
||||||
@@ -230,7 +242,7 @@ impl Nvmc {
|
@@ -230,7 +262,7 @@ impl Nvmc {
|
||||||
let regs = &*self.registers;
|
let regs = &*self.registers;
|
||||||
regs.config.write(Configuration::WEN::Een);
|
regs.config.write(Configuration::WEN::Een);
|
||||||
while !self.is_ready() {}
|
while !self.is_ready() {}
|
||||||
@@ -97,7 +117,7 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
while !self.is_ready() {}
|
while !self.is_ready() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +326,7 @@ impl Nvmc {
|
@@ -322,7 +354,7 @@ impl Nvmc {
|
||||||
// Put the NVMC in write mode.
|
// Put the NVMC in write mode.
|
||||||
regs.config.write(Configuration::WEN::Wen);
|
regs.config.write(Configuration::WEN::Wen);
|
||||||
|
|
||||||
@@ -106,7 +126,7 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
let word: u32 = (data[i + 0] as u32) << 0
|
let word: u32 = (data[i + 0] as u32) << 0
|
||||||
| (data[i + 1] as u32) << 8
|
| (data[i + 1] as u32) << 8
|
||||||
| (data[i + 2] as u32) << 16
|
| (data[i + 2] as u32) << 16
|
||||||
@@ -374,3 +386,170 @@ impl hil::flash::Flash for Nvmc {
|
@@ -390,3 +422,178 @@ impl hil::flash::Flash for Nvmc {
|
||||||
self.erase_page(page_number)
|
self.erase_page(page_number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +209,11 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
+ /// Fails with `EINVAL` if any of the following conditions does not hold:
|
+ /// Fails with `EINVAL` if any of the following conditions does not hold:
|
||||||
+ /// - `ptr` must be word-aligned.
|
+ /// - `ptr` must be word-aligned.
|
||||||
+ /// - `slice.len()` must be word-aligned.
|
+ /// - `slice.len()` must be word-aligned.
|
||||||
|
+ /// - The slice starting at `ptr` of length `slice.len()` must fit in the storage.
|
||||||
+ fn write_slice(&self, ptr: usize, slice: &[u8]) -> ReturnCode {
|
+ fn write_slice(&self, ptr: usize, slice: &[u8]) -> ReturnCode {
|
||||||
|
+ if !in_storage(ptr, slice.len()) {
|
||||||
|
+ return ReturnCode::EINVAL;
|
||||||
|
+ }
|
||||||
+ if ptr & WORD_MASK != 0 || slice.len() & WORD_MASK != 0 {
|
+ if ptr & WORD_MASK != 0 || slice.len() & WORD_MASK != 0 {
|
||||||
+ return ReturnCode::EINVAL;
|
+ return ReturnCode::EINVAL;
|
||||||
+ }
|
+ }
|
||||||
@@ -213,7 +237,11 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
+ ///
|
+ ///
|
||||||
+ /// Fails with `EINVAL` if any of the following conditions does not hold:
|
+ /// Fails with `EINVAL` if any of the following conditions does not hold:
|
||||||
+ /// - `ptr` must be page-aligned.
|
+ /// - `ptr` must be page-aligned.
|
||||||
|
+ /// - The slice starting at `ptr` of length `PAGE_SIZE` must fit in the storage.
|
||||||
+ fn erase_page(&self, ptr: usize) -> ReturnCode {
|
+ fn erase_page(&self, ptr: usize) -> ReturnCode {
|
||||||
|
+ if !in_storage(ptr, PAGE_SIZE) {
|
||||||
|
+ return ReturnCode::EINVAL;
|
||||||
|
+ }
|
||||||
+ if ptr & PAGE_MASK != 0 {
|
+ if ptr & PAGE_MASK != 0 {
|
||||||
+ return ReturnCode::EINVAL;
|
+ return ReturnCode::EINVAL;
|
||||||
+ }
|
+ }
|
||||||
@@ -278,14 +306,16 @@ index 5abd2d84..5a726fdb 100644
|
|||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
diff --git a/kernel/src/process.rs b/kernel/src/process.rs
|
diff --git a/kernel/src/process.rs b/kernel/src/process.rs
|
||||||
index eb00f274..35c19d15 100644
|
index eb00f274..663c2422 100644
|
||||||
--- a/kernel/src/process.rs
|
--- a/kernel/src/process.rs
|
||||||
+++ b/kernel/src/process.rs
|
+++ b/kernel/src/process.rs
|
||||||
@@ -1604,6 +1604,31 @@ impl<C: 'static + Chip> Process<'a, C> {
|
@@ -1604,6 +1604,33 @@ impl<C: 'static + Chip> Process<'a, C> {
|
||||||
return Ok((None, 0));
|
return Ok((None, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // Allocate MPU region for storage.
|
+ // Allocate MPU region for storage. The storage is currently static and readable by all
|
||||||
|
+ // processes. This will be fixed once Tock supports persistent storage outside the
|
||||||
|
+ // application flash (i.e. not the current writeable flash regions support).
|
||||||
+ const STORAGE_PTR: usize = 0xc0000;
|
+ const STORAGE_PTR: usize = 0xc0000;
|
||||||
+ const STORAGE_LEN: usize = 0x40000;
|
+ const STORAGE_LEN: usize = 0x40000;
|
||||||
+ if chip
|
+ if chip
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ const PAGE_SIZE: usize = 0x1000;
|
|||||||
// 0xc0000-0xfffff: Store
|
// 0xc0000-0xfffff: Store
|
||||||
#[cfg(not(any(test, feature = "ram_storage")))]
|
#[cfg(not(any(test, feature = "ram_storage")))]
|
||||||
const STORE_ADDR: usize = 0xC0000;
|
const STORE_ADDR: usize = 0xC0000;
|
||||||
const STORE_SIZE_LIMIT: usize = 0x40000;
|
|
||||||
const STORE_SIZE: usize = NUM_PAGES * PAGE_SIZE;
|
const STORE_SIZE: usize = NUM_PAGES * PAGE_SIZE;
|
||||||
|
|
||||||
impl PersistentStore {
|
impl PersistentStore {
|
||||||
@@ -155,8 +154,6 @@ impl PersistentStore {
|
|||||||
///
|
///
|
||||||
/// This should be at most one instance of persistent store per program lifetime.
|
/// This should be at most one instance of persistent store per program lifetime.
|
||||||
pub fn new(rng: &mut impl Rng256) -> PersistentStore {
|
pub fn new(rng: &mut impl Rng256) -> PersistentStore {
|
||||||
// This should ideally be a compile-time assert, but Rust doesn't have native support.
|
|
||||||
assert!(STORE_SIZE <= STORE_SIZE_LIMIT);
|
|
||||||
#[cfg(not(any(test, feature = "ram_storage")))]
|
#[cfg(not(any(test, feature = "ram_storage")))]
|
||||||
let storage = PersistentStore::new_prod_storage();
|
let storage = PersistentStore::new_prod_storage();
|
||||||
#[cfg(any(test, feature = "ram_storage"))]
|
#[cfg(any(test, feature = "ram_storage"))]
|
||||||
|
|||||||
Reference in New Issue
Block a user