components/
isolated_nonvolatile_storage.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Component for isolated non-volatile storage Drivers.
6//!
7//! This provides one component, IsolatedNonvolatileStorageComponent, which provides
8//! a system call interface to isolated non-volatile storage.
9//!
10//! This differs from NonvolatileStorageComponent in that it provides isolation
11//! between apps. Each app has it's own storage address space (that starts at 0)
12//! which doesn't interfere with other apps.
13//!
14//! Usage
15//! -----
16//! ```rust
17//! let nonvolatile_storage = components::isolated_nonvolatile_storage::IsolatedNonvolatileStorageComponent::new(
18//!     board_kernel,
19//!     &sam4l::flashcalw::FLASH_CONTROLLER,
20//!     0x60000,
21//!     0x20000,
22//! )
23//! .finalize(components::isolated_nonvolatile_storage_component_static!(
24//!     sam4l::flashcalw::FLASHCALW
25//! ));
26//! ```
27
28use capsules_extra::isolated_nonvolatile_storage_driver::IsolatedNonvolatileStorage;
29use capsules_extra::nonvolatile_to_pages::NonvolatileToPages;
30use core::mem::MaybeUninit;
31use kernel::capabilities;
32use kernel::component::Component;
33use kernel::create_capability;
34use kernel::hil;
35
36// How much storage space to allocate per-app. Currently, regions are not
37// growable, so this will be all the space the app gets.
38// Only affects newly allocated regions. Old regions can remain the same size.
39pub const ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT: usize = 2048;
40
41// Setup static space for the objects.
42#[macro_export]
43macro_rules! isolated_nonvolatile_storage_component_static {
44    ($F:ty, $APP_REGION_SIZE:expr $(,)?) => {{
45        let page = kernel::static_buf!(<$F as kernel::hil::flash::Flash>::Page);
46        let ntp = kernel::static_buf!(
47            capsules_extra::nonvolatile_to_pages::NonvolatileToPages<'static, $F>
48        );
49        let ns = kernel::static_buf!(
50            capsules_extra::isolated_nonvolatile_storage_driver::IsolatedNonvolatileStorage<
51                'static,
52                $APP_REGION_SIZE,
53            >
54        );
55        let buffer =
56            kernel::static_buf!([u8; capsules_extra::isolated_nonvolatile_storage_driver::BUF_LEN]);
57
58        (page, ntp, ns, buffer)
59    };};
60}
61
62pub type IsolatedNonvolatileStorageComponentType<const APP_REGION_SIZE: usize> =
63    IsolatedNonvolatileStorage<'static, APP_REGION_SIZE>;
64
65pub struct IsolatedNonvolatileStorageComponent<
66    F: 'static + hil::flash::Flash + hil::flash::HasClient<'static, NonvolatileToPages<'static, F>>,
67    const APP_REGION_SIZE: usize,
68> {
69    board_kernel: &'static kernel::Kernel,
70    driver_num: usize,
71    flash: &'static F,
72    userspace_start: usize,
73    userspace_length: usize,
74}
75
76impl<
77        F: 'static
78            + hil::flash::Flash
79            + hil::flash::HasClient<'static, NonvolatileToPages<'static, F>>,
80        const APP_REGION_SIZE: usize,
81    > IsolatedNonvolatileStorageComponent<F, APP_REGION_SIZE>
82{
83    pub fn new(
84        board_kernel: &'static kernel::Kernel,
85        driver_num: usize,
86        flash: &'static F,
87        userspace_start: usize,
88        userspace_length: usize,
89    ) -> Self {
90        Self {
91            board_kernel,
92            driver_num,
93            flash,
94            userspace_start,
95            userspace_length,
96        }
97    }
98}
99
100impl<
101        F: 'static
102            + hil::flash::Flash
103            + hil::flash::HasClient<'static, NonvolatileToPages<'static, F>>,
104        const APP_REGION_SIZE: usize,
105    > Component for IsolatedNonvolatileStorageComponent<F, APP_REGION_SIZE>
106{
107    type StaticInput = (
108        &'static mut MaybeUninit<<F as hil::flash::Flash>::Page>,
109        &'static mut MaybeUninit<NonvolatileToPages<'static, F>>,
110        &'static mut MaybeUninit<IsolatedNonvolatileStorage<'static, APP_REGION_SIZE>>,
111        &'static mut MaybeUninit<
112            [u8; capsules_extra::isolated_nonvolatile_storage_driver::BUF_LEN],
113        >,
114    );
115    type Output = &'static IsolatedNonvolatileStorage<'static, APP_REGION_SIZE>;
116
117    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
118        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
119
120        let buffer = static_buffer
121            .3
122            .write([0; capsules_extra::isolated_nonvolatile_storage_driver::BUF_LEN]);
123
124        let flash_pagebuffer = static_buffer
125            .0
126            .write(<F as hil::flash::Flash>::Page::default());
127
128        let nv_to_page = static_buffer
129            .1
130            .write(NonvolatileToPages::new(self.flash, flash_pagebuffer));
131        hil::flash::HasClient::set_client(self.flash, nv_to_page);
132
133        let nonvolatile_storage = static_buffer.2.write(IsolatedNonvolatileStorage::new(
134            nv_to_page,
135            self.board_kernel.create_grant(self.driver_num, &grant_cap),
136            self.userspace_start, // Start address for userspace accessible region
137            self.userspace_length, // Length of userspace accessible region
138            buffer,
139        ));
140        hil::nonvolatile_storage::NonvolatileStorage::set_client(nv_to_page, nonvolatile_storage);
141        nonvolatile_storage
142    }
143}