nrf52840dk_thread_tutorial/
main.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//! Tock kernel for the Nordic Semiconductor nRF52840 development kit (DK).
6
7#![no_std]
8#![no_main]
9#![deny(missing_docs)]
10
11use core::ptr::addr_of;
12
13use kernel::component::Component;
14use kernel::platform::{KernelResources, SyscallDriverLookup};
15use kernel::{capabilities, create_capability, static_init};
16use nrf52840::gpio::Pin;
17use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
18use nrf52840dk_lib::{self, NUM_PROCS};
19
20type ScreenDriver = components::screen::ScreenComponentType;
21
22// State for loading and holding applications.
23// How should the kernel respond when a process faults.
24const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
25    capsules_system::process_policies::PanicFaultPolicy {};
26
27type Ieee802154RawDriver =
28    components::ieee802154::Ieee802154RawComponentType<nrf52840::ieee802154_radio::Radio<'static>>;
29
30type AES128CTREncryptionOracleDriver =
31    capsules_extra::tutorials::encryption_oracle_chkpt5::EncryptionOracleDriver<
32        'static,
33        nrf52840::aes::AesECB<'static>,
34    >;
35
36struct Platform {
37    base: nrf52840dk_lib::Platform,
38    ieee802154: &'static Ieee802154RawDriver,
39    eui64: &'static nrf52840dk_lib::Eui64Driver,
40    screen: &'static ScreenDriver,
41    nonvolatile_storage:
42        &'static capsules_extra::isolated_nonvolatile_storage_driver::IsolatedNonvolatileStorage<
43            'static,
44            {
45                components::isolated_nonvolatile_storage::ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT
46            },
47        >,
48    encryption_oracle: &'static AES128CTREncryptionOracleDriver,
49}
50
51impl SyscallDriverLookup for Platform {
52    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
53    where
54        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
55    {
56        match driver_num {
57            capsules_extra::eui64::DRIVER_NUM => f(Some(self.eui64)),
58            capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154)),
59            capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)),
60            capsules_extra::tutorials::encryption_oracle_chkpt5::DRIVER_NUM => {
61                f(Some(self.encryption_oracle))
62            }
63            capsules_extra::isolated_nonvolatile_storage_driver::DRIVER_NUM => {
64                f(Some(self.nonvolatile_storage))
65            }
66            _ => self.base.with_driver(driver_num, f),
67        }
68    }
69}
70
71type Chip = nrf52840dk_lib::Chip;
72
73impl KernelResources<Chip> for Platform {
74    type SyscallDriverLookup = Self;
75    type SyscallFilter = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SyscallFilter;
76    type ProcessFault = <nrf52840dk_lib::Platform as KernelResources<Chip>>::ProcessFault;
77    type Scheduler = <nrf52840dk_lib::Platform as KernelResources<Chip>>::Scheduler;
78    type SchedulerTimer = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SchedulerTimer;
79    type WatchDog = <nrf52840dk_lib::Platform as KernelResources<Chip>>::WatchDog;
80    type ContextSwitchCallback =
81        <nrf52840dk_lib::Platform as KernelResources<Chip>>::ContextSwitchCallback;
82
83    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
84        self
85    }
86    fn syscall_filter(&self) -> &Self::SyscallFilter {
87        self.base.syscall_filter()
88    }
89    fn process_fault(&self) -> &Self::ProcessFault {
90        self.base.process_fault()
91    }
92    fn scheduler(&self) -> &Self::Scheduler {
93        self.base.scheduler()
94    }
95    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
96        self.base.scheduler_timer()
97    }
98    fn watchdog(&self) -> &Self::WatchDog {
99        self.base.watchdog()
100    }
101    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
102        self.base.context_switch_callback()
103    }
104}
105
106/// Main function called after RAM initialized.
107#[no_mangle]
108pub unsafe fn main() {
109    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
110
111    // Create the base board:
112    let (board_kernel, base_platform, chip, nrf52840_peripherals, _mux_alarm) =
113        nrf52840dk_lib::start();
114
115    //--------------------------------------------------------------------------
116    // RAW 802.15.4
117    //--------------------------------------------------------------------------
118
119    let device_id = (*addr_of!(nrf52840::ficr::FICR_INSTANCE)).id();
120
121    let eui64 = components::eui64::Eui64Component::new(u64::from_le_bytes(device_id))
122        .finalize(components::eui64_component_static!());
123
124    let ieee802154 = components::ieee802154::Ieee802154RawComponent::new(
125        board_kernel,
126        capsules_extra::ieee802154::DRIVER_NUM,
127        &nrf52840_peripherals.ieee802154_radio,
128    )
129    .finalize(components::ieee802154_raw_component_static!(
130        nrf52840::ieee802154_radio::Radio,
131    ));
132
133    //--------------------------------------------------------------------------
134    // AES Encryption Oracle
135    //--------------------------------------------------------------------------
136    const CRYPT_SIZE: usize = 7 * kernel::hil::symmetric_encryption::AES128_BLOCK_SIZE;
137    let aes_src_buffer = kernel::static_init!([u8; 16], [0; 16]);
138    let aes_dst_buffer = kernel::static_init!([u8; CRYPT_SIZE], [0; CRYPT_SIZE]);
139
140    let encryption_oracle = static_init!(
141        AES128CTREncryptionOracleDriver,
142        AES128CTREncryptionOracleDriver::new(
143            &nrf52840_peripherals.nrf52.ecb,
144            aes_src_buffer,
145            aes_dst_buffer,
146            board_kernel.create_grant(
147                capsules_extra::tutorials::encryption_oracle_chkpt5::DRIVER_NUM,
148                &create_capability!(capabilities::MemoryAllocationCapability)
149            )
150        )
151    );
152
153    kernel::hil::symmetric_encryption::AES128::set_client(
154        &nrf52840_peripherals.nrf52.ecb,
155        encryption_oracle,
156    );
157    //--------------------------------------------------------------------------
158    // SCREEN
159    //--------------------------------------------------------------------------
160
161    const SCREEN_I2C_SDA_PIN: Pin = Pin::P1_10;
162    const SCREEN_I2C_SCL_PIN: Pin = Pin::P1_11;
163
164    let i2c_bus = components::i2c::I2CMuxComponent::new(&nrf52840_peripherals.nrf52.twi1, None)
165        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
166    nrf52840_peripherals.nrf52.twi1.configure(
167        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SCL_PIN as u32),
168        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SDA_PIN as u32),
169    );
170    nrf52840_peripherals
171        .nrf52
172        .twi1
173        .set_speed(nrf52840::i2c::Speed::K400);
174
175    // I2C address is b011110X, and on this board D/C̅ is GND.
176    let ssd1306_sh1106_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
177        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
178
179    // Create the ssd1306 object for the actual screen driver.
180    #[cfg(feature = "screen_ssd1306")]
181    let ssd1306_sh1106 = components::ssd1306::Ssd1306Component::new(ssd1306_sh1106_i2c, true)
182        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
183
184    #[cfg(feature = "screen_sh1106")]
185    let ssd1306_sh1106 = components::sh1106::Sh1106Component::new(ssd1306_sh1106_i2c, true)
186        .finalize(components::sh1106_component_static!(nrf52840::i2c::TWI));
187
188    let screen = components::screen::ScreenComponent::new(
189        board_kernel,
190        capsules_extra::screen::DRIVER_NUM,
191        ssd1306_sh1106,
192        None,
193    )
194    .finalize(components::screen_component_static!(1032));
195
196    ssd1306_sh1106.init_screen();
197
198    //--------------------------------------------------------------------------
199    // NONVOLATILE STORAGE
200    //--------------------------------------------------------------------------
201
202    // 32kB of userspace-accessible storage, page aligned:
203    kernel::storage_volume!(APP_STORAGE, 32);
204
205    let nonvolatile_storage = components::isolated_nonvolatile_storage::IsolatedNonvolatileStorageComponent::new(
206        board_kernel,
207        capsules_extra::isolated_nonvolatile_storage_driver::DRIVER_NUM,
208        &nrf52840_peripherals.nrf52.nvmc,
209        core::ptr::addr_of!(APP_STORAGE) as usize,
210        APP_STORAGE.len()
211    )
212    .finalize(components::isolated_nonvolatile_storage_component_static!(
213        nrf52840::nvmc::Nvmc,
214        { components::isolated_nonvolatile_storage::ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT }
215    ));
216
217    //--------------------------------------------------------------------------
218    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
219    //--------------------------------------------------------------------------
220
221    let platform = Platform {
222        base: base_platform,
223        eui64,
224        ieee802154,
225        screen,
226        nonvolatile_storage,
227        encryption_oracle,
228    };
229
230    //--------------------------------------------------------------------------
231    // CREDENTIAL CHECKING
232    //--------------------------------------------------------------------------
233
234    // Create the credential checker.
235    let checking_policy = components::appid::checker_null::AppCheckerNullComponent::new()
236        .finalize(components::app_checker_null_component_static!());
237
238    // Create the AppID assigner.
239    let assigner = components::appid::assigner_name::AppIdAssignerNamesComponent::new()
240        .finalize(components::appid_assigner_names_component_static!());
241
242    // Create the process checking machine.
243    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
244        .finalize(components::process_checker_machine_component_static!());
245
246    //--------------------------------------------------------------------------
247    // STORAGE PERMISSIONS
248    //--------------------------------------------------------------------------
249
250    let storage_permissions_policy =
251        components::storage_permissions::individual::StoragePermissionsIndividualComponent::new()
252            .finalize(
253                components::storage_permissions_individual_component_static!(
254                    nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
255                    kernel::process::ProcessStandardDebugFull,
256                ),
257            );
258
259    //--------------------------------------------------------------------------
260    // PROCESS LOADING
261    //--------------------------------------------------------------------------
262
263    // These symbols are defined in the standard Tock linker script.
264    extern "C" {
265        /// Beginning of the ROM region containing app images.
266        static _sapps: u8;
267        /// End of the ROM region containing app images.
268        static _eapps: u8;
269        /// Beginning of the RAM region for app memory.
270        static mut _sappmem: u8;
271        /// End of the RAM region for app memory.
272        static _eappmem: u8;
273    }
274
275    let app_flash = core::slice::from_raw_parts(
276        core::ptr::addr_of!(_sapps),
277        core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
278    );
279    let app_memory = core::slice::from_raw_parts_mut(
280        core::ptr::addr_of_mut!(_sappmem),
281        core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
282    );
283
284    // Create and start the asynchronous process loader.
285    let _loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
286        checker,
287        board_kernel,
288        chip,
289        &FAULT_RESPONSE,
290        assigner,
291        storage_permissions_policy,
292        app_flash,
293        app_memory,
294    )
295    .finalize(components::process_loader_sequential_component_static!(
296        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
297        kernel::process::ProcessStandardDebugFull,
298        NUM_PROCS
299    ));
300
301    board_kernel.kernel_loop(
302        &platform,
303        chip,
304        Some(&platform.base.ipc),
305        &main_loop_capability,
306    );
307}