Refactor tutorial 08
parent
7e583dc923
commit
48e4d135c2
Binary file not shown.
Binary file not shown.
@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Architectural symmetric multiprocessing.
|
||||||
|
|
||||||
|
use cortex_a::regs::*;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Return the executing core's id.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn core_id<T>() -> T
|
||||||
|
where
|
||||||
|
T: From<u8>,
|
||||||
|
{
|
||||||
|
const CORE_MASK: u64 = 0b11;
|
||||||
|
|
||||||
|
T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Conditional exporting of processor architecture code.
|
|
||||||
|
|
||||||
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
|
||||||
mod aarch64;
|
|
||||||
|
|
||||||
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
|
||||||
pub use aarch64::*;
|
|
@ -1,53 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Synchronization primitives.
|
|
||||||
|
|
||||||
use crate::interface;
|
|
||||||
use core::cell::UnsafeCell;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Arch-public
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// A pseudo-lock for teaching purposes.
|
|
||||||
///
|
|
||||||
/// Used to introduce [interior mutability].
|
|
||||||
///
|
|
||||||
/// In contrast to a real Mutex implementation, does not protect against concurrent access to the
|
|
||||||
/// contained data. This part is preserved for later lessons.
|
|
||||||
///
|
|
||||||
/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
|
|
||||||
/// executing single-threaded, aka only running on a single core with interrupts disabled.
|
|
||||||
///
|
|
||||||
/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
|
|
||||||
pub struct NullLock<T: ?Sized> {
|
|
||||||
data: UnsafeCell<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: ?Sized + Send> Send for NullLock<T> {}
|
|
||||||
unsafe impl<T: ?Sized + Send> Sync for NullLock<T> {}
|
|
||||||
|
|
||||||
impl<T> NullLock<T> {
|
|
||||||
/// Wraps `data` into a new `NullLock`.
|
|
||||||
pub const fn new(data: T) -> NullLock<T> {
|
|
||||||
NullLock {
|
|
||||||
data: UnsafeCell::new(data),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// OS interface implementations
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<T> interface::sync::Mutex for &NullLock<T> {
|
|
||||||
type Data = T;
|
|
||||||
|
|
||||||
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R {
|
|
||||||
// In a real lock, there would be code encapsulating this line that ensures that this
|
|
||||||
// mutable reference will ever only be given out once at a time.
|
|
||||||
f(unsafe { &mut *self.data.get() })
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Top-level BSP file for the Raspberry Pi 3 and 4.
|
||||||
|
|
||||||
|
pub mod console;
|
||||||
|
pub mod cpu;
|
||||||
|
pub mod driver;
|
||||||
|
pub mod memory;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Global instances
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
use super::device_driver;
|
||||||
|
|
||||||
|
static GPIO: device_driver::GPIO =
|
||||||
|
unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_BASE) };
|
||||||
|
|
||||||
|
static PL011_UART: device_driver::PL011Uart =
|
||||||
|
unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_BASE) };
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Board identification.
|
||||||
|
pub fn board_name() -> &'static str {
|
||||||
|
#[cfg(feature = "bsp_rpi3")]
|
||||||
|
{
|
||||||
|
"Raspberry Pi 3"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bsp_rpi4")]
|
||||||
|
{
|
||||||
|
"Raspberry Pi 4"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! BSP console facilities.
|
||||||
|
|
||||||
|
use super::{super::device_driver, memory::map};
|
||||||
|
use crate::console;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// In case of a panic, the panic handler uses this function to take a last shot at printing
|
||||||
|
/// something before the system is halted.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - Use only for printing during a panic.
|
||||||
|
pub unsafe fn panic_console_out() -> impl fmt::Write {
|
||||||
|
let mut uart = device_driver::PanicUart::new(map::mmio::PL011_UART_BASE);
|
||||||
|
uart.init();
|
||||||
|
uart
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a reference to the console.
|
||||||
|
pub fn console() -> &'static impl console::interface::All {
|
||||||
|
&super::PL011_UART
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! BSP Processor code.
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Used by `arch` code to find the early boot core.
|
||||||
|
pub const BOOT_CORE_ID: usize = 0;
|
||||||
|
|
||||||
|
/// The early boot core's stack address.
|
||||||
|
pub const BOOT_CORE_STACK_START: u64 = 0x80_000;
|
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! BSP driver support.
|
||||||
|
|
||||||
|
use crate::driver;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Device Driver Manager type.
|
||||||
|
pub struct BSPDriverManager {
|
||||||
|
device_drivers: [&'static (dyn DeviceDriver + Sync); 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Global instances
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager {
|
||||||
|
device_drivers: [&super::GPIO, &super::PL011_UART],
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Return a reference to the driver manager.
|
||||||
|
pub fn driver_manager() -> &'static impl driver::interface::DriverManager {
|
||||||
|
&BSP_DRIVER_MANAGER
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// OS Interface Code
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
use driver::interface::DeviceDriver;
|
||||||
|
|
||||||
|
impl driver::interface::DriverManager for BSPDriverManager {
|
||||||
|
fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] {
|
||||||
|
&self.device_drivers[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_device_driver_init(&self) {
|
||||||
|
// Configure PL011Uart's output pins.
|
||||||
|
super::GPIO.map_pl011_uart();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! BSP Memory Management.
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// The board's memory map.
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub(super) mod map {
|
||||||
|
pub const GPIO_OFFSET: usize = 0x0020_0000;
|
||||||
|
pub const UART_OFFSET: usize = 0x0020_1000;
|
||||||
|
|
||||||
|
/// Physical devices.
|
||||||
|
#[cfg(feature = "bsp_rpi3")]
|
||||||
|
pub mod mmio {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub const BASE: usize = 0x3F00_0000;
|
||||||
|
pub const GPIO_BASE: usize = BASE + GPIO_OFFSET;
|
||||||
|
pub const PL011_UART_BASE: usize = BASE + UART_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Physical devices.
|
||||||
|
#[cfg(feature = "bsp_rpi4")]
|
||||||
|
pub mod mmio {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub const BASE: usize = 0xFE00_0000;
|
||||||
|
pub const GPIO_BASE: usize = BASE + GPIO_OFFSET;
|
||||||
|
pub const PL011_UART_BASE: usize = BASE + UART_OFFSET;
|
||||||
|
}
|
||||||
|
}
|
@ -1,74 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Board Support Package for the Raspberry Pi.
|
|
||||||
|
|
||||||
mod memory_map;
|
|
||||||
|
|
||||||
use super::driver;
|
|
||||||
use crate::interface;
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
/// Used by `arch` code to find the early boot core.
|
|
||||||
pub const BOOT_CORE_ID: u64 = 0;
|
|
||||||
|
|
||||||
/// The early boot core's stack address.
|
|
||||||
pub const BOOT_CORE_STACK_START: u64 = 0x80_000;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Global BSP driver instances
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) };
|
|
||||||
static PL011_UART: driver::PL011Uart =
|
|
||||||
unsafe { driver::PL011Uart::new(memory_map::mmio::PL011_UART_BASE) };
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Implementation of the kernel's BSP calls
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Board identification.
|
|
||||||
pub fn board_name() -> &'static str {
|
|
||||||
#[cfg(feature = "bsp_rpi3")]
|
|
||||||
{
|
|
||||||
"Raspberry Pi 3"
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "bsp_rpi4")]
|
|
||||||
{
|
|
||||||
"Raspberry Pi 4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a reference to a `console::All` implementation.
|
|
||||||
pub fn console() -> &'static impl interface::console::All {
|
|
||||||
&PL011_UART
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In case of a panic, the panic handler uses this function to take a last shot at printing
|
|
||||||
/// something before the system is halted.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Use only for printing during a panic.
|
|
||||||
pub unsafe fn panic_console_out() -> impl fmt::Write {
|
|
||||||
let uart = driver::PanicUart::new(memory_map::mmio::PL011_UART_BASE);
|
|
||||||
uart.init();
|
|
||||||
uart
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return an array of references to all `DeviceDriver` compatible `BSP` drivers.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The order of devices is the order in which `DeviceDriver::init()` is called.
|
|
||||||
pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
|
|
||||||
[&GPIO, &PL011_UART]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// BSP initialization code that runs after driver init.
|
|
||||||
pub fn post_driver_init() {
|
|
||||||
// Configure PL011Uart's output pins.
|
|
||||||
GPIO.map_pl011_uart();
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! The board's memory map.
|
|
||||||
|
|
||||||
/// Physical devices.
|
|
||||||
#[rustfmt::skip]
|
|
||||||
pub mod mmio {
|
|
||||||
#[cfg(feature = "bsp_rpi3")]
|
|
||||||
pub const BASE: usize = 0x3F00_0000;
|
|
||||||
|
|
||||||
#[cfg(feature = "bsp_rpi4")]
|
|
||||||
pub const BASE: usize = 0xFE00_0000;
|
|
||||||
|
|
||||||
pub const GPIO_BASE: usize = BASE + 0x0020_0000;
|
|
||||||
pub const PL011_UART_BASE: usize = BASE + 0x0020_1000;
|
|
||||||
}
|
|
@ -0,0 +1,54 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! System console.
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Console interfaces.
|
||||||
|
pub mod interface {
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
/// Console write functions.
|
||||||
|
pub trait Write {
|
||||||
|
/// Write a single character.
|
||||||
|
fn write_char(&self, c: char);
|
||||||
|
|
||||||
|
/// Write a Rust format string.
|
||||||
|
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
|
||||||
|
|
||||||
|
/// Block execution until the last character has been physically put on the TX wire
|
||||||
|
/// (draining TX buffers/FIFOs, if any).
|
||||||
|
fn flush(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Console read functions.
|
||||||
|
pub trait Read {
|
||||||
|
/// Read a single character.
|
||||||
|
fn read_char(&self) -> char {
|
||||||
|
' '
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear RX buffers, if any.
|
||||||
|
fn clear(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Console statistics.
|
||||||
|
pub trait Statistics {
|
||||||
|
/// Return the number of characters written.
|
||||||
|
fn chars_written(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the number of characters read.
|
||||||
|
fn chars_read(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait alias for a full-fledged console.
|
||||||
|
pub trait All = Write + Read + Statistics;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Processor code.
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[path = "_arch/aarch64/cpu.rs"]
|
||||||
|
mod arch_cpu;
|
||||||
|
pub use arch_cpu::*;
|
||||||
|
|
||||||
|
pub mod smp;
|
@ -0,0 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Symmetric multiprocessing.
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[path = "../_arch/aarch64/cpu/smp.rs"]
|
||||||
|
mod arch_cpu_smp;
|
||||||
|
pub use arch_cpu_smp::*;
|
@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Driver support.
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Driver interfaces.
|
||||||
|
pub mod interface {
|
||||||
|
|
||||||
|
/// Device Driver functions.
|
||||||
|
pub trait DeviceDriver {
|
||||||
|
/// Return a compatibility string for identifying the driver.
|
||||||
|
fn compatible(&self) -> &str;
|
||||||
|
|
||||||
|
/// Called by the kernel to bring up the device.
|
||||||
|
fn init(&self) -> Result<(), ()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Device driver management functions.
|
||||||
|
///
|
||||||
|
/// The `BSP` is supposed to supply one global instance.
|
||||||
|
pub trait DriverManager {
|
||||||
|
/// Return a slice of references to all `BSP`-instantiated drivers.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - The order of devices is the order in which `DeviceDriver::init()` is called.
|
||||||
|
fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)];
|
||||||
|
|
||||||
|
/// Initialization code that runs after driver init.
|
||||||
|
///
|
||||||
|
/// For example, device driver code that depends on other drivers already being online.
|
||||||
|
fn post_device_driver_init(&self);
|
||||||
|
}
|
||||||
|
}
|
@ -1,133 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Trait definitions for coupling `kernel` and `BSP` code.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! +-------------------+
|
|
||||||
//! | Interface (Trait) |
|
|
||||||
//! | |
|
|
||||||
//! +--+-------------+--+
|
|
||||||
//! ^ ^
|
|
||||||
//! | |
|
|
||||||
//! | |
|
|
||||||
//! +----------+--+ +--+----------+
|
|
||||||
//! | Kernel code | | BSP Code |
|
|
||||||
//! | | | |
|
|
||||||
//! +-------------+ +-------------+
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
/// System console operations.
|
|
||||||
pub mod console {
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
/// Console write functions.
|
|
||||||
pub trait Write {
|
|
||||||
/// Write a single character.
|
|
||||||
fn write_char(&self, c: char);
|
|
||||||
|
|
||||||
/// Write a Rust format string.
|
|
||||||
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
|
|
||||||
|
|
||||||
/// Block execution until the last character has been physically put on the TX wire
|
|
||||||
/// (draining TX buffers/FIFOs, if any).
|
|
||||||
fn flush(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Console read functions.
|
|
||||||
pub trait Read {
|
|
||||||
/// Read a single character.
|
|
||||||
fn read_char(&self) -> char {
|
|
||||||
' '
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear RX buffers, if any.
|
|
||||||
fn clear(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Console statistics.
|
|
||||||
pub trait Statistics {
|
|
||||||
/// Return the number of characters written.
|
|
||||||
fn chars_written(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the number of characters read.
|
|
||||||
fn chars_read(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait alias for a full-fledged console.
|
|
||||||
pub trait All = Write + Read + Statistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Synchronization primitives.
|
|
||||||
pub mod sync {
|
|
||||||
/// Any object implementing this trait guarantees exclusive access to the data contained within
|
|
||||||
/// the mutex for the duration of the lock.
|
|
||||||
///
|
|
||||||
/// The trait follows the [Rust embedded WG's
|
|
||||||
/// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
|
|
||||||
/// provides some goodness such as [deadlock
|
|
||||||
/// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
|
|
||||||
/// best implemented **for a reference to a container struct**, and has a usage pattern that
|
|
||||||
/// might feel strange at first:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
|
|
||||||
///
|
|
||||||
/// fn foo() {
|
|
||||||
/// let mut r = &MUT; // Note that r is mutable
|
|
||||||
/// r.lock(|data| *data += 1);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub trait Mutex {
|
|
||||||
/// Type of data encapsulated by the mutex.
|
|
||||||
type Data;
|
|
||||||
|
|
||||||
/// Creates a critical section and grants temporary mutable access to the encapsulated data.
|
|
||||||
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Driver interfaces.
|
|
||||||
pub mod driver {
|
|
||||||
/// Driver result type, e.g. for indicating successful driver init.
|
|
||||||
pub type Result = core::result::Result<(), ()>;
|
|
||||||
|
|
||||||
/// Device Driver functions.
|
|
||||||
pub trait DeviceDriver {
|
|
||||||
/// Return a compatibility string for identifying the driver.
|
|
||||||
fn compatible(&self) -> &str;
|
|
||||||
|
|
||||||
/// Called by the kernel to bring up the device.
|
|
||||||
fn init(&self) -> Result {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Timekeeping interfaces.
|
|
||||||
pub mod time {
|
|
||||||
use core::time::Duration;
|
|
||||||
|
|
||||||
/// Timer functions.
|
|
||||||
pub trait Timer {
|
|
||||||
/// The timer's resolution.
|
|
||||||
fn resolution(&self) -> Duration;
|
|
||||||
|
|
||||||
/// The uptime since power-on of the device.
|
|
||||||
///
|
|
||||||
/// This includes time consumed by firmware and bootloaders.
|
|
||||||
fn uptime(&self) -> Duration;
|
|
||||||
|
|
||||||
/// Spin for a given duration.
|
|
||||||
fn spin_for(&self, duration: Duration);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,91 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Synchronization primitives.
|
||||||
|
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Synchronization interfaces.
|
||||||
|
pub mod interface {
|
||||||
|
|
||||||
|
/// Any object implementing this trait guarantees exclusive access to the data contained within
|
||||||
|
/// the Mutex for the duration of the provided closure.
|
||||||
|
///
|
||||||
|
/// The trait follows the [Rust embedded WG's
|
||||||
|
/// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
|
||||||
|
/// provides some goodness such as [deadlock
|
||||||
|
/// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
|
||||||
|
/// best implemented **for a reference to a container struct**, and has a usage pattern that
|
||||||
|
/// might feel strange at first:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
|
||||||
|
///
|
||||||
|
/// fn foo() {
|
||||||
|
/// let mut r = &MUT; // Note that r is mutable
|
||||||
|
/// r.lock(|data| *data += 1);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait Mutex {
|
||||||
|
/// The type of encapsulated data.
|
||||||
|
type Data;
|
||||||
|
|
||||||
|
/// Creates a critical section and grants temporary mutable access to the encapsulated data.
|
||||||
|
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A pseudo-lock for teaching purposes.
|
||||||
|
///
|
||||||
|
/// Used to introduce [interior mutability].
|
||||||
|
///
|
||||||
|
/// In contrast to a real Mutex implementation, does not protect against concurrent access from
|
||||||
|
/// other cores to the contained data. This part is preserved for later lessons.
|
||||||
|
///
|
||||||
|
/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
|
||||||
|
/// executing single-threaded, aka only running on a single core with interrupts disabled.
|
||||||
|
///
|
||||||
|
/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
|
||||||
|
pub struct NullLock<T: ?Sized> {
|
||||||
|
data: UnsafeCell<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
unsafe impl<T: ?Sized> Sync for NullLock<T> {}
|
||||||
|
|
||||||
|
impl<T> NullLock<T> {
|
||||||
|
/// Wraps `data` into a new `NullLock`.
|
||||||
|
pub const fn new(data: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: UnsafeCell::new(data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// OS Interface Code
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
impl<T> interface::Mutex for &NullLock<T> {
|
||||||
|
type Data = T;
|
||||||
|
|
||||||
|
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R {
|
||||||
|
// In a real lock, there would be code encapsulating this line that ensures that this
|
||||||
|
// mutable reference will ever only be given out once at a time.
|
||||||
|
let data = unsafe { &mut *self.data.get() };
|
||||||
|
|
||||||
|
f(data)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//! Timer primitives.
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[path = "_arch/aarch64/time.rs"]
|
||||||
|
mod arch_time;
|
||||||
|
pub use arch_time::*;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Timekeeping interfaces.
|
||||||
|
pub mod interface {
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
/// Time management functions.
|
||||||
|
///
|
||||||
|
/// The `BSP` is supposed to supply one global instance.
|
||||||
|
pub trait TimeManager {
|
||||||
|
/// The timer's resolution.
|
||||||
|
fn resolution(&self) -> Duration;
|
||||||
|
|
||||||
|
/// The uptime since power-on of the device.
|
||||||
|
///
|
||||||
|
/// This includes time consumed by firmware and bootloaders.
|
||||||
|
fn uptime(&self) -> Duration;
|
||||||
|
|
||||||
|
/// Spin for a given duration.
|
||||||
|
fn spin_for(&self, duration: Duration);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue