mirror of
https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials.git
synced 2024-11-11 07:10:59 +00:00
Refactor tutorial 04
This commit is contained in:
parent
523af645cd
commit
771dfbab7f
@ -14,7 +14,7 @@ ifeq ($(BSP),rpi3)
|
|||||||
QEMU_BINARY = qemu-system-aarch64
|
QEMU_BINARY = qemu-system-aarch64
|
||||||
QEMU_MACHINE_TYPE = raspi3
|
QEMU_MACHINE_TYPE = raspi3
|
||||||
QEMU_RELEASE_ARGS = -serial stdio -display none
|
QEMU_RELEASE_ARGS = -serial stdio -display none
|
||||||
LINKER_FILE = src/bsp/rpi/link.ld
|
LINKER_FILE = src/bsp/raspberrypi/link.ld
|
||||||
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
|
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
|
||||||
else ifeq ($(BSP),rpi4)
|
else ifeq ($(BSP),rpi4)
|
||||||
TARGET = aarch64-unknown-none-softfloat
|
TARGET = aarch64-unknown-none-softfloat
|
||||||
@ -22,7 +22,7 @@ else ifeq ($(BSP),rpi4)
|
|||||||
# QEMU_BINARY = qemu-system-aarch64
|
# QEMU_BINARY = qemu-system-aarch64
|
||||||
# QEMU_MACHINE_TYPE =
|
# QEMU_MACHINE_TYPE =
|
||||||
# QEMU_RELEASE_ARGS = -serial stdio -display none
|
# QEMU_RELEASE_ARGS = -serial stdio -display none
|
||||||
LINKER_FILE = src/bsp/rpi/link.ld
|
LINKER_FILE = src/bsp/raspberrypi/link.ld
|
||||||
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72
|
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -60,8 +60,7 @@ $(OUTPUT): $(CARGO_OUTPUT)
|
|||||||
$(OBJCOPY_CMD) $< $(OUTPUT)
|
$(OBJCOPY_CMD) $< $(OUTPUT)
|
||||||
|
|
||||||
doc:
|
doc:
|
||||||
cargo xdoc --target=$(TARGET) --features bsp_$(BSP) --document-private-items
|
cargo xdoc --target=$(TARGET) --features bsp_$(BSP) --document-private-items --open
|
||||||
xdg-open target/$(TARGET)/doc/kernel/index.html
|
|
||||||
|
|
||||||
ifeq ($(QEMU_MACHINE_TYPE),)
|
ifeq ($(QEMU_MACHINE_TYPE),)
|
||||||
qemu:
|
qemu:
|
||||||
|
@ -2,157 +2,9 @@
|
|||||||
|
|
||||||
## tl;dr
|
## tl;dr
|
||||||
|
|
||||||
All hand-written assembly is replaced by Rust code from the [cortex-a] crate,
|
All hand-written assembly is replaced by Rust code from the [cortex-a] crate, which provides
|
||||||
which provides zero-overhead abstractions and wraps the `unsafe` parts.
|
zero-overhead abstractions and wraps the `unsafe` parts.
|
||||||
|
|
||||||
[cortex-a]: https://github.com/rust-embedded/cortex-a
|
[cortex-a]: https://github.com/rust-embedded/cortex-a
|
||||||
|
|
||||||
## Diff to previous
|
## Diff to previous
|
||||||
```diff
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/Cargo.toml 04_zero_overhead_abstraction/Cargo.toml
|
|
||||||
--- 03_hacky_hello_world/Cargo.toml
|
|
||||||
+++ 04_zero_overhead_abstraction/Cargo.toml
|
|
||||||
@@ -10,7 +10,10 @@
|
|
||||||
# The features section is used to select the target board.
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
-bsp_rpi3 = []
|
|
||||||
-bsp_rpi4 = []
|
|
||||||
+bsp_rpi3 = ["cortex-a"]
|
|
||||||
+bsp_rpi4 = ["cortex-a"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
+
|
|
||||||
+# Optional dependencies
|
|
||||||
+cortex-a = { version = "2.9.x", optional = true }
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/arch/aarch64/start.S 04_zero_overhead_abstraction/src/arch/aarch64/start.S
|
|
||||||
--- 03_hacky_hello_world/src/arch/aarch64/start.S
|
|
||||||
+++ 04_zero_overhead_abstraction/src/arch/aarch64/start.S
|
|
||||||
@@ -1,21 +0,0 @@
|
|
||||||
-// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
-//
|
|
||||||
-// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
-
|
|
||||||
-.section ".text._start"
|
|
||||||
-
|
|
||||||
-.global _start
|
|
||||||
-
|
|
||||||
-_start:
|
|
||||||
- mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register
|
|
||||||
- and x1, x1, #3 // Clear all bits except [1:0], which hold core id
|
|
||||||
- cbz x1, 2f // Jump to label 2 if we are core 0
|
|
||||||
-1: wfe // Wait for event
|
|
||||||
- b 1b // In case an event happened, jump back to 1
|
|
||||||
-2: // If we are here, we are core0
|
|
||||||
- ldr x1, =_start // Load address of function "_start()"
|
|
||||||
- mov sp, x1 // Set start of stack to before our code, aka first
|
|
||||||
- // address before "_start()"
|
|
||||||
- bl runtime_init // Jump to the "runtime_init()" kernel function
|
|
||||||
- b 1b // We should never reach here. But just in case,
|
|
||||||
- // park this core aswell
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/arch/aarch64.rs 04_zero_overhead_abstraction/src/arch/aarch64.rs
|
|
||||||
--- 03_hacky_hello_world/src/arch/aarch64.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/arch/aarch64.rs
|
|
||||||
@@ -4,7 +4,28 @@
|
|
||||||
|
|
||||||
//! AArch64.
|
|
||||||
|
|
||||||
-global_asm!(include_str!("aarch64/start.S"));
|
|
||||||
+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
|
|
||||||
@@ -13,9 +34,7 @@
|
|
||||||
/// Pause execution on the calling CPU core.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn wait_forever() -> ! {
|
|
||||||
- unsafe {
|
|
||||||
- loop {
|
|
||||||
- asm!("wfe" :::: "volatile")
|
|
||||||
- }
|
|
||||||
+ loop {
|
|
||||||
+ asm::wfe()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/bsp/rpi.rs 04_zero_overhead_abstraction/src/bsp/rpi.rs
|
|
||||||
--- 03_hacky_hello_world/src/bsp/rpi.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/bsp/rpi.rs
|
|
||||||
@@ -7,6 +7,12 @@
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main.rs
|
|
||||||
--- 03_hacky_hello_world/src/main.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/main.rs
|
|
||||||
@@ -19,9 +19,7 @@
|
|
||||||
//! [Architecture-specific code]: arch/index.html
|
|
||||||
//! [`kernel::interface`]: interface/index.html
|
|
||||||
|
|
||||||
-#![feature(asm)]
|
|
||||||
#![feature(format_args_nl)]
|
|
||||||
-#![feature(global_asm)]
|
|
||||||
#![feature(panic_info_message)]
|
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
@@ -47,7 +45,8 @@
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
unsafe fn kernel_init() -> ! {
|
|
||||||
- println!("Hello from Rust!");
|
|
||||||
+ println!("[0] Hello from pure Rust!");
|
|
||||||
|
|
||||||
- panic!("Stopping here.")
|
|
||||||
+ println!("[1] Stopping here.");
|
|
||||||
+ arch::wait_forever()
|
|
||||||
}
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/runtime_init.rs 04_zero_overhead_abstraction/src/runtime_init.rs
|
|
||||||
--- 03_hacky_hello_world/src/runtime_init.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/runtime_init.rs
|
|
||||||
@@ -42,8 +42,7 @@
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
-#[no_mangle]
|
|
||||||
-pub unsafe extern "C" fn runtime_init() -> ! {
|
|
||||||
+pub unsafe fn runtime_init() -> ! {
|
|
||||||
zero_bss();
|
|
||||||
|
|
||||||
crate::kernel_init()
|
|
||||||
|
|
||||||
```
|
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -2,11 +2,15 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
//! AArch64.
|
//! Architectural processor code.
|
||||||
|
|
||||||
use crate::bsp;
|
use crate::{bsp, cpu};
|
||||||
use cortex_a::{asm, regs::*};
|
use cortex_a::{asm, regs::*};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Boot Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// The entry of the `kernel` binary.
|
/// The entry of the `kernel` binary.
|
||||||
///
|
///
|
||||||
/// The function must be named `_start`, because the linker is looking for this exact name.
|
/// The function must be named `_start`, because the linker is looking for this exact name.
|
||||||
@ -14,13 +18,15 @@ use cortex_a::{asm, regs::*};
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// - Linker script must ensure to place this function at `0x80_000`.
|
/// - Linker script must ensure to place this function at `0x80_000`.
|
||||||
|
#[naked]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn _start() -> ! {
|
pub unsafe extern "C" fn _start() -> ! {
|
||||||
const CORE_MASK: u64 = 0x3;
|
use crate::runtime_init;
|
||||||
|
|
||||||
if bsp::BOOT_CORE_ID == MPIDR_EL1.get() & CORE_MASK {
|
// Expect the boot core to start in EL2.
|
||||||
SP.set(bsp::BOOT_CORE_STACK_START);
|
if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
|
||||||
crate::runtime_init::runtime_init()
|
SP.set(bsp::cpu::BOOT_CORE_STACK_START);
|
||||||
|
runtime_init::runtime_init()
|
||||||
} else {
|
} else {
|
||||||
// If not core0, infinitely wait for events.
|
// If not core0, infinitely wait for events.
|
||||||
wait_forever()
|
wait_forever()
|
||||||
@ -28,10 +34,10 @@ pub unsafe extern "C" fn _start() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Implementation of the kernel's architecture abstraction code
|
// Public Code
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Pause execution on the calling CPU core.
|
/// Pause execution on the core.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn wait_forever() -> ! {
|
pub fn wait_forever() -> ! {
|
||||||
loop {
|
loop {
|
22
04_zero_overhead_abstraction/src/_arch/aarch64/cpu/smp.rs
Normal file
22
04_zero_overhead_abstraction/src/_arch/aarch64/cpu/smp.rs
Normal file
@ -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::*;
|
|
@ -2,10 +2,10 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
//! Conditional exporting of Board Support Packages.
|
//! Conditional re-exporting of Board Support Packages.
|
||||||
|
|
||||||
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
||||||
mod rpi;
|
mod raspberrypi;
|
||||||
|
|
||||||
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
||||||
pub use rpi::*;
|
pub use raspberrypi::*;
|
||||||
|
8
04_zero_overhead_abstraction/src/bsp/raspberrypi.rs
Normal file
8
04_zero_overhead_abstraction/src/bsp/raspberrypi.rs
Normal file
@ -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;
|
47
04_zero_overhead_abstraction/src/bsp/raspberrypi/console.rs
Normal file
47
04_zero_overhead_abstraction/src/bsp/raspberrypi/console.rs
Normal file
@ -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 {}
|
||||||
|
}
|
15
04_zero_overhead_abstraction/src/bsp/raspberrypi/cpu.rs
Normal file
15
04_zero_overhead_abstraction/src/bsp/raspberrypi/cpu.rs
Normal file
@ -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 {}
|
|
||||||
}
|
|
19
04_zero_overhead_abstraction/src/console.rs
Normal file
19
04_zero_overhead_abstraction/src/console.rs
Normal file
@ -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;
|
||||||
|
}
|
12
04_zero_overhead_abstraction/src/cpu.rs
Normal file
12
04_zero_overhead_abstraction/src/cpu.rs
Normal file
@ -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;
|
10
04_zero_overhead_abstraction/src/cpu/smp.rs
Normal file
10
04_zero_overhead_abstraction/src/cpu/smp.rs
Normal file
@ -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 {
|
|
||||||
' '
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,39 +5,109 @@
|
|||||||
// Rust embedded logo for `make doc`.
|
// Rust embedded logo for `make doc`.
|
||||||
#![doc(html_logo_url = "https://git.io/JeGIp")]
|
#![doc(html_logo_url = "https://git.io/JeGIp")]
|
||||||
|
|
||||||
//! The `kernel`
|
//! The `kernel` binary.
|
||||||
//!
|
//!
|
||||||
//! The `kernel` is composed by glueing together code from
|
//! # Code organization and architecture
|
||||||
//!
|
//!
|
||||||
//! - [Hardware-specific Board Support Packages] (`BSPs`).
|
//! The code is divided into different *modules*, each representing a typical **subsystem** of the
|
||||||
//! - [Architecture-specific code].
|
//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example,
|
||||||
//! - HW- and architecture-agnostic `kernel` code.
|
//! `src/memory.rs` contains code that is concerned with all things memory management.
|
||||||
//!
|
//!
|
||||||
//! using the [`kernel::interface`] traits.
|
//! ## Visibility of processor architecture code
|
||||||
//!
|
//!
|
||||||
//! [Hardware-specific Board Support Packages]: bsp/index.html
|
//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target
|
||||||
//! [Architecture-specific code]: arch/index.html
|
//! processor architecture. For each supported processor architecture, there exists a subfolder in
|
||||||
//! [`kernel::interface`]: interface/index.html
|
//! `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::*`
|
||||||
|
|
||||||
#![feature(format_args_nl)]
|
#![feature(format_args_nl)]
|
||||||
|
#![feature(naked_functions)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
// Conditionally includes the selected `architecture` code, which provides the `_start()` function,
|
// `mod cpu` provides the `_start()` function, the first function to run. `_start()` then calls
|
||||||
// the first function to run.
|
// `runtime_init()`, which jumps to `kernel_init()`.
|
||||||
mod arch;
|
|
||||||
|
|
||||||
// `_start()` then calls `runtime_init()`, which on completion, jumps to `kernel_init()`.
|
|
||||||
mod runtime_init;
|
|
||||||
|
|
||||||
// Conditionally includes the selected `BSP` code.
|
|
||||||
mod bsp;
|
mod bsp;
|
||||||
|
mod console;
|
||||||
mod interface;
|
mod cpu;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod panic_wait;
|
mod panic_wait;
|
||||||
mod print;
|
mod print;
|
||||||
|
mod runtime_init;
|
||||||
|
|
||||||
/// Early init code.
|
/// Early init code.
|
||||||
///
|
///
|
||||||
@ -48,5 +118,5 @@ unsafe fn kernel_init() -> ! {
|
|||||||
println!("[0] Hello from pure Rust!");
|
println!("[0] Hello from pure Rust!");
|
||||||
|
|
||||||
println!("[1] Stopping here.");
|
println!("[1] Stopping here.");
|
||||||
arch::wait_forever()
|
cpu::wait_forever()
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Zero out a memory region.
|
/// Zero out a memory region.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
//! A panic handler that infinitely waits.
|
//! A panic handler that infinitely waits.
|
||||||
|
|
||||||
use crate::{arch, println};
|
use crate::{cpu, println};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
@ -15,5 +15,5 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
println!("\nKernel panic!");
|
println!("\nKernel panic!");
|
||||||
}
|
}
|
||||||
|
|
||||||
arch::wait_forever()
|
cpu::wait_forever()
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,24 @@
|
|||||||
|
|
||||||
//! Printing facilities.
|
//! Printing facilities.
|
||||||
|
|
||||||
use crate::{bsp, interface};
|
use crate::{bsp, console};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Private Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn _print(args: fmt::Arguments) {
|
pub fn _print(args: fmt::Arguments) {
|
||||||
use interface::console::Write;
|
use console::interface::Write;
|
||||||
|
|
||||||
bsp::console().write_fmt(args).unwrap();
|
bsp::console::console().write_fmt(args).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Prints without a newline.
|
/// Prints without a newline.
|
||||||
///
|
///
|
||||||
/// Carbon copy from https://doc.rust-lang.org/src/std/macros.rs.html
|
/// Carbon copy from https://doc.rust-lang.org/src/std/macros.rs.html
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
use crate::memory;
|
use crate::memory;
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Private Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Return the range spanning the .bss section.
|
/// Return the range spanning the .bss section.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -36,6 +40,10 @@ unsafe fn zero_bss() {
|
|||||||
memory::zero_volatile(bss_range());
|
memory::zero_volatile(bss_range());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
|
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
|
||||||
/// init code.
|
/// init code.
|
||||||
///
|
///
|
||||||
|
Loading…
Reference in New Issue
Block a user