Skip to content
Snippets Groups Projects
Commit 62470980 authored by Julien Cretin's avatar Julien Cretin
Browse files

Do not use writeable flash regions for persistent storage

They don't play well with DFU.
parent 20674c51
No related branches found
No related tags found
No related merge requests found
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
*/ */
MEMORY { MEMORY {
/* The application region is 64 bytes (0x40) */ /* The application region is 64 bytes (0x40) and we reserve 0x40000 at the end
FLASH (rx) : ORIGIN = 0x00040040, LENGTH = 0x000BFFC0 * of the flash for the persistent storage.
*/
FLASH (rx) : ORIGIN = 0x00040040, LENGTH = 0x0007FFC0
SRAM (rwx) : ORIGIN = 0x20020000, LENGTH = 128K SRAM (rwx) : ORIGIN = 0x20020000, LENGTH = 128K
} }
......
...@@ -106,7 +106,7 @@ index 5abd2d84..5a726fdb 100644 ...@@ -106,7 +106,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,178 @@ impl hil::flash::Flash for Nvmc { @@ -374,3 +386,170 @@ impl hil::flash::Flash for Nvmc {
self.erase_page(page_number) self.erase_page(page_number)
} }
} }
...@@ -189,11 +189,7 @@ index 5abd2d84..5a726fdb 100644 ...@@ -189,11 +189,7 @@ 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 a writeable flash region. + fn write_slice(&self, ptr: usize, slice: &[u8]) -> ReturnCode {
+ fn write_slice(&self, appid: AppId, ptr: usize, slice: &[u8]) -> ReturnCode {
+ if !appid.in_writeable_flash_region(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;
+ } + }
...@@ -217,11 +213,7 @@ index 5abd2d84..5a726fdb 100644 ...@@ -217,11 +213,7 @@ 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 a writeable flash region. + fn erase_page(&self, ptr: usize) -> ReturnCode {
+ fn erase_page(&self, appid: AppId, ptr: usize) -> ReturnCode {
+ if !appid.in_writeable_flash_region(ptr, PAGE_SIZE) {
+ return ReturnCode::EINVAL;
+ }
+ if ptr & PAGE_MASK != 0 { + if ptr & PAGE_MASK != 0 {
+ return ReturnCode::EINVAL; + return ReturnCode::EINVAL;
+ } + }
...@@ -257,11 +249,11 @@ index 5abd2d84..5a726fdb 100644 ...@@ -257,11 +249,11 @@ index 5abd2d84..5a726fdb 100644
+ None => return ReturnCode::EINVAL, + None => return ReturnCode::EINVAL,
+ Some(slice) => slice, + Some(slice) => slice,
+ }; + };
+ self.write_slice(appid, ptr, slice.as_ref()) + self.write_slice(ptr, slice.as_ref())
+ }) + })
+ .unwrap_or_else(|err| err.into()), + .unwrap_or_else(|err| err.into()),
+ +
+ (3, ptr) => self.erase_page(appid, ptr), + (3, ptr) => self.erase_page(ptr),
+ +
+ _ => ReturnCode::ENOSUPPORT, + _ => ReturnCode::ENOSUPPORT,
+ } + }
...@@ -285,39 +277,3 @@ index 5abd2d84..5a726fdb 100644 ...@@ -285,39 +277,3 @@ index 5abd2d84..5a726fdb 100644
+ } + }
+ } + }
+} +}
diff --git a/kernel/src/callback.rs b/kernel/src/callback.rs
index c812e0bf..bd1613b3 100644
--- a/kernel/src/callback.rs
+++ b/kernel/src/callback.rs
@@ -130,6 +130,31 @@ impl AppId {
(start, end)
})
}
+
+ pub fn in_writeable_flash_region(&self, ptr: usize, len: usize) -> bool {
+ self.kernel.process_map_or(false, *self, |process| {
+ let ptr = match ptr.checked_sub(process.flash_start() as usize) {
+ None => return false,
+ Some(ptr) => ptr,
+ };
+ (0..process.number_writeable_flash_regions()).any(|i| {
+ let (region_ptr, region_len) = process.get_writeable_flash_region(i);
+ let region_ptr = region_ptr as usize;
+ let region_len = region_len as usize;
+ // We want to check the 2 following inequalities:
+ // (1) `region_ptr <= ptr`
+ // (2) `ptr + len <= region_ptr + region_len`
+ // However, the second one may overflow written as is. We introduce a third
+ // inequality to solve this issue:
+ // (3) `len <= region_len`
+ // Using this third inequality, we can rewrite the second one as:
+ // (4) `ptr - region_ptr <= region_len - len`
+ // This fourth inequality is equivalent to the second one but doesn't overflow when
+ // the first and third inequalities hold.
+ region_ptr <= ptr && len <= region_len && ptr - region_ptr <= region_len - len
+ })
+ })
+ }
}
/// Type to uniquely identify a callback subscription across all drivers.
...@@ -138,12 +138,15 @@ const PAGE_SIZE: usize = 0x100; ...@@ -138,12 +138,15 @@ const PAGE_SIZE: usize = 0x100;
#[cfg(not(feature = "ram_storage"))] #[cfg(not(feature = "ram_storage"))]
const PAGE_SIZE: usize = 0x1000; const PAGE_SIZE: usize = 0x1000;
// We have the following layout:
// 0x00000-0x2ffff: Tock
// 0x30000-0x3ffff: Padding
// 0x40000-0xbffff: App
// 0xc0000-0xfffff: Store
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;
#[cfg(not(any(test, feature = "ram_storage")))]
#[link_section = ".app_state"]
static STORE: [u8; STORE_SIZE] = [0xff; STORE_SIZE];
impl PersistentStore { impl PersistentStore {
/// Gives access to the persistent store. /// Gives access to the persistent store.
/// ///
...@@ -164,9 +167,11 @@ impl PersistentStore { ...@@ -164,9 +167,11 @@ impl PersistentStore {
#[cfg(not(any(test, feature = "ram_storage")))] #[cfg(not(any(test, feature = "ram_storage")))]
fn new_prod_storage() -> Storage { fn new_prod_storage() -> Storage {
// This should ideally be a compile-time assert, but Rust doesn't have native support.
assert!(STORE_SIZE <= STORE_SIZE_LIMIT);
let store = unsafe { let store = unsafe {
// Safety: The store cannot alias because this function is called only once. // Safety: The store cannot alias because this function is called only once.
core::slice::from_raw_parts_mut(STORE.as_ptr() as *mut u8, STORE_SIZE) core::slice::from_raw_parts_mut(STORE_ADDR as *mut u8, STORE_SIZE)
}; };
unsafe { unsafe {
// Safety: The store is in a writeable flash region. // Safety: The store is in a writeable flash region.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment