nrf52840dk_test_appid_tbf/
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 kernel::component::Component;
12use kernel::hil::led::LedLow;
13use kernel::hil::time::Counter;
14use kernel::platform::{KernelResources, SyscallDriverLookup};
15use kernel::process::{ProcessArray, ProcessLoadingAsync};
16use kernel::scheduler::round_robin::RoundRobinSched;
17use kernel::{capabilities, create_capability, static_init};
18use nrf52840::gpio::Pin;
19use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
20use nrf52_components::{UartChannel, UartPins};
21
22// The nRF52840DK LEDs (see back of board)
23const LED1_PIN: Pin = Pin::P0_13;
24const LED2_PIN: Pin = Pin::P0_14;
25const LED3_PIN: Pin = Pin::P0_15;
26const LED4_PIN: Pin = Pin::P0_16;
27
28const BUTTON_RST_PIN: Pin = Pin::P0_18;
29
30const UART_RTS: Option<Pin> = Some(Pin::P0_05);
31const UART_TXD: Pin = Pin::P0_06;
32const UART_CTS: Option<Pin> = Some(Pin::P0_07);
33const UART_RXD: Pin = Pin::P0_08;
34
35/// Debug Writer
36pub mod io;
37
38// State for loading and holding applications.
39// How should the kernel respond when a process faults.
40const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
41    capsules_system::process_policies::PanicFaultPolicy {};
42
43// Number of concurrent processes this platform supports.
44const NUM_PROCS: usize = 8;
45
46type ChipHw = nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>;
47
48kernel::stack_size! {0x2000}
49
50//------------------------------------------------------------------------------
51// SYSCALL DRIVER TYPE DEFINITIONS
52//------------------------------------------------------------------------------
53
54type AlarmDriver = components::alarm::AlarmDriverComponentType<nrf52840::rtc::Rtc<'static>>;
55
56/// Supported drivers by the platform
57pub struct Platform {
58    console: &'static capsules_core::console::Console<'static>,
59    led: &'static capsules_core::led::LedDriver<
60        'static,
61        kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
62        4,
63    >,
64    alarm: &'static AlarmDriver,
65    scheduler: &'static RoundRobinSched<'static>,
66    systick: cortexm4::systick::SysTick,
67    processes: &'static ProcessArray<NUM_PROCS>,
68}
69
70impl SyscallDriverLookup for Platform {
71    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
72    where
73        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
74    {
75        match driver_num {
76            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
77            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
78            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
79            _ => f(None),
80        }
81    }
82}
83
84/// This is in a separate, inline(never) function so that its stack frame is
85/// removed when this function returns. Otherwise, the stack space used for
86/// these static_inits is wasted.
87#[inline(never)]
88unsafe fn create_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
89    let ieee802154_ack_buf = static_init!(
90        [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
91        [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
92    );
93    // Initialize chip peripheral drivers
94    let nrf52840_peripherals = static_init!(
95        Nrf52840DefaultPeripherals,
96        Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
97    );
98
99    nrf52840_peripherals
100}
101
102impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
103    for Platform
104{
105    type SyscallDriverLookup = Self;
106    type SyscallFilter = ();
107    type ProcessFault = ();
108    type Scheduler = RoundRobinSched<'static>;
109    type SchedulerTimer = cortexm4::systick::SysTick;
110    type WatchDog = ();
111    type ContextSwitchCallback = ();
112
113    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
114        self
115    }
116    fn syscall_filter(&self) -> &Self::SyscallFilter {
117        &()
118    }
119    fn process_fault(&self) -> &Self::ProcessFault {
120        &()
121    }
122    fn scheduler(&self) -> &Self::Scheduler {
123        self.scheduler
124    }
125    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
126        &self.systick
127    }
128    fn watchdog(&self) -> &Self::WatchDog {
129        &()
130    }
131    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
132        &()
133    }
134}
135
136impl kernel::process::ProcessLoadingAsyncClient for Platform {
137    fn process_loaded(&self, _result: Result<(), kernel::process::ProcessLoadError>) {}
138
139    fn process_loading_finished(&self) {
140        kernel::debug!("Processes Loaded:");
141
142        for (i, proc) in self.processes.as_slice().iter().enumerate() {
143            proc.get().map(|p| {
144                kernel::debug!("[{}] {}", i, p.get_process_name());
145                kernel::debug!("    ShortId: {}", p.short_app_id());
146            });
147        }
148    }
149}
150
151/// Main function called after RAM initialized.
152#[no_mangle]
153pub unsafe fn main() {
154    //--------------------------------------------------------------------------
155    // INITIAL SETUP
156    //--------------------------------------------------------------------------
157
158    // Apply errata fixes and enable interrupts.
159    nrf52840::init();
160
161    // Initialize deferred calls very early.
162    kernel::deferred_call::initialize_deferred_call_state::<
163        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
164    >();
165
166    // Set up peripheral drivers. Called in separate function to reduce stack
167    // usage.
168    let nrf52840_peripherals = create_peripherals();
169
170    // Set up circular peripheral dependencies.
171    nrf52840_peripherals.init();
172    let base_peripherals = &nrf52840_peripherals.nrf52;
173
174    // Choose the channel for serial output. This board can be configured to use
175    // either the Segger RTT channel or via UART with traditional TX/RX GPIO
176    // pins.
177    let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
178
179    // Create an array to hold process references.
180    let processes = components::process_array::ProcessArrayComponent::new()
181        .finalize(components::process_array_component_static!(NUM_PROCS));
182
183    // Setup space to store the core kernel data structure.
184    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
185
186    // Create (and save for panic debugging) a chip object to setup low-level
187    // resources (e.g. MPU, systick).
188    let chip = static_init!(
189        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
190        nrf52840::chip::NRF52::new(nrf52840_peripherals)
191    );
192
193    // Do nRF configuration and setup. This is shared code with other nRF-based
194    // platforms.
195    nrf52_components::startup::NrfStartupComponent::new(
196        false,
197        BUTTON_RST_PIN,
198        nrf52840::uicr::Regulator0Output::DEFAULT,
199        &base_peripherals.nvmc,
200    )
201    .finalize(());
202
203    //--------------------------------------------------------------------------
204    // CAPABILITIES
205    //--------------------------------------------------------------------------
206
207    // Create capabilities that the board needs to call certain protected kernel
208    // functions.
209    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
210
211    //--------------------------------------------------------------------------
212    // LEDs
213    //--------------------------------------------------------------------------
214
215    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
216        LedLow<'static, nrf52840::gpio::GPIOPin>,
217        LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
218        LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]),
219        LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]),
220        LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]),
221    ));
222
223    //--------------------------------------------------------------------------
224    // TIMER
225    //--------------------------------------------------------------------------
226
227    let rtc = &base_peripherals.rtc;
228    let _ = rtc.start();
229    let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
230        .finalize(components::alarm_mux_component_static!(nrf52840::rtc::Rtc));
231    let alarm = components::alarm::AlarmDriverComponent::new(
232        board_kernel,
233        capsules_core::alarm::DRIVER_NUM,
234        mux_alarm,
235    )
236    .finalize(components::alarm_component_static!(nrf52840::rtc::Rtc));
237
238    //--------------------------------------------------------------------------
239    // UART & CONSOLE & DEBUG
240    //--------------------------------------------------------------------------
241
242    let uart_channel = nrf52_components::UartChannelComponent::new(
243        uart_channel,
244        mux_alarm,
245        &base_peripherals.uarte0,
246    )
247    .finalize(nrf52_components::uart_channel_component_static!(
248        nrf52840::rtc::Rtc
249    ));
250
251    // Virtualize the UART channel for the console and for kernel debug.
252    let uart_mux = components::console::UartMuxComponent::new(uart_channel, 115200)
253        .finalize(components::uart_mux_component_static!());
254
255    // Setup the serial console for userspace.
256    let console = components::console::ConsoleComponent::new(
257        board_kernel,
258        capsules_core::console::DRIVER_NUM,
259        uart_mux,
260    )
261    .finalize(components::console_component_static!());
262
263    // Tool for displaying information about processes.
264    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
265        .finalize(components::process_printer_text_component_static!());
266
267    // Create the process console, an interactive terminal for managing
268    // processes.
269    let pconsole = components::process_console::ProcessConsoleComponent::new(
270        board_kernel,
271        uart_mux,
272        mux_alarm,
273        process_printer,
274        Some(cortexm4::support::reset),
275    )
276    .finalize(components::process_console_component_static!(
277        nrf52840::rtc::Rtc<'static>
278    ));
279
280    // Create the debugger object that handles calls to `debug!()`.
281    components::debug_writer::DebugWriterComponent::new::<
282        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
283    >(
284        uart_mux,
285        create_capability!(capabilities::SetDebugWriterCapability),
286    )
287    .finalize(components::debug_writer_component_static!());
288
289    //--------------------------------------------------------------------------
290    // NRF CLOCK SETUP
291    //--------------------------------------------------------------------------
292
293    nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
294
295    //--------------------------------------------------------------------------
296    // Credential Checking
297    //--------------------------------------------------------------------------
298
299    // Create the credential checker.
300    let checking_policy = components::appid::checker_null::AppCheckerNullComponent::new()
301        .finalize(components::app_checker_null_component_static!());
302
303    // Create the AppID assigner.
304    let assigner = components::appid::assigner_tbf::AppIdAssignerTbfHeaderComponent::new()
305        .finalize(components::appid_assigner_tbf_header_component_static!());
306
307    // Create the process checking machine.
308    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
309        .finalize(components::process_checker_machine_component_static!());
310
311    //--------------------------------------------------------------------------
312    // STORAGE PERMISSIONS
313    //--------------------------------------------------------------------------
314
315    let storage_permissions_policy =
316        components::storage_permissions::null::StoragePermissionsNullComponent::new().finalize(
317            components::storage_permissions_null_component_static!(
318                nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
319                kernel::process::ProcessStandardDebugFull,
320            ),
321        );
322
323    //--------------------------------------------------------------------------
324    // PROCESS LOADING
325    //--------------------------------------------------------------------------
326
327    // These symbols are defined in the standard Tock linker script.
328    extern "C" {
329        /// Beginning of the ROM region containing app images.
330        static _sapps: u8;
331        /// End of the ROM region containing app images.
332        static _eapps: u8;
333        /// Beginning of the RAM region for app memory.
334        static mut _sappmem: u8;
335        /// End of the RAM region for app memory.
336        static _eappmem: u8;
337    }
338
339    let app_flash = core::slice::from_raw_parts(
340        core::ptr::addr_of!(_sapps),
341        core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
342    );
343    let app_memory = core::slice::from_raw_parts_mut(
344        core::ptr::addr_of_mut!(_sappmem),
345        core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
346    );
347
348    // Create and start the asynchronous process loader.
349    let loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
350        checker,
351        board_kernel,
352        chip,
353        &FAULT_RESPONSE,
354        assigner,
355        storage_permissions_policy,
356        app_flash,
357        app_memory,
358    )
359    .finalize(components::process_loader_sequential_component_static!(
360        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
361        kernel::process::ProcessStandardDebugFull,
362        NUM_PROCS
363    ));
364
365    //--------------------------------------------------------------------------
366    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
367    //--------------------------------------------------------------------------
368
369    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
370        .finalize(components::round_robin_component_static!(NUM_PROCS));
371
372    let platform = static_init!(
373        Platform,
374        Platform {
375            console,
376            led,
377            alarm,
378            scheduler,
379            systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
380            processes,
381        }
382    );
383    loader.set_client(platform);
384
385    let _ = pconsole.start();
386
387    board_kernel.kernel_loop(
388        platform,
389        chip,
390        None::<&kernel::ipc::IPC<0>>,
391        &main_loop_capability,
392    );
393}