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    /// The implementation of the interface between userspace and the kernel for
24    /// this specific chip. Likely this is architecture specific, but individual
25    /// chips may have various custom requirements.
26    type UserspaceKernelBoundary: syscall::UserspaceKernelBoundary;
27
28    /// The kernel calls this function to tell the chip to check for all pending
29    /// interrupts and to correctly dispatch them to the peripheral drivers for
30    /// the chip.
31    ///
32    /// This function should loop internally until all interrupts have been
33    /// handled. It is ok, however, if an interrupt occurs after the last check
34    /// but before this function returns. The kernel will handle this edge case.
35    fn service_pending_interrupts(&self);
36
37    /// Ask the chip to check if there are any pending interrupts.
38    fn has_pending_interrupts(&self) -> bool;
39
40    /// Returns a reference to the implementation for the MPU on this chip.
41    fn mpu(&self) -> &Self::MPU;
42
43    /// Returns a reference to the implementation for the interface between
44    /// userspace and kernelspace.
45    fn userspace_kernel_boundary(&self) -> &Self::UserspaceKernelBoundary;
46
47    /// Called when there is nothing left for the chip to do and it should enter
48    /// a low power sleep state. This low power sleep state should allow
49    /// interrupts to still be active so that the next interrupt event wakes the
50    /// chip and resumes the scheduler.
51    fn sleep(&self);
52
53    /// Run a function in an atomic state w.r.t. to the current core. This
54    /// means that interrupts are disabled so that an interrupt will not fire
55    /// during the passed in function's execution, but *does not* make any
56    /// guarantees about memory consistency on a multi-core system.
57    unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
58    where
59        F: FnOnce() -> R;
60
61    /// Print out chip state (system registers) to a supplied
62    /// writer. This does not print out the execution context
63    /// (data registers), as this depends on how they are stored;
64    /// that is implemented by
65    /// `syscall::UserspaceKernelBoundary::print_context`.
66    /// This also does not print out a process memory state,
67    /// that is implemented by `process::Process::print_memory_map`.
68    /// The MPU state is printed by the MPU's implementation of
69    /// the Display trait.
70    /// Used by panic.
71    unsafe fn print_state(&self, writer: &mut dyn Write);
72}
73
74/// Interface for handling interrupts on a hardware chip.
75///
76/// Each board must construct an implementation of this trait to handle specific
77/// interrupts. When an interrupt (identified by number) has triggered and
78/// should be handled, the implementation of this trait will be called with the
79/// interrupt number. The implementation can then handle the interrupt, or
80/// return `false` to signify that it does not know how to handle the interrupt.
81///
82/// This functionality is given this `InterruptService` interface so that
83/// multiple objects can be chained together to handle interrupts for a chip.
84/// This is useful for code organization and removing the need for duplication
85/// when multiple variations of a specific microcontroller exist. Then a shared,
86/// base object can handle most interrupts, and variation-specific objects can
87/// handle the variation-specific interrupts.
88///
89/// To simplify structuring the Rust code when using `InterruptService`, the
90/// interrupt number should be passed "top-down". That is, an interrupt to be
91/// handled will first be passed to the `InterruptService` object that is most
92/// specific. If that object cannot handle the interrupt, then it should
93/// maintain a reference to the second most specific object, and return by
94/// calling to that object to handle the interrupt. This continues until the
95/// base object handles the interrupt or decides that the chip does not know how
96/// to handle the interrupt. For example, consider a `nRF52840` chip that
97/// depends on the `nRF52` crate. If both have specific interrupts they know how
98/// to handle, the flow would look like:
99///
100/// ```ignore
101///           +---->nrf52840_peripherals
102///           |        |
103///           |        |
104///           |        v
105/// kernel-->nrf52     nrf52_peripherals
106/// ```
107/// where the kernel instructs the `nrf52` crate to handle interrupts, and if
108/// there is an interrupt ready then that interrupt is passed through the
109/// InterruptService objects until something can service it.
110pub trait InterruptService {
111    /// Service an interrupt, if supported by this chip. If this interrupt
112    /// number is not supported, return false.
113    unsafe fn service_interrupt(&self, interrupt: u32) -> bool;
114}
115
116/// Generic operations that clock-like things are expected to support.
117pub trait ClockInterface {
118    fn is_enabled(&self) -> bool;
119    fn enable(&self);
120    fn disable(&self);
121}
122
123/// Helper struct for interfaces that expect clocks, but have no clock control.
124pub struct NoClockControl {}
125impl ClockInterface for NoClockControl {
126    fn is_enabled(&self) -> bool {
127        true
128    }
129    fn enable(&self) {}
130    fn disable(&self) {}
131}
132
133/// Instance of NoClockControl for things that need references to
134/// `ClockInterface` objects.
135pub const NO_CLOCK_CONTROL: NoClockControl = NoClockControl {};