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