Merge pull request #51 from rust-embedded/2020-03_refactor
Refactor for better modularity and more sensible namespacespull/54/head
commit
f7ffb4a612
@ -0,0 +1,98 @@
|
||||
# Before we start
|
||||
|
||||
The following text is a 1:1 copy of the documentation that can be found at the top of the kernel's
|
||||
main source code file in each tutorial. It describes the general structure of the source code, and
|
||||
tries to convey the philosophy behind the respective approach. Please read it to make yourself
|
||||
familiar with what you will encounter during the tutorials. It will help you to navigate the code
|
||||
better and understand the differences and additions beteween the separate tutorials.
|
||||
|
||||
Please also note that the following text will reference source code files (e.g. `**/memory.rs`) or
|
||||
functions that won't exist yet in the first bunch of the tutorials. They will be added gradually as
|
||||
the tutorials advance.
|
||||
|
||||
Have fun!
|
||||
|
||||
## Code organization and architecture
|
||||
|
||||
The code is divided into different *modules*, each representing a typical **subsystem** of the
|
||||
`kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example,
|
||||
`src/memory.rs` contains code that is concerned with all things memory management.
|
||||
|
||||
## Visibility of processor architecture code
|
||||
|
||||
Some of the `kernel`'s subsystems depend on low-level code that is specific to the target processor
|
||||
architecture. For each supported processor architecture, there exists a subfolder in `src/_arch`,
|
||||
for example, `src/_arch/aarch64`.
|
||||
|
||||
The architecture folders mirror the subsystem modules laid out in `src`. For example, architectural
|
||||
code that belongs to the `kernel`'s memory subsystem (`src/memory.rs`) would go into
|
||||
`src/_arch/aarch64/memory.rs`. The latter file is directly included and re-exported in
|
||||
`src/memory.rs`, so that the architectural code parts are transparent with respect to the code's
|
||||
module organization. That means a public function `foo()` defined in `src/_arch/aarch64/memory.rs`
|
||||
would be reachable as `crate::memory::foo()` only.
|
||||
|
||||
The `_` in `_arch` denotes that this folder is not part of the standard module hierarchy. Rather,
|
||||
it's contents are conditionally pulled into respective files using the `#[path =
|
||||
"_arch/xxx/yyy.rs"]` attribute.
|
||||
|
||||
## BSP code
|
||||
|
||||
`BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains
|
||||
target board specific definitions and functions. These are things such as the board's memory map or
|
||||
instances of drivers for devices that are featured on the respective board.
|
||||
|
||||
Just like processor architecture code, the `BSP` code's module structure tries to mirror the
|
||||
`kernel`'s subsystem modules, but there is no transparent re-exporting this time. That means
|
||||
whatever is provided must be called starting from the `bsp` namespace, e.g.
|
||||
`bsp::driver::driver_manager()`.
|
||||
|
||||
## Kernel interfaces
|
||||
|
||||
Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target and
|
||||
board for which the kernel is compiled. For example, the `interrupt controller` hardware of the
|
||||
`Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` code to
|
||||
play nicely with any of the two without much hassle.
|
||||
|
||||
In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, `interface`
|
||||
traits are provided *whenever possible* and *where it makes sense*. They are defined in the
|
||||
respective subsystem module and help to enforce the idiom of *program to an interface, not an
|
||||
implementation*. For example, there will be a common IRQ handling interface which the two different
|
||||
interrupt controller `drivers` of both Raspberrys will implement, and only export the interface to
|
||||
the rest of the `kernel`.
|
||||
|
||||
```
|
||||
+-------------------+
|
||||
| Interface (Trait) |
|
||||
| |
|
||||
+--+-------------+--+
|
||||
^ ^
|
||||
| |
|
||||
| |
|
||||
+----------+--+ +--+----------+
|
||||
| kernel code | | bsp code |
|
||||
| | | arch code |
|
||||
+-------------+ +-------------+
|
||||
```
|
||||
|
||||
# Summary
|
||||
|
||||
For a logical `kernel` subsystem, corresponding code can be distributed over several physical
|
||||
locations. Here is an example for the **memory** subsystem:
|
||||
|
||||
- `src/memory.rs` and `src/memory/**/*`
|
||||
- Common code that is agnostic of target processor architecture and `BSP` characteristics.
|
||||
- Example: A function to zero a chunk of memory.
|
||||
- Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code.
|
||||
- Example: An `MMU` interface that defines `MMU` function prototypes.
|
||||
- `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*`
|
||||
- `BSP` specific code.
|
||||
- Example: The board's memory map (physical addresses of DRAM and MMIO devices).
|
||||
- `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*`
|
||||
- Processor architecture specific code.
|
||||
- Example: Implementation of the `MMU` interface for the `__arch_name__` processor
|
||||
architecture.
|
||||
|
||||
From a namespace perspective, **memory** subsystem code lives in:
|
||||
|
||||
- `crate::memory::*`
|
||||
- `crate::bsp::memory::*`
|
Binary file not shown.
@ -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::*;
|
@ -0,0 +1,10 @@
|
||||
// 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::*;
|
Binary file not shown.
Binary file not shown.
@ -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::*;
|
@ -0,0 +1,10 @@
|
||||
// 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::*;
|
Binary file not shown.
Binary file not shown.
@ -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::*;
|
@ -0,0 +1,7 @@
|
||||
// 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;
|
@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
//
|
||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||
|
||||
//! BSP console facilities.
|
||||
|
||||
use crate::console;
|
||||
use core::fmt;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Private Definitions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// A mystical, magical device for generating QEMU output out of the void.
|
||||
struct QEMUOutput;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Private Code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
|
||||
/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
|
||||
/// we get `write_fmt()` automatically.
|
||||
///
|
||||
/// See [`src/print.rs`].
|
||||
///
|
||||
/// [`src/print.rs`]: ../../print/index.html
|
||||
impl fmt::Write for QEMUOutput {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for c in s.chars() {
|
||||
unsafe {
|
||||
core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Public Code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Return a reference to the console.
|
||||
pub fn console() -> impl console::interface::Write {
|
||||
QEMUOutput {}
|
||||
}
|
@ -1,38 +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.
|
||||
|
||||
use crate::interface;
|
||||
use core::fmt;
|
||||
|
||||
/// A mystical, magical device for generating QEMU output out of the void.
|
||||
struct QEMUOutput;
|
||||
|
||||
/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
|
||||
/// to implement the `kernel`'s `print!` and `println!` macros.
|
||||
///
|
||||
/// See [`src/print.rs`].
|
||||
///
|
||||
/// [`src/print.rs`]: ../../print/index.html
|
||||
impl interface::console::Write for QEMUOutput {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for c in s.chars() {
|
||||
unsafe {
|
||||
core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Implementation of the kernel's BSP calls
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Returns a ready-to-use `console::Write` implementation.
|
||||
pub fn console() -> impl interface::console::Write {
|
||||
QEMUOutput {}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
// 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 {
|
||||
/// Console write functions.
|
||||
///
|
||||
/// `core::fmt::Write` is exactly what we need for now. Re-export it here because
|
||||
/// implementing `console::Write` gives a better hint to the reader about the
|
||||
/// intention.
|
||||
pub use core::fmt::Write;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// 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::*;
|
@ -1,37 +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 {
|
||||
/// Console write functions.
|
||||
///
|
||||
/// `core::fmt::Write` is exactly what we need for now. Re-export it here because
|
||||
/// implementing `console::Write` gives a better hint to the reader about the
|
||||
/// intention.
|
||||
pub use core::fmt::Write;
|
||||
|
||||
/// Console read functions.
|
||||
pub trait Read {
|
||||
/// Read a single character.
|
||||
fn read_char(&self) -> char {
|
||||
' '
|
||||
}
|
||||
}
|
||||
}
|
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,40 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
//
|
||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||
|
||||
//! AArch64.
|
||||
|
||||
use crate::bsp;
|
||||
use cortex_a::{asm, regs::*};
|
||||
|
||||
/// The entry of the `kernel` binary.
|
||||
///
|
||||
/// The function must be named `_start`, because the linker is looking for this exact name.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Linker script must ensure to place this function at `0x80_000`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn _start() -> ! {
|
||||
const CORE_MASK: u64 = 0x3;
|
||||
|
||||
if bsp::BOOT_CORE_ID == MPIDR_EL1.get() & CORE_MASK {
|
||||
SP.set(bsp::BOOT_CORE_STACK_START);
|
||||
crate::runtime_init::runtime_init()
|
||||
} else {
|
||||
// If not core0, infinitely wait for events.
|
||||
wait_forever()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Implementation of the kernel's architecture abstraction code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Pause execution on the calling CPU core.
|
||||
#[inline(always)]
|
||||
pub fn wait_forever() -> ! {
|
||||
loop {
|
||||
asm::wfe()
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
// 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;
|
@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
//
|
||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||
|
||||
//! BSP console facilities.
|
||||
|
||||
use crate::console;
|
||||
use core::fmt;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Private Definitions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// A mystical, magical device for generating QEMU output out of the void.
|
||||
struct QEMUOutput;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Private Code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
|
||||
/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
|
||||
/// we get `write_fmt()` automatically.
|
||||
///
|
||||
/// See [`src/print.rs`].
|
||||
///
|
||||
/// [`src/print.rs`]: ../../print/index.html
|
||||
impl fmt::Write for QEMUOutput {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for c in s.chars() {
|
||||
unsafe {
|
||||
core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Public Code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Return a reference to the console.
|
||||
pub fn console() -> impl console::interface::Write {
|
||||
QEMUOutput {}
|
||||
}
|
@ -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;
|
@ -1,44 +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.
|
||||
|
||||
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;
|
||||
|
||||
/// A mystical, magical device for generating QEMU output out of the void.
|
||||
struct QEMUOutput;
|
||||
|
||||
/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
|
||||
/// to implement the `kernel`'s `print!` and `println!` macros.
|
||||
///
|
||||
/// See [`src/print.rs`].
|
||||
///
|
||||
/// [`src/print.rs`]: ../../print/index.html
|
||||
impl interface::console::Write for QEMUOutput {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for c in s.chars() {
|
||||
unsafe {
|
||||
core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Implementation of the kernel's BSP calls
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Returns a ready-to-use `console::Write` implementation.
|
||||
pub fn console() -> impl interface::console::Write {
|
||||
QEMUOutput {}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
// 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 {
|
||||
/// Console write functions.
|
||||
///
|
||||
/// `core::fmt::Write` is exactly what we need for now. Re-export it here because
|
||||
/// implementing `console::Write` gives a better hint to the reader about the
|
||||
/// intention.
|
||||
pub use core::fmt::Write;
|
||||
}
|
@ -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::*;
|
@ -1,37 +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 {
|
||||
/// Console write functions.
|
||||
///
|
||||
/// `core::fmt::Write` is exactly what we need for now. Re-export it here because
|
||||
/// implementing `console::Write` gives a better hint to the reader about the
|
||||
/// intention.
|
||||
pub use core::fmt::Write;
|
||||
|
||||
/// Console read functions.
|
||||
pub trait Read {
|
||||
/// Read a single character.
|
||||
fn read_char(&self) -> char {
|
||||
' '
|
||||
}
|
||||
}
|
||||
}
|
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,8 @@
|
||||
// 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;
|
@ -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,31 @@
|
||||
// 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 Rust format string.
|
||||
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
|
||||
}
|
||||
|
||||
/// Console statistics.
|
||||
pub trait Statistics {
|
||||
/// Return the number of characters written.
|
||||
fn chars_written(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait alias for a full-fledged console.
|
||||
pub trait All = Write + 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::*;
|
@ -1,87 +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 Rust format string.
|
||||
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
|
||||
}
|
||||
|
||||
/// Console read functions.
|
||||
pub trait Read {
|
||||
/// Read a single character.
|
||||
fn read_char(&self) -> char {
|
||||
' '
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue