nrf52840dk_root_of_trust_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 2024.
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 kernel::component::Component;
12use kernel::debug;
13use kernel::platform::{KernelResources, SyscallDriverLookup};
14use kernel::static_init;
15use kernel::{capabilities, create_capability};
16use nrf52840::gpio::Pin;
17
18// State for loading and holding applications.
19// How should the kernel respond when a process faults.
20const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
21    capsules_system::process_policies::PanicFaultPolicy {};
22
23const CRYPT_SIZE: usize = 7 * kernel::hil::symmetric_encryption::AES128_BLOCK_SIZE;
24
25// Screen
26type ScreenDriver = components::screen::ScreenComponentType;
27
28struct Platform {
29    base: nrf52840dk_lib::Platform,
30    screen: &'static ScreenDriver,
31    oracle: &'static capsules_extra::tutorials::encryption_oracle_chkpt5::EncryptionOracleDriver<
32        'static,
33        nrf52840::aes::AesECB<'static>,
34    >,
35}
36
37impl SyscallDriverLookup for Platform {
38    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
39    where
40        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
41    {
42        match driver_num {
43            capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)),
44            capsules_extra::tutorials::encryption_oracle_chkpt5::DRIVER_NUM => f(Some(self.oracle)),
45            _ => self.base.with_driver(driver_num, f),
46        }
47    }
48}
49
50type Chip = nrf52840dk_lib::Chip;
51
52impl KernelResources<Chip> for Platform {
53    type SyscallDriverLookup = Self;
54    type SyscallFilter = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SyscallFilter;
55    type ProcessFault = <nrf52840dk_lib::Platform as KernelResources<Chip>>::ProcessFault;
56    type Scheduler = <nrf52840dk_lib::Platform as KernelResources<Chip>>::Scheduler;
57    type SchedulerTimer = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SchedulerTimer;
58    type WatchDog = <nrf52840dk_lib::Platform as KernelResources<Chip>>::WatchDog;
59    type ContextSwitchCallback =
60        <nrf52840dk_lib::Platform as KernelResources<Chip>>::ContextSwitchCallback;
61
62    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
63        self
64    }
65    fn syscall_filter(&self) -> &Self::SyscallFilter {
66        self.base.syscall_filter()
67    }
68    fn process_fault(&self) -> &Self::ProcessFault {
69        self.base.process_fault()
70    }
71    fn scheduler(&self) -> &Self::Scheduler {
72        self.base.scheduler()
73    }
74    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
75        self.base.scheduler_timer()
76    }
77    fn watchdog(&self) -> &Self::WatchDog {
78        self.base.watchdog()
79    }
80    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
81        self.base.context_switch_callback()
82    }
83}
84
85/// Main function called after RAM initialized.
86#[no_mangle]
87pub unsafe fn main() {
88    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
89
90    // Create the base board:
91    let (board_kernel, base_platform, chip, nrf52840_peripherals, _mux_alarm) =
92        nrf52840dk_lib::start_no_pconsole();
93
94    //--------------------------------------------------------------------------
95    // SCREEN
96    //--------------------------------------------------------------------------
97
98    const SCREEN_I2C_SDA_PIN: Pin = Pin::P1_10;
99    const SCREEN_I2C_SCL_PIN: Pin = Pin::P1_11;
100
101    let i2c_bus = components::i2c::I2CMuxComponent::new(&nrf52840_peripherals.nrf52.twi1, None)
102        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
103    nrf52840_peripherals.nrf52.twi1.configure(
104        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SCL_PIN as u32),
105        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SDA_PIN as u32),
106    );
107    nrf52840_peripherals
108        .nrf52
109        .twi1
110        .set_speed(nrf52840::i2c::Speed::K400);
111
112    // I2C address is b011110X, and on this board D/C̅ is GND.
113    let ssd1306_sh1106_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
114        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
115
116    // Create the ssd1306 object for the actual screen driver.
117    #[cfg(feature = "screen_ssd1306")]
118    let ssd1306_sh1106 = components::ssd1306::Ssd1306Component::new(ssd1306_sh1106_i2c, true)
119        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
120
121    #[cfg(feature = "screen_sh1106")]
122    let ssd1306_sh1106 = components::sh1106::Sh1106Component::new(ssd1306_sh1106_i2c, true)
123        .finalize(components::sh1106_component_static!(nrf52840::i2c::TWI));
124
125    let screen = components::screen::ScreenComponent::new(
126        board_kernel,
127        capsules_extra::screen::DRIVER_NUM,
128        ssd1306_sh1106,
129        None,
130    )
131    .finalize(components::screen_component_static!(1032));
132
133    ssd1306_sh1106.init_screen();
134
135    //--------------------------------------------------------------------------
136    // ENCRYPTION ORACLE
137    //--------------------------------------------------------------------------
138
139    let aes_src_buffer = kernel::static_init!([u8; 16], [0; 16]);
140    let aes_dst_buffer = kernel::static_init!([u8; CRYPT_SIZE], [0; CRYPT_SIZE]);
141
142    let oracle = static_init!(
143        capsules_extra::tutorials::encryption_oracle_chkpt5::EncryptionOracleDriver<
144            'static,
145            nrf52840::aes::AesECB<'static>,
146        >,
147        capsules_extra::tutorials::encryption_oracle_chkpt5::EncryptionOracleDriver::new(
148            &nrf52840_peripherals.nrf52.ecb,
149            aes_src_buffer,
150            aes_dst_buffer,
151            board_kernel.create_grant(
152                capsules_extra::tutorials::encryption_oracle_chkpt5::DRIVER_NUM, // our driver number
153                &create_capability!(capabilities::MemoryAllocationCapability)
154            ),
155        ),
156    );
157
158    kernel::hil::symmetric_encryption::AES128::set_client(&nrf52840_peripherals.nrf52.ecb, oracle);
159
160    //--------------------------------------------------------------------------
161    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
162    //--------------------------------------------------------------------------
163
164    let platform = Platform {
165        base: base_platform,
166        screen,
167        oracle,
168    };
169
170    // These symbols are defined in the linker script.
171    extern "C" {
172        /// Beginning of the ROM region containing app images.
173        static _sapps: u8;
174        /// End of the ROM region containing app images.
175        static _eapps: u8;
176        /// Beginning of the RAM region for app memory.
177        static mut _sappmem: u8;
178        /// End of the RAM region for app memory.
179        static _eappmem: u8;
180    }
181
182    let process_management_capability =
183        create_capability!(capabilities::ProcessManagementCapability);
184
185    kernel::process::load_processes(
186        board_kernel,
187        chip,
188        core::slice::from_raw_parts(
189            core::ptr::addr_of!(_sapps),
190            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
191        ),
192        core::slice::from_raw_parts_mut(
193            core::ptr::addr_of_mut!(_sappmem),
194            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
195        ),
196        &FAULT_RESPONSE,
197        &process_management_capability,
198    )
199    .unwrap_or_else(|err| {
200        debug!("Error loading processes!");
201        debug!("{:?}", err);
202    });
203
204    board_kernel.kernel_loop(
205        &platform,
206        chip,
207        Some(&platform.base.ipc),
208        &main_loop_capability,
209    );
210}