kernel/platform/chip.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//! Interfaces for implementing microcontrollers in Tock.
6
7use crate::platform::mpu;
8use crate::syscall;
9use core::fmt::Write;
10
11/// Interface for individual MCUs.
12///
13/// The trait defines chip-specific properties of Tock's operation. These
14/// include whether and which memory protection mechanism and scheduler_timer to
15/// use, how to switch between the kernel and userland applications, and how to
16/// handle hardware events.
17///
18/// Each microcontroller should define a struct and implement this trait.
19pub trait Chip {
20 /// The particular Memory Protection Unit (MPU) for this chip.
21 type MPU: mpu::MPU;
22
23 /// Provider to query the currently running thread ID.
24 type ThreadIdProvider: ThreadIdProvider;
25
26 /// The implementation of the interface between userspace and the kernel for
27 /// this specific chip. Likely this is architecture specific, but individual
28 /// chips may have various custom requirements.
29 type UserspaceKernelBoundary: syscall::UserspaceKernelBoundary;
30
31 /// The kernel calls this function to tell the chip to check for all pending
32 /// interrupts and to correctly dispatch them to the peripheral drivers for
33 /// the chip.
34 ///
35 /// This function should loop internally until all interrupts have been
36 /// handled. It is ok, however, if an interrupt occurs after the last check
37 /// but before this function returns. The kernel will handle this edge case.
38 fn service_pending_interrupts(&self);
39
40 /// Ask the chip to check if there are any pending interrupts.
41 fn has_pending_interrupts(&self) -> bool;
42
43 /// Returns a reference to the implementation for the MPU on this chip.
44 fn mpu(&self) -> &Self::MPU;
45
46 /// Returns a reference to the implementation for the interface between
47 /// userspace and kernelspace.
48 fn userspace_kernel_boundary(&self) -> &Self::UserspaceKernelBoundary;
49
50 /// Called when there is nothing left for the chip to do and it should enter
51 /// a low power sleep state. This low power sleep state should allow
52 /// interrupts to still be active so that the next interrupt event wakes the
53 /// chip and resumes the scheduler.
54 fn sleep(&self);
55
56 /// Run a function in an atomic state w.r.t. to the current core. This
57 /// means that interrupts are disabled so that an interrupt will not fire
58 /// during the passed in function's execution, but *does not* make any
59 /// guarantees about memory consistency on a multi-core system.
60 unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
61 where
62 F: FnOnce() -> R;
63
64 /// Print out debug information about the current chip state (system
65 /// registers, MPU configuration, etc.) to a supplied writer.
66 ///
67 /// This function may be called across thread boundaries (such as from a
68 /// panic handler). As implementors of `Chip` do not have to be `Send` or
69 /// `Sync`, `&self` may not be available in these contexts. Therefore, this
70 /// function instead accepts an `Option<&Self>` parameter named `this`. In
71 /// contexts where `&self` is available, callers should invoke this function
72 /// by passing `Some(&self)` to `this`. Otherwise, `this` will be set to
73 /// `None`. The implementation of `print_state` may not print certain
74 /// information if it depends on runtime-accessible state in `Self`, but
75 /// that reference is not provided.
76 unsafe fn print_state(this: Option<&Self>, writer: &mut dyn Write);
77}
78
79/// Interface for retrieving the currently executing thread.
80///
81/// This is used to enforce correctness with shared state that has access
82/// restrictions (e.g., only a single thread can access a specific value).
83///
84/// Many embedded platforms are single-core and only permit a single execution
85/// thread at a time. However, interrupts can typically occur at any time, and
86/// the execution of an interrupt service routine (ISR) constitutes a second
87/// thread. Implementations of this trait must be able to differentiate between
88/// at minimum the main thread of execution and an ISR execution, but may also
89/// consider multiple execution threads if available on a particular device.
90///
91/// # Safety
92///
93/// This thread is marked as `unsafe` as implementation must guarantee its
94/// correctness. Users of this trait are allowed to make soundness guarantees
95/// based on the implementation being correct. Failing to provide a correct
96/// implementation can lead to unsound behavior. By implementing this trait,
97/// providers are guaranteeing the implementations are always correct for the
98/// given hardware platform.
99pub unsafe trait ThreadIdProvider {
100 /// Return a unique ID for the currently executing thread.
101 ///
102 /// The unique ID must fit in a `usize` and must be unique and consistent
103 /// for the currently running thread. The actual value is opaque and there
104 /// is no assumption about the meaning of the assigned IDs. Implementations
105 /// are allowed to arbitrarily assign IDs to threads as long as the IDs are
106 /// unique and consistent.
107 fn running_thread_id() -> usize;
108}
109
110/// Interface for handling interrupts on a hardware chip.
111///
112/// Each board must construct an implementation of this trait to handle specific
113/// interrupts. When an interrupt (identified by number) has triggered and
114/// should be handled, the implementation of this trait will be called with the
115/// interrupt number. The implementation can then handle the interrupt, or
116/// return `false` to signify that it does not know how to handle the interrupt.
117///
118/// This functionality is given this `InterruptService` interface so that
119/// multiple objects can be chained together to handle interrupts for a chip.
120/// This is useful for code organization and removing the need for duplication
121/// when multiple variations of a specific microcontroller exist. Then a shared,
122/// base object can handle most interrupts, and variation-specific objects can
123/// handle the variation-specific interrupts.
124///
125/// To simplify structuring the Rust code when using `InterruptService`, the
126/// interrupt number should be passed "top-down". That is, an interrupt to be
127/// handled will first be passed to the `InterruptService` object that is most
128/// specific. If that object cannot handle the interrupt, then it should
129/// maintain a reference to the second most specific object, and return by
130/// calling to that object to handle the interrupt. This continues until the
131/// base object handles the interrupt or decides that the chip does not know how
132/// to handle the interrupt. For example, consider a `nRF52840` chip that
133/// depends on the `nRF52` crate. If both have specific interrupts they know how
134/// to handle, the flow would look like:
135///
136/// ```ignore
137/// +---->nrf52840_peripherals
138/// | |
139/// | |
140/// | v
141/// kernel-->nrf52 nrf52_peripherals
142/// ```
143/// where the kernel instructs the `nrf52` crate to handle interrupts, and if
144/// there is an interrupt ready then that interrupt is passed through the
145/// InterruptService objects until something can service it.
146pub trait InterruptService {
147 /// Service an interrupt, if supported by this chip. If this interrupt
148 /// number is not supported, return false.
149 unsafe fn service_interrupt(&self, interrupt: u32) -> bool;
150}
151
152/// A default implementation of `InterruptService` that handles nothing and returns `false`.
153impl InterruptService for () {
154 unsafe fn service_interrupt(&self, _interrupt: u32) -> bool {
155 false
156 }
157}
158
159/// Generic operations that clock-like things are expected to support.
160pub trait ClockInterface {
161 fn is_enabled(&self) -> bool;
162 fn enable(&self);
163 fn disable(&self);
164}
165
166/// Helper struct for interfaces that expect clocks, but have no clock control.
167pub struct NoClockControl {}
168impl ClockInterface for NoClockControl {
169 fn is_enabled(&self) -> bool {
170 true
171 }
172 fn enable(&self) {}
173 fn disable(&self) {}
174}
175
176/// Instance of NoClockControl for things that need references to
177/// `ClockInterface` objects.
178pub const NO_CLOCK_CONTROL: NoClockControl = NoClockControl {};