nrf52840dk_dynamic_apps_and_policies/
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 nRF52840-based dynamic processes and policies tutorial.
6
7#![no_std]
8#![no_main]
9#![deny(missing_docs)]
10
11use kernel::component::Component;
12use kernel::deferred_call::DeferredCallClient;
13use kernel::platform::{KernelResources, SyscallDriverLookup};
14use kernel::process::ProcessLoadingAsync;
15use kernel::process::ShortId;
16use kernel::{capabilities, create_capability, static_init};
17use nrf52840::gpio::Pin;
18use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
19
20mod app_id_assigner_name_metadata;
21mod checker_credentials_not_required;
22mod system_call_filter;
23
24// GPIO used for the screen shield
25const SCREEN_I2C_SDA_PIN: Pin = Pin::P1_10;
26const SCREEN_I2C_SCL_PIN: Pin = Pin::P1_11;
27
28// Number of concurrent processes this platform supports.
29const NUM_PROCS: usize = 8;
30
31type ChipHw = nrf52840dk_lib::ChipHw;
32
33// How should the kernel respond when a process faults.
34const FAULT_RESPONSE: capsules_system::process_policies::StopWithDebugFaultPolicy =
35    capsules_system::process_policies::StopWithDebugFaultPolicy {};
36
37// How many credential verifying keys the kernel supports.
38const NUM_CREDENTIAL_KEYS: usize = 1;
39// Length of the key used for the ECDSA-P256 signature.
40const SIGNATURE_KEY_LEN: usize = 64;
41// Length of the hash used for the signature (SHA-256).
42const SIGNATURE_HASH_LEN: usize = 32;
43// Length of the ECDSA-P256 signature.
44const SIGNATURE_SIG_LEN: usize = 64;
45
46//------------------------------------------------------------------------------
47// SYSCALL DRIVER TYPE DEFINITIONS
48//------------------------------------------------------------------------------
49
50/// Needed for process info capsule.
51pub struct PMCapability;
52unsafe impl capabilities::ProcessManagementCapability for PMCapability {}
53unsafe impl capabilities::ProcessStartCapability for PMCapability {}
54
55#[cfg(feature = "screen_ssd1306")]
56type Screen = components::ssd1306::Ssd1306ComponentType<nrf52840::i2c::TWI<'static>>;
57#[cfg(feature = "screen_sh1106")]
58type Screen = components::sh1106::Sh1106ComponentType<nrf52840::i2c::TWI<'static>>;
59type ScreenDriver = components::screen::ScreenSharedComponentType<Screen>;
60
61type ProcessInfoDriver = capsules_extra::process_info_driver::ProcessInfo<PMCapability>;
62
63type IsolatedNonvolatileStorageDriver =
64    capsules_extra::isolated_nonvolatile_storage_driver::IsolatedNonvolatileStorage<
65        'static,
66        {
67            components::isolated_nonvolatile_storage::ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT
68        },
69    >;
70
71type FlashUser =
72    capsules_core::virtualizers::virtual_flash::FlashUser<'static, nrf52840::nvmc::Nvmc>;
73type NonVolatilePages = components::dynamic_binary_storage::NVPages<FlashUser>;
74
75type DynamicBinaryStorage<'a> = kernel::dynamic_binary_storage::SequentialDynamicBinaryStorage<
76    'static,
77    'static,
78    nrf52840::chip::NRF52<'a, Nrf52840DefaultPeripherals<'a>>,
79    kernel::process::ProcessStandardDebugFull,
80    NonVolatilePages,
81>;
82type AppLoaderDriver = capsules_extra::app_loader::AppLoader<
83    DynamicBinaryStorage<'static>,
84    DynamicBinaryStorage<'static>,
85>;
86
87type Verifier = ecdsa_sw::p256_verifier::EcdsaP256SignatureVerifier<'static>;
88type SignatureVerifyInMemoryKeys =
89    components::signature_verify_in_memory_keys::SignatureVerifyInMemoryKeysComponentType<
90        Verifier,
91        NUM_CREDENTIAL_KEYS,
92        SIGNATURE_KEY_LEN,
93        SIGNATURE_HASH_LEN,
94        SIGNATURE_SIG_LEN,
95    >;
96type SignatureChecker = components::appid::checker_signature::AppCheckerSignatureComponentType<
97    SignatureVerifyInMemoryKeys,
98    capsules_extra::sha256::Sha256Software<'static>,
99    SIGNATURE_HASH_LEN,
100    SIGNATURE_SIG_LEN,
101>;
102
103//------------------------------------------------------------------------------
104// SHORTID HELPER FUNCTION
105//------------------------------------------------------------------------------
106
107fn create_short_id_from_name(name: &str, metadata: u8) -> ShortId {
108    let sum = kernel::utilities::helpers::crc32_posix(name.as_bytes());
109
110    // Combine the metadata and CRC into the short id.
111    let sid = ((metadata as u32) << 28) | (sum & 0xFFFFFFF);
112
113    core::num::NonZeroU32::new(sid).into()
114}
115
116//------------------------------------------------------------------------------
117// PLATFORM
118//------------------------------------------------------------------------------
119
120struct Platform {
121    board_kernel: &'static kernel::Kernel,
122    syscall_filter: &'static system_call_filter::DynamicPoliciesCustomFilter,
123    base: nrf52840dk_lib::Platform,
124    screen: &'static ScreenDriver,
125    process_info: &'static ProcessInfoDriver,
126    nonvolatile_storage: &'static IsolatedNonvolatileStorageDriver,
127    dynamic_app_loader: &'static AppLoaderDriver,
128}
129
130// Expose system call interfaces to userspace.
131impl SyscallDriverLookup for Platform {
132    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
133    where
134        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
135    {
136        match driver_num {
137            capsules_extra::screen::screen::DRIVER_NUM => f(Some(self.screen)),
138            capsules_extra::process_info_driver::DRIVER_NUM => f(Some(self.process_info)),
139            capsules_extra::isolated_nonvolatile_storage_driver::DRIVER_NUM => {
140                f(Some(self.nonvolatile_storage))
141            }
142            capsules_extra::app_loader::DRIVER_NUM => f(Some(self.dynamic_app_loader)),
143            _ => self.base.with_driver(driver_num, f),
144        }
145    }
146}
147
148// Configure the kernel.
149impl KernelResources<ChipHw> for Platform {
150    type SyscallDriverLookup = Self;
151    type SyscallFilter = system_call_filter::DynamicPoliciesCustomFilter;
152    type ProcessFault = <nrf52840dk_lib::Platform as KernelResources<ChipHw>>::ProcessFault;
153    type Scheduler = <nrf52840dk_lib::Platform as KernelResources<ChipHw>>::Scheduler;
154    type SchedulerTimer = <nrf52840dk_lib::Platform as KernelResources<ChipHw>>::SchedulerTimer;
155    type WatchDog = <nrf52840dk_lib::Platform as KernelResources<ChipHw>>::WatchDog;
156    type ContextSwitchCallback =
157        <nrf52840dk_lib::Platform as KernelResources<ChipHw>>::ContextSwitchCallback;
158
159    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
160        self
161    }
162    fn syscall_filter(&self) -> &Self::SyscallFilter {
163        self.syscall_filter
164    }
165    fn process_fault(&self) -> &Self::ProcessFault {
166        self.base.process_fault()
167    }
168    fn scheduler(&self) -> &Self::Scheduler {
169        self.base.scheduler()
170    }
171    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
172        self.base.scheduler_timer()
173    }
174    fn watchdog(&self) -> &Self::WatchDog {
175        self.base.watchdog()
176    }
177    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
178        self.base.context_switch_callback()
179    }
180}
181
182// Called by the process loader when the board boots.
183impl kernel::process::ProcessLoadingAsyncClient for Platform {
184    fn process_loaded(&self, _result: Result<(), kernel::process::ProcessLoadError>) {}
185
186    fn process_loading_finished(&self) {
187        kernel::debug!("Processes Loaded at Main:");
188
189        for (i, p) in self
190            .board_kernel
191            .process_iter_capability(&create_capability!(
192                capabilities::ProcessManagementCapability
193            ))
194            .enumerate()
195        {
196            kernel::debug!("[{}] {}", i, p.get_process_name());
197            kernel::debug!("    ShortId: {}", p.short_app_id());
198        }
199    }
200}
201
202//------------------------------------------------------------------------------
203// MAIN
204//------------------------------------------------------------------------------
205
206/// Main function called after RAM initialized.
207#[no_mangle]
208pub unsafe fn main() {
209    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
210
211    // Create the base board:
212    let (board_kernel, base_platform, chip, nrf52840_peripherals, _mux_alarm) =
213        nrf52840dk_lib::start();
214
215    //--------------------------------------------------------------------------
216    // SCREEN
217    //--------------------------------------------------------------------------
218
219    let i2c_bus = components::i2c::I2CMuxComponent::new(&nrf52840_peripherals.nrf52.twi1, None)
220        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
221    nrf52840_peripherals.nrf52.twi1.configure(
222        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SCL_PIN as u32),
223        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SDA_PIN as u32),
224    );
225    nrf52840_peripherals
226        .nrf52
227        .twi1
228        .set_speed(nrf52840::i2c::Speed::K400);
229
230    // I2C address is b011110X, and on this board D/C̅ is GND.
231    let ssd1306_sh1106_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
232        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
233
234    // Create the ssd1306 object for the actual screen driver.
235    #[cfg(feature = "screen_ssd1306")]
236    let ssd1306_sh1106 = components::ssd1306::Ssd1306Component::new(ssd1306_sh1106_i2c, true)
237        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
238
239    #[cfg(feature = "screen_sh1106")]
240    let ssd1306_sh1106 = components::sh1106::Sh1106Component::new(ssd1306_sh1106_i2c, true)
241        .finalize(components::sh1106_component_static!(nrf52840::i2c::TWI));
242
243    let apps_regions = kernel::static_init!(
244        [capsules_extra::screen::screen_shared::AppScreenRegion; 3],
245        [
246            capsules_extra::screen::screen_shared::AppScreenRegion::new(
247                create_short_id_from_name("process_manager", 0x0),
248                0,      // x
249                0,      // y
250                16 * 8, // width
251                7 * 8   // height
252            ),
253            capsules_extra::screen::screen_shared::AppScreenRegion::new(
254                create_short_id_from_name("counter", 0x0),
255                0,     // x
256                7 * 8, // y
257                8 * 8, // width
258                1 * 8  // height
259            ),
260            capsules_extra::screen::screen_shared::AppScreenRegion::new(
261                create_short_id_from_name("temperature", 0x0),
262                8 * 8, // x
263                7 * 8, // y
264                8 * 8, // width
265                1 * 8  // height
266            )
267        ]
268    );
269
270    let screen = components::screen::ScreenSharedComponent::new(
271        board_kernel,
272        capsules_extra::screen::screen::DRIVER_NUM,
273        ssd1306_sh1106,
274        apps_regions,
275    )
276    .finalize(components::screen_shared_component_static!(1032, Screen));
277
278    ssd1306_sh1106.init_screen();
279
280    //--------------------------------------------------------------------------
281    // VIRTUAL FLASH
282    //--------------------------------------------------------------------------
283
284    let mux_flash = components::flash::FlashMuxComponent::new(&nrf52840_peripherals.nrf52.nvmc)
285        .finalize(components::flash_mux_component_static!(
286            nrf52840::nvmc::Nvmc
287        ));
288
289    // Create a virtual flash user for dynamic binary storage
290    let virtual_flash_dbs = components::flash::FlashUserComponent::new(mux_flash).finalize(
291        components::flash_user_component_static!(nrf52840::nvmc::Nvmc),
292    );
293
294    // Create a virtual flash user for nonvolatile
295    let virtual_flash_nvm = components::flash::FlashUserComponent::new(mux_flash).finalize(
296        components::flash_user_component_static!(nrf52840::nvmc::Nvmc),
297    );
298
299    //--------------------------------------------------------------------------
300    // NONVOLATILE STORAGE
301    //--------------------------------------------------------------------------
302
303    // 32kB of userspace-accessible storage, page aligned:
304    kernel::storage_volume!(APP_STORAGE, 32);
305
306    let nonvolatile_storage = components::isolated_nonvolatile_storage::IsolatedNonvolatileStorageComponent::new(
307        board_kernel,
308        capsules_extra::isolated_nonvolatile_storage_driver::DRIVER_NUM,
309        virtual_flash_nvm,
310        core::ptr::addr_of!(APP_STORAGE) as usize,
311        APP_STORAGE.len()
312    )
313    .finalize(components::isolated_nonvolatile_storage_component_static!(
314        capsules_core::virtualizers::virtual_flash::FlashUser<'static, nrf52840::nvmc::Nvmc>,
315        { components::isolated_nonvolatile_storage::ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT }
316    ));
317
318    //--------------------------------------------------------------------------
319    // PROCESS INFO FOR USERSPACE
320    //--------------------------------------------------------------------------
321
322    let process_info = components::process_info_driver::ProcessInfoComponent::new(
323        board_kernel,
324        capsules_extra::process_info_driver::DRIVER_NUM,
325        PMCapability,
326    )
327    .finalize(components::process_info_component_static!(PMCapability));
328
329    //--------------------------------------------------------------------------
330    // SYSTEM CALL FILTERING
331    //--------------------------------------------------------------------------
332
333    let syscall_filter = static_init!(
334        system_call_filter::DynamicPoliciesCustomFilter,
335        system_call_filter::DynamicPoliciesCustomFilter {}
336    );
337
338    //--------------------------------------------------------------------------
339    // CREDENTIAL CHECKING
340    //--------------------------------------------------------------------------
341
342    // Create the software-based SHA engine.
343    let sha = components::sha::ShaSoftware256Component::new()
344        .finalize(components::sha_software_256_component_static!());
345
346    // Create the credential checker.
347    //
348    // Setup an example key.
349    //
350    // - `ec-secp256r1-priv-key.pem`:
351    //   ```
352    //   -----BEGIN EC PRIVATE KEY-----
353    //   MHcCAQEEIGU0zCXHLqxDmrHHAWEQP5zNfWRQrAiIpH9YwxHlqysmoAoGCCqGSM49
354    //   AwEHoUQDQgAE4BM6kKdKNWFRjuFECfFpwc9q239+Uvi3QXniTVdBI1IuthIDs4UQ
355    //   5fMlB2KPVJWCV0VQvaPiF+g0MIkmTCNisQ==
356    //   -----END EC PRIVATE KEY-----
357    //   ```
358    //
359    // - `ec-secp256r1-pub-key.pem`:
360    //   ```
361    //   -----BEGIN PUBLIC KEY-----
362    //   MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4BM6kKdKNWFRjuFECfFpwc9q239+
363    //   Uvi3QXniTVdBI1IuthIDs4UQ5fMlB2KPVJWCV0VQvaPiF+g0MIkmTCNisQ==
364    //   -----END PUBLIC KEY-----
365    //   ```
366    //
367    // You can add the correct signature to a TBF by saving the private key to
368    // a file and then running:
369    //
370    //     tockloader tbf credential add ecdsap256 --private-key ec-secp256r1-priv-key.pem
371    //
372    let verifying_key0 = kernel::static_init!(
373        [u8; SIGNATURE_KEY_LEN],
374        [
375            0xe0, 0x13, 0x3a, 0x90, 0xa7, 0x4a, 0x35, 0x61, 0x51, 0x8e, 0xe1, 0x44, 0x09, 0xf1,
376            0x69, 0xc1, 0xcf, 0x6a, 0xdb, 0x7f, 0x7e, 0x52, 0xf8, 0xb7, 0x41, 0x79, 0xe2, 0x4d,
377            0x57, 0x41, 0x23, 0x52, 0x2e, 0xb6, 0x12, 0x03, 0xb3, 0x85, 0x10, 0xe5, 0xf3, 0x25,
378            0x07, 0x62, 0x8f, 0x54, 0x95, 0x82, 0x57, 0x45, 0x50, 0xbd, 0xa3, 0xe2, 0x17, 0xe8,
379            0x34, 0x30, 0x89, 0x26, 0x4c, 0x23, 0x62, 0xb1
380        ]
381    );
382    let verifying_keys = kernel::static_init!(
383        [&'static mut [u8; SIGNATURE_KEY_LEN]; NUM_CREDENTIAL_KEYS],
384        [verifying_key0]
385    );
386    // Setup the ECDSA-P256 verifier.
387    let ecdsa_p256_verifying_key =
388        kernel::static_init!([u8; SIGNATURE_KEY_LEN], [0; SIGNATURE_KEY_LEN]);
389    let ecdsa_p256_verifier = kernel::static_init!(
390        ecdsa_sw::p256_verifier::EcdsaP256SignatureVerifier<'static>,
391        ecdsa_sw::p256_verifier::EcdsaP256SignatureVerifier::new(ecdsa_p256_verifying_key)
392    );
393    ecdsa_p256_verifier.register();
394
395    // Setup the in-memory key selector.
396    let verifier_multiple_keys =
397        components::signature_verify_in_memory_keys::SignatureVerifyInMemoryKeysComponent::new(
398            ecdsa_p256_verifier,
399            verifying_keys,
400        )
401        .finalize(
402            components::signature_verify_in_memory_keys_component_static!(
403                Verifier,
404                NUM_CREDENTIAL_KEYS,
405                SIGNATURE_KEY_LEN,
406                SIGNATURE_HASH_LEN,
407                SIGNATURE_SIG_LEN,
408            ),
409        );
410
411    // Policy checks for a valid EcdsaNistP256 signature.
412    let checking_policy_signature =
413        components::appid::checker_signature::AppCheckerSignatureComponent::new(
414            sha,
415            verifier_multiple_keys,
416            tock_tbf::types::TbfFooterV2CredentialsType::EcdsaNistP256,
417        )
418        .finalize(components::app_checker_signature_component_static!(
419            SignatureVerifyInMemoryKeys,
420            capsules_extra::sha256::Sha256Software<'static>,
421            SIGNATURE_HASH_LEN,
422            SIGNATURE_SIG_LEN,
423        ));
424
425    // Wrap the policy checker with a custom version that does not require valid
426    // credentials to load the app. We are ok with this for this tutorial
427    // because the verifying key (or lack thereof) is encoded in the AppId so
428    // we can still check if an app is signed or not.
429    let checking_policy = static_init!(
430        checker_credentials_not_required::AppCheckerCredentialsNotRequired<
431            SignatureChecker,
432        >,
433        checker_credentials_not_required::AppCheckerCredentialsNotRequired::new(
434            checking_policy_signature
435        ),
436    );
437
438    // Create the AppID assigner.
439    let assigner = static_init!(
440        app_id_assigner_name_metadata::AppIdAssignerNameMetadata,
441        app_id_assigner_name_metadata::AppIdAssignerNameMetadata::new()
442    );
443
444    // Create the process checking machine.
445    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
446        .finalize(components::process_checker_machine_component_static!());
447
448    //--------------------------------------------------------------------------
449    // STORAGE PERMISSIONS
450    //--------------------------------------------------------------------------
451
452    let storage_permissions_policy =
453        components::storage_permissions::null::StoragePermissionsNullComponent::new().finalize(
454            components::storage_permissions_null_component_static!(
455                nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
456                kernel::process::ProcessStandardDebugFull,
457            ),
458        );
459
460    //--------------------------------------------------------------------------
461    // PROCESS LOADING
462    //--------------------------------------------------------------------------
463
464    // These symbols are defined in the standard Tock linker script.
465    extern "C" {
466        /// Beginning of the ROM region containing app images.
467        static _sapps: u8;
468        /// End of the ROM region containing app images.
469        static _eapps: u8;
470        /// Beginning of the RAM region for app memory.
471        static mut _sappmem: u8;
472        /// End of the RAM region for app memory.
473        static _eappmem: u8;
474    }
475
476    let app_flash = core::slice::from_raw_parts(
477        core::ptr::addr_of!(_sapps),
478        core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
479    );
480    let app_memory = core::slice::from_raw_parts_mut(
481        core::ptr::addr_of_mut!(_sappmem),
482        core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
483    );
484
485    // Create and start the asynchronous process loader.
486    let loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
487        checker,
488        board_kernel,
489        chip,
490        &FAULT_RESPONSE,
491        assigner,
492        storage_permissions_policy,
493        app_flash,
494        app_memory,
495    )
496    .finalize(components::process_loader_sequential_component_static!(
497        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
498        kernel::process::ProcessStandardDebugFull,
499        NUM_PROCS
500    ));
501
502    //--------------------------------------------------------------------------
503    // DYNAMIC PROCESS LOADING
504    //--------------------------------------------------------------------------
505
506    // Create the dynamic binary flasher.
507    let dynamic_binary_storage =
508        components::dynamic_binary_storage::SequentialBinaryStorageComponent::new(
509            virtual_flash_dbs,
510            loader,
511        )
512        .finalize(components::sequential_binary_storage_component_static!(
513            FlashUser,
514            nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
515            kernel::process::ProcessStandardDebugFull,
516        ));
517
518    // Create the dynamic app loader capsule.
519    let dynamic_app_loader = components::app_loader::AppLoaderComponent::new(
520        board_kernel,
521        capsules_extra::app_loader::DRIVER_NUM,
522        dynamic_binary_storage,
523        dynamic_binary_storage,
524    )
525    .finalize(components::app_loader_component_static!(
526        DynamicBinaryStorage<'static>,
527        DynamicBinaryStorage<'static>,
528    ));
529
530    //--------------------------------------------------------------------------
531    // PLATFORM SETUP AND START KERNEL LOOP
532    //--------------------------------------------------------------------------
533
534    let platform = static_init!(
535        Platform,
536        Platform {
537            board_kernel,
538            syscall_filter,
539            base: base_platform,
540            screen,
541            process_info,
542            nonvolatile_storage,
543            dynamic_app_loader,
544        }
545    );
546    loader.set_client(platform);
547
548    board_kernel.kernel_loop(
549        platform,
550        chip,
551        Some(&platform.base.ipc),
552        &main_loop_capability,
553    );
554}