Having a little code formatting party

pull/35/head
Andre Richter 5 years ago
parent 29d992615d
commit 56a650397d
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -5,7 +5,7 @@
//! Conditional exporting of Board Support Packages. //! Conditional exporting of Board Support Packages.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub mod rpi3; mod rpi3;
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub use rpi3::*; pub use rpi3::*;

@ -12,8 +12,8 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.

@ -50,6 +50,22 @@ diff -uNr 01_wait_forever/src/arch/aarch64/start.S 02_runtime_init/src/arch/aarc
+ b 1b // We should never reach here. But just in case, + b 1b // We should never reach here. But just in case,
+ // park this core aswell + // park this core aswell
diff -uNr 01_wait_forever/src/arch/aarch64.rs 02_runtime_init/src/arch/aarch64.rs
--- 01_wait_forever/src/arch/aarch64.rs
+++ 02_runtime_init/src/arch/aarch64.rs
@@ -6,9 +6,9 @@
global_asm!(include_str!("aarch64/start.S"));
-////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation of the kernel's architecture abstraction code
-////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
/// Pause execution on the calling CPU core.
#[inline(always)]
diff -uNr 01_wait_forever/src/bsp/rpi3/link.ld 02_runtime_init/src/bsp/rpi3/link.ld diff -uNr 01_wait_forever/src/bsp/rpi3/link.ld 02_runtime_init/src/bsp/rpi3/link.ld
--- 01_wait_forever/src/bsp/rpi3/link.ld --- 01_wait_forever/src/bsp/rpi3/link.ld
+++ 02_runtime_init/src/bsp/rpi3/link.ld +++ 02_runtime_init/src/bsp/rpi3/link.ld
@ -81,12 +97,11 @@ diff -uNr 01_wait_forever/src/bsp/rpi3/link.ld 02_runtime_init/src/bsp/rpi3/link
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
--- 01_wait_forever/src/main.rs --- 01_wait_forever/src/main.rs
+++ 02_runtime_init/src/main.rs +++ 02_runtime_init/src/main.rs
@@ -16,9 +16,16 @@ @@ -16,9 +16,15 @@
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to +// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
+// `kernel_entry()`.
+mod runtime_init; +mod runtime_init;
+ +
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.
@ -110,8 +125,8 @@ diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.r
+ +
+//! Rust runtime initialization code. +//! Rust runtime initialization code.
+ +
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, +/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
+/// then calls the kernel entry. +/// kernel entry.
+/// +///
+/// Called from `BSP` code. +/// Called from `BSP` code.
+/// +///

Binary file not shown.

Binary file not shown.

@ -6,9 +6,9 @@
global_asm!(include_str!("aarch64/start.S")); global_asm!(include_str!("aarch64/start.S"));
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
/// Pause execution on the calling CPU core. /// Pause execution on the calling CPU core.
#[inline(always)] #[inline(always)]

@ -5,7 +5,7 @@
//! Conditional exporting of Board Support Packages. //! Conditional exporting of Board Support Packages.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub mod rpi3; mod rpi3;
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub use rpi3::*; pub use rpi3::*;

@ -12,12 +12,11 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to // `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
// `kernel_entry()`.
mod runtime_init; mod runtime_init;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.

@ -4,8 +4,8 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// then calls the kernel entry. /// kernel entry.
/// ///
/// Called from `BSP` code. /// Called from `BSP` code.
/// ///

@ -28,10 +28,26 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
endif endif
diff -uNr 02_runtime_init/src/arch/aarch64.rs 03_hacky_hello_world/src/arch/aarch64.rs
--- 02_runtime_init/src/arch/aarch64.rs
+++ 03_hacky_hello_world/src/arch/aarch64.rs
@@ -6,9 +6,9 @@
global_asm!(include_str!("aarch64/start.S"));
-////////////////////////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code
-////////////////////////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
/// Pause execution on the calling CPU core.
#[inline(always)]
diff -uNr 02_runtime_init/src/bsp/rpi3.rs 03_hacky_hello_world/src/bsp/rpi3.rs diff -uNr 02_runtime_init/src/bsp/rpi3.rs 03_hacky_hello_world/src/bsp/rpi3.rs
--- 02_runtime_init/src/bsp/rpi3.rs --- 02_runtime_init/src/bsp/rpi3.rs
+++ 03_hacky_hello_world/src/bsp/rpi3.rs +++ 03_hacky_hello_world/src/bsp/rpi3.rs
@@ -4,4 +4,36 @@ @@ -4,4 +4,35 @@
//! Board Support Package for the Raspberry Pi 3. //! Board Support Package for the Raspberry Pi 3.
@ -42,9 +58,8 @@ diff -uNr 02_runtime_init/src/bsp/rpi3.rs 03_hacky_hello_world/src/bsp/rpi3.rs
+/// A mystical, magical device for generating QEMU output out of the void. +/// A mystical, magical device for generating QEMU output out of the void.
+struct QEMUOutput; +struct QEMUOutput;
+ +
+/// Implementing `console::Write` enables usage of the `format_args!` macros, +/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
+/// which in turn are used to implement the `kernel`'s `print!` and `println!` +/// to implement the `kernel`'s `print!` and `println!` macros.
+/// macros.
+/// +///
+/// See [`src/print.rs`]. +/// See [`src/print.rs`].
+/// +///
@ -61,9 +76,9 @@ diff -uNr 02_runtime_init/src/bsp/rpi3.rs 03_hacky_hello_world/src/bsp/rpi3.rs
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// Implementation of the kernel's BSP calls +// Implementation of the kernel's BSP calls
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+ +
+/// Returns a ready-to-use `console::Write` implementation. +/// Returns a ready-to-use `console::Write` implementation.
+pub fn console() -> impl interface::console::Write { +pub fn console() -> impl interface::console::Write {
@ -98,9 +113,9 @@ diff -uNr 02_runtime_init/src/interface.rs 03_hacky_hello_world/src/interface.rs
+pub mod console { +pub mod console {
+ /// Console write functions. + /// Console write functions.
+ /// + ///
+ /// `core::fmt::Write` is exactly what we need for now. Re-export it here + /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
+ /// because implementing `console::Write` gives a better hint to the reader + /// implementing `console::Write` gives a better hint to the reader about the
+ /// about the intention. + /// intention.
+ pub use core::fmt::Write; + pub use core::fmt::Write;
+ +
+ /// Console read functions. + /// Console read functions.
@ -114,15 +129,21 @@ diff -uNr 02_runtime_init/src/interface.rs 03_hacky_hello_world/src/interface.rs
diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
--- 02_runtime_init/src/main.rs --- 02_runtime_init/src/main.rs
+++ 03_hacky_hello_world/src/main.rs +++ 03_hacky_hello_world/src/main.rs
@@ -6,9 +6,17 @@ @@ -6,9 +6,23 @@
#![doc(html_logo_url = "https://git.io/JeGIp")] #![doc(html_logo_url = "https://git.io/JeGIp")]
//! The `kernel` //! The `kernel`
+//! +//!
+//! The `kernel` is composed by glueing together hardware-specific Board Support +//! The `kernel` is composed by glueing together code from
+//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
+//! [`kernel::interface`] traits.
+//! +//!
+//! - [Hardware-specific Board Support Packages] (`BSPs`).
+//! - [Architecture-specific code].
+//! - HW- and architecture-agnostic `kernel` code.
+//!
+//! using the [`kernel::interface`] traits.
+//!
+//! [Hardware-specific Board Support Packages]: bsp/index.html
+//! [Architecture-specific code]: arch/index.html
+//! [`kernel::interface`]: interface/index.html +//! [`kernel::interface`]: interface/index.html
#![feature(asm)] #![feature(asm)]
@ -132,7 +153,15 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
#![no_main] #![no_main]
#![no_std] #![no_std]
@@ -23,9 +31,13 @@ @@ -16,15 +30,20 @@
// the first function to run.
mod arch;
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to
+// `kernel_entry()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.
mod bsp; mod bsp;

Binary file not shown.

Binary file not shown.

@ -6,9 +6,9 @@
global_asm!(include_str!("aarch64/start.S")); global_asm!(include_str!("aarch64/start.S"));
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Pause execution on the calling CPU core. /// Pause execution on the calling CPU core.
#[inline(always)] #[inline(always)]

@ -5,7 +5,7 @@
//! Conditional exporting of Board Support Packages. //! Conditional exporting of Board Support Packages.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub mod rpi3; mod rpi3;
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub use rpi3::*; pub use rpi3::*;

@ -10,9 +10,8 @@ use core::fmt;
/// A mystical, magical device for generating QEMU output out of the void. /// A mystical, magical device for generating QEMU output out of the void.
struct QEMUOutput; struct QEMUOutput;
/// Implementing `console::Write` enables usage of the `format_args!` macros, /// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
/// which in turn are used to implement the `kernel`'s `print!` and `println!` /// to implement the `kernel`'s `print!` and `println!` macros.
/// macros.
/// ///
/// See [`src/print.rs`]. /// See [`src/print.rs`].
/// ///
@ -29,9 +28,9 @@ impl interface::console::Write for QEMUOutput {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls // Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Returns a ready-to-use `console::Write` implementation. /// Returns a ready-to-use `console::Write` implementation.
pub fn console() -> impl interface::console::Write { pub fn console() -> impl interface::console::Write {

@ -22,9 +22,9 @@
pub mod console { pub mod console {
/// Console write functions. /// Console write functions.
/// ///
/// `core::fmt::Write` is exactly what we need for now. Re-export it here /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
/// because implementing `console::Write` gives a better hint to the reader /// implementing `console::Write` gives a better hint to the reader about the
/// about the intention. /// intention.
pub use core::fmt::Write; pub use core::fmt::Write;
/// Console read functions. /// Console read functions.

@ -7,10 +7,16 @@
//! The `kernel` //! The `kernel`
//! //!
//! The `kernel` is composed by glueing together hardware-specific Board Support //! The `kernel` is composed by glueing together code from
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! //!
//! - [Hardware-specific Board Support Packages] (`BSPs`).
//! - [Architecture-specific code].
//! - HW- and architecture-agnostic `kernel` code.
//!
//! using the [`kernel::interface`] traits.
//!
//! [Hardware-specific Board Support Packages]: bsp/index.html
//! [Architecture-specific code]: arch/index.html
//! [`kernel::interface`]: interface/index.html //! [`kernel::interface`]: interface/index.html
#![feature(asm)] #![feature(asm)]
@ -20,8 +26,8 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to // `_start()` then calls `runtime_init::init()`, which on completion, jumps to

@ -4,8 +4,8 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// then calls the kernel entry. /// kernel entry.
/// ///
/// Called from `BSP` code. /// Called from `BSP` code.
/// ///

@ -55,7 +55,7 @@ diff -uNr 03_hacky_hello_world/src/arch/aarch64/start.S 04_zero_overhead_abstrac
diff -uNr 03_hacky_hello_world/src/arch/aarch64.rs 04_zero_overhead_abstraction/src/arch/aarch64.rs 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 --- 03_hacky_hello_world/src/arch/aarch64.rs
+++ 04_zero_overhead_abstraction/src/arch/aarch64.rs +++ 04_zero_overhead_abstraction/src/arch/aarch64.rs
@@ -4,7 +4,29 @@ @@ -4,7 +4,28 @@
//! AArch64. //! AArch64.
@ -65,8 +65,7 @@ diff -uNr 03_hacky_hello_world/src/arch/aarch64.rs 04_zero_overhead_abstraction/
+ +
+/// 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 +/// The function must be named `_start`, because the linker is looking for this exact name.
+/// exact name.
+/// +///
+/// # Safety +/// # Safety
+/// +///
@ -84,9 +83,9 @@ diff -uNr 03_hacky_hello_world/src/arch/aarch64.rs 04_zero_overhead_abstraction/
+ } + }
+} +}
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
@@ -13,9 +35,7 @@ @@ -13,9 +34,7 @@
/// Pause execution on the calling CPU core. /// Pause execution on the calling CPU core.
#[inline(always)] #[inline(always)]
pub fn wait_forever() -> ! { pub fn wait_forever() -> ! {
@ -116,8 +115,8 @@ diff -uNr 03_hacky_hello_world/src/bsp/rpi3.rs 04_zero_overhead_abstraction/src/
diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main.rs diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main.rs
--- 03_hacky_hello_world/src/main.rs --- 03_hacky_hello_world/src/main.rs
+++ 04_zero_overhead_abstraction/src/main.rs +++ 04_zero_overhead_abstraction/src/main.rs
@@ -13,9 +13,7 @@ @@ -19,9 +19,7 @@
//! //! [Architecture-specific code]: arch/index.html
//! [`kernel::interface`]: interface/index.html //! [`kernel::interface`]: interface/index.html
-#![feature(asm)] -#![feature(asm)]
@ -126,7 +125,7 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![no_main] #![no_main]
#![no_std] #![no_std]
@@ -37,7 +35,8 @@ @@ -43,7 +41,8 @@
/// Entrypoint of the `kernel`. /// Entrypoint of the `kernel`.
fn kernel_entry() -> ! { fn kernel_entry() -> ! {

@ -9,8 +9,7 @@ use cortex_a::{asm, regs::*};
/// 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 /// The function must be named `_start`, because the linker is looking for this exact name.
/// exact name.
/// ///
/// # Safety /// # Safety
/// ///
@ -28,9 +27,9 @@ pub unsafe extern "C" fn _start() -> ! {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Pause execution on the calling CPU core. /// Pause execution on the calling CPU core.
#[inline(always)] #[inline(always)]

@ -5,7 +5,7 @@
//! Conditional exporting of Board Support Packages. //! Conditional exporting of Board Support Packages.
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub mod rpi3; mod rpi3;
#[cfg(feature = "bsp_rpi3")] #[cfg(feature = "bsp_rpi3")]
pub use rpi3::*; pub use rpi3::*;

@ -13,9 +13,8 @@ pub const BOOT_CORE_STACK_START: u64 = 0x80_000;
/// A mystical, magical device for generating QEMU output out of the void. /// A mystical, magical device for generating QEMU output out of the void.
struct QEMUOutput; struct QEMUOutput;
/// Implementing `console::Write` enables usage of the `format_args!` macros, /// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
/// which in turn are used to implement the `kernel`'s `print!` and `println!` /// to implement the `kernel`'s `print!` and `println!` macros.
/// macros.
/// ///
/// See [`src/print.rs`]. /// See [`src/print.rs`].
/// ///
@ -32,9 +31,9 @@ impl interface::console::Write for QEMUOutput {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls // Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Returns a ready-to-use `console::Write` implementation. /// Returns a ready-to-use `console::Write` implementation.
pub fn console() -> impl interface::console::Write { pub fn console() -> impl interface::console::Write {

@ -22,9 +22,9 @@
pub mod console { pub mod console {
/// Console write functions. /// Console write functions.
/// ///
/// `core::fmt::Write` is exactly what we need for now. Re-export it here /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
/// because implementing `console::Write` gives a better hint to the reader /// implementing `console::Write` gives a better hint to the reader about the
/// about the intention. /// intention.
pub use core::fmt::Write; pub use core::fmt::Write;
/// Console read functions. /// Console read functions.

@ -7,10 +7,16 @@
//! The `kernel` //! The `kernel`
//! //!
//! The `kernel` is composed by glueing together hardware-specific Board Support //! The `kernel` is composed by glueing together code from
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! //!
//! - [Hardware-specific Board Support Packages] (`BSPs`).
//! - [Architecture-specific code].
//! - HW- and architecture-agnostic `kernel` code.
//!
//! using the [`kernel::interface`] traits.
//!
//! [Hardware-specific Board Support Packages]: bsp/index.html
//! [Architecture-specific code]: arch/index.html
//! [`kernel::interface`]: interface/index.html //! [`kernel::interface`]: interface/index.html
#![feature(format_args_nl)] #![feature(format_args_nl)]
@ -18,8 +24,8 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to // `_start()` then calls `runtime_init::init()`, which on completion, jumps to

@ -4,8 +4,8 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// then calls the kernel entry. /// kernel entry.
/// ///
/// Called from `BSP` code. /// Called from `BSP` code.
/// ///

@ -45,7 +45,7 @@ you can check out implemntations in the [spin crate] or the [parking lot crate].
diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/src/arch/aarch64/sync.rs diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/src/arch/aarch64/sync.rs
--- 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs --- 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs
+++ 05_safe_globals/src/arch/aarch64/sync.rs +++ 05_safe_globals/src/arch/aarch64/sync.rs
@@ -0,0 +1,47 @@ @@ -0,0 +1,44 @@
+// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT
+// +//
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
@ -59,13 +59,11 @@ diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/
+/// +///
+/// Used to introduce [interior mutability]. +/// Used to introduce [interior mutability].
+/// +///
+/// In contrast to a real Mutex implementation, does not protect against +/// In contrast to a real Mutex implementation, does not protect against concurrent access to the
+/// concurrent access to the contained data. This part is preserved for later +/// contained data. This part is preserved for later lessons.
+/// lessons.
+/// +///
+/// The lock will only be used as long as it is safe to do so, i.e. as long as +/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
+/// the kernel is executing single-threaded, aka only running on a single core +/// executing single-threaded, aka only running on a single core with interrupts disabled.
+/// with interrupts disabled.
+/// +///
+/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html +/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
+pub struct NullLock<T: ?Sized> { +pub struct NullLock<T: ?Sized> {
@ -87,9 +85,8 @@ diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/
+ type Data = T; + type Data = T;
+ +
+ fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + 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 + // In a real lock, there would be code encapsulating this line that ensures that this
+ // ensures that this mutable reference will ever only be given out once + // mutable reference will ever only be given out once at a time.
+ // at a time.
+ f(unsafe { &mut *self.data.get() }) + f(unsafe { &mut *self.data.get() })
+ } + }
+} +}
@ -110,7 +107,7 @@ diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64.rs 05_safe_globals/src/a
diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/rpi3.rs diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/rpi3.rs
--- 04_zero_overhead_abstraction/src/bsp/rpi3.rs --- 04_zero_overhead_abstraction/src/bsp/rpi3.rs
+++ 05_safe_globals/src/bsp/rpi3.rs +++ 05_safe_globals/src/bsp/rpi3.rs
@@ -4,39 +4,115 @@ @@ -4,38 +4,114 @@
//! Board Support Package for the Raspberry Pi 3. //! Board Support Package for the Raspberry Pi 3.
@ -142,14 +139,13 @@ diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/r
+ } + }
+} +}
-/// Implementing `console::Write` enables usage of the `format_args!` macros, -/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, -/// to implement the `kernel`'s `print!` and `println!` macros.
/// which in turn are used to implement the `kernel`'s `print!` and `println!` +/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
-/// macros. +/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
+/// macros. By implementing `write_str()`, we get `write_fmt()` automatically. +/// we get `write_fmt()` automatically.
+/// +///
+/// The function takes an `&mut self`, so it must be implemented for the inner +/// The function takes an `&mut self`, so it must be implemented for the inner struct.
+/// struct.
/// ///
/// See [`src/print.rs`]. /// See [`src/print.rs`].
/// ///
@ -175,9 +171,9 @@ diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/r
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
+// BSP-public +// BSP-public
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+ +
+/// The main struct. +/// The main struct.
+pub struct QEMUOutput { +pub struct QEMUOutput {
@ -192,18 +188,18 @@ diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/r
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// OS interface implementations +// OS interface implementations
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+ +
+/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded +/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
+/// by a Mutex to serialize access. +/// serialize access.
+impl interface::console::Write for QEMUOutput { +impl interface::console::Write for QEMUOutput {
+ fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
+ use interface::sync::Mutex; + use interface::sync::Mutex;
+ +
+ // Fully qualified syntax for the call to + // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
+ // `core::fmt::Write::write:fmt()` to increase readability. + // readability.
+ let mut r = &self.inner; + let mut r = &self.inner;
+ r.lock(|inner| fmt::Write::write_fmt(inner, args)) + r.lock(|inner| fmt::Write::write_fmt(inner, args))
+ } + }
@ -220,15 +216,15 @@ diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/r
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// Global instances +// Global instances
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+ +
+static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new(); +static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new();
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls // Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
-/// Returns a ready-to-use `console::Write` implementation. -/// Returns a ready-to-use `console::Write` implementation.
-pub fn console() -> impl interface::console::Write { -pub fn console() -> impl interface::console::Write {
@ -238,23 +234,10 @@ diff -uNr 04_zero_overhead_abstraction/src/bsp/rpi3.rs 05_safe_globals/src/bsp/r
+ &QEMU_OUTPUT + &QEMU_OUTPUT
} }
diff -uNr 04_zero_overhead_abstraction/src/bsp.rs 05_safe_globals/src/bsp.rs
--- 04_zero_overhead_abstraction/src/bsp.rs
+++ 05_safe_globals/src/bsp.rs
@@ -5,7 +5,7 @@
//! Conditional exporting of Board Support Packages.
#[cfg(feature = "bsp_rpi3")]
-pub mod rpi3;
+mod rpi3;
#[cfg(feature = "bsp_rpi3")]
pub use rpi3::*;
diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/interface.rs diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/interface.rs
--- 04_zero_overhead_abstraction/src/interface.rs --- 04_zero_overhead_abstraction/src/interface.rs
+++ 05_safe_globals/src/interface.rs +++ 05_safe_globals/src/interface.rs
@@ -20,17 +20,68 @@ @@ -20,17 +20,66 @@
/// System console operations. /// System console operations.
pub mod console { pub mod console {
@ -262,9 +245,9 @@ diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/inte
+ +
/// Console write functions. /// Console write functions.
- /// - ///
- /// `core::fmt::Write` is exactly what we need for now. Re-export it here - /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
- /// because implementing `console::Write` gives a better hint to the reader - /// implementing `console::Write` gives a better hint to the reader about the
- /// about the intention. - /// intention.
- pub use core::fmt::Write; - pub use core::fmt::Write;
+ pub trait Write { + pub trait Write {
+ fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
@ -297,20 +280,19 @@ diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/inte
+ +
+/// Synchronization primitives. +/// Synchronization primitives.
+pub mod sync { +pub mod sync {
+ /// Any object implementing this trait guarantees exclusive access to the + /// Any object implementing this trait guarantees exclusive access to the data contained within
+ /// data contained within the mutex for the duration of the lock. + /// the mutex for the duration of the lock.
+ /// + ///
+ /// The trait follows the [Rust embedded WG's + /// The trait follows the [Rust embedded WG's
+ /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) + /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
+ /// and therefore provides some goodness such as [deadlock + /// provides some goodness such as [deadlock
+ /// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility). + /// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
+ /// + ///
+ /// # Example + /// # Example
+ /// + ///
+ /// Since the lock function takes an `&mut self` to enable + /// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
+ /// deadlock-prevention, the trait is best implemented **for a reference to + /// best implemented **for a reference to a container struct**, and has a usage pattern that
+ /// a container struct**, and has a usage pattern that might feel strange at + /// might feel strange at first:
+ /// first:
+ /// + ///
+ /// ``` + /// ```
+ /// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0)); + /// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
@ -324,8 +306,7 @@ diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/inte
+ /// Type of data encapsulated by the mutex. + /// Type of data encapsulated by the mutex.
+ type Data; + type Data;
+ +
+ /// Creates a critical section and grants temporary mutable access to + /// Creates a critical section and grants temporary mutable access to the encapsulated data.
+ /// the encapsulated data.
+ fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
+ } + }
} }
@ -333,7 +314,7 @@ diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/inte
diff -uNr 04_zero_overhead_abstraction/src/main.rs 05_safe_globals/src/main.rs diff -uNr 04_zero_overhead_abstraction/src/main.rs 05_safe_globals/src/main.rs
--- 04_zero_overhead_abstraction/src/main.rs --- 04_zero_overhead_abstraction/src/main.rs
+++ 05_safe_globals/src/main.rs +++ 05_safe_globals/src/main.rs
@@ -15,6 +15,7 @@ @@ -21,6 +21,7 @@
#![feature(format_args_nl)] #![feature(format_args_nl)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
@ -341,7 +322,17 @@ diff -uNr 04_zero_overhead_abstraction/src/main.rs 05_safe_globals/src/main.rs
#![no_main] #![no_main]
#![no_std] #![no_std]
@@ -35,8 +36,12 @@ @@ -28,8 +29,7 @@
// the first function to run.
mod arch;
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to
-// `kernel_entry()`.
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@@ -41,8 +41,12 @@
/// Entrypoint of the `kernel`. /// Entrypoint of the `kernel`.
fn kernel_entry() -> ! { fn kernel_entry() -> ! {

@ -11,8 +11,7 @@ use cortex_a::{asm, regs::*};
/// 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 /// The function must be named `_start`, because the linker is looking for this exact name.
/// exact name.
/// ///
/// # Safety /// # Safety
/// ///
@ -30,9 +29,9 @@ pub unsafe extern "C" fn _start() -> ! {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Pause execution on the calling CPU core. /// Pause execution on the calling CPU core.
#[inline(always)] #[inline(always)]

@ -11,13 +11,11 @@ use core::cell::UnsafeCell;
/// ///
/// Used to introduce [interior mutability]. /// Used to introduce [interior mutability].
/// ///
/// In contrast to a real Mutex implementation, does not protect against /// In contrast to a real Mutex implementation, does not protect against concurrent access to the
/// concurrent access to the contained data. This part is preserved for later /// contained data. This part is preserved for later lessons.
/// lessons.
/// ///
/// The lock will only be used as long as it is safe to do so, i.e. as long as /// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
/// the kernel is executing single-threaded, aka only running on a single core /// executing single-threaded, aka only running on a single core with interrupts disabled.
/// with interrupts disabled.
/// ///
/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html /// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
pub struct NullLock<T: ?Sized> { pub struct NullLock<T: ?Sized> {
@ -39,9 +37,8 @@ impl<T> interface::sync::Mutex for &NullLock<T> {
type Data = T; type Data = T;
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R { 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 // In a real lock, there would be code encapsulating this line that ensures that this
// ensures that this mutable reference will ever only be given out once // mutable reference will ever only be given out once at a time.
// at a time.
f(unsafe { &mut *self.data.get() }) f(unsafe { &mut *self.data.get() })
} }
} }

@ -30,12 +30,11 @@ impl QEMUOutputInner {
} }
} }
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, /// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
/// which in turn are used to implement the `kernel`'s `print!` and `println!` /// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
/// macros. By implementing `write_str()`, we get `write_fmt()` automatically. /// we get `write_fmt()` automatically.
/// ///
/// The function takes an `&mut self`, so it must be implemented for the inner /// The function takes an `&mut self`, so it must be implemented for the inner struct.
/// struct.
/// ///
/// See [`src/print.rs`]. /// See [`src/print.rs`].
/// ///
@ -57,9 +56,9 @@ impl fmt::Write for QEMUOutputInner {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// BSP-public // BSP-public
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// The main struct. /// The main struct.
pub struct QEMUOutput { pub struct QEMUOutput {
@ -74,18 +73,18 @@ impl QEMUOutput {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// OS interface implementations // OS interface implementations
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
/// by a Mutex to serialize access. /// serialize access.
impl interface::console::Write for QEMUOutput { impl interface::console::Write for QEMUOutput {
fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
use interface::sync::Mutex; use interface::sync::Mutex;
// Fully qualified syntax for the call to // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
// `core::fmt::Write::write:fmt()` to increase readability. // readability.
let mut r = &self.inner; let mut r = &self.inner;
r.lock(|inner| fmt::Write::write_fmt(inner, args)) r.lock(|inner| fmt::Write::write_fmt(inner, args))
} }
@ -102,15 +101,15 @@ impl interface::console::Statistics for QEMUOutput {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Global instances // Global instances
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new(); static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new();
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls // Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Return a reference to a `console::All` implementation. /// Return a reference to a `console::All` implementation.
pub fn console() -> &'static impl interface::console::All { pub fn console() -> &'static impl interface::console::All {

@ -53,20 +53,19 @@ pub mod console {
/// Synchronization primitives. /// Synchronization primitives.
pub mod sync { pub mod sync {
/// Any object implementing this trait guarantees exclusive access to the /// Any object implementing this trait guarantees exclusive access to the data contained within
/// data contained within the mutex for the duration of the lock. /// the mutex for the duration of the lock.
/// ///
/// The trait follows the [Rust embedded WG's /// The trait follows the [Rust embedded WG's
/// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
/// and therefore provides some goodness such as [deadlock /// provides some goodness such as [deadlock
/// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility). /// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
/// ///
/// # Example /// # Example
/// ///
/// Since the lock function takes an `&mut self` to enable /// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
/// deadlock-prevention, the trait is best implemented **for a reference to /// best implemented **for a reference to a container struct**, and has a usage pattern that
/// a container struct**, and has a usage pattern that might feel strange at /// might feel strange at first:
/// first:
/// ///
/// ``` /// ```
/// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0)); /// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
@ -80,8 +79,7 @@ pub mod sync {
/// Type of data encapsulated by the mutex. /// Type of data encapsulated by the mutex.
type Data; type Data;
/// Creates a critical section and grants temporary mutable access to /// Creates a critical section and grants temporary mutable access to the encapsulated data.
/// the encapsulated data.
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R; fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
} }
} }

@ -7,10 +7,16 @@
//! The `kernel` //! The `kernel`
//! //!
//! The `kernel` is composed by glueing together hardware-specific Board Support //! The `kernel` is composed by glueing together code from
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! //!
//! - [Hardware-specific Board Support Packages] (`BSPs`).
//! - [Architecture-specific code].
//! - HW- and architecture-agnostic `kernel` code.
//!
//! using the [`kernel::interface`] traits.
//!
//! [Hardware-specific Board Support Packages]: bsp/index.html
//! [Architecture-specific code]: arch/index.html
//! [`kernel::interface`]: interface/index.html //! [`kernel::interface`]: interface/index.html
#![feature(format_args_nl)] #![feature(format_args_nl)]
@ -19,12 +25,11 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to // `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
// `kernel_entry()`.
mod runtime_init; mod runtime_init;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.

@ -4,8 +4,8 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// then calls the kernel entry. /// kernel entry.
/// ///
/// Called from `BSP` code. /// Called from `BSP` code.
/// ///

@ -55,9 +55,9 @@ diff -uNr 05_safe_globals/Cargo.toml 06_drivers_gpio_uart/Cargo.toml
diff -uNr 05_safe_globals/src/arch/aarch64.rs 06_drivers_gpio_uart/src/arch/aarch64.rs diff -uNr 05_safe_globals/src/arch/aarch64.rs 06_drivers_gpio_uart/src/arch/aarch64.rs
--- 05_safe_globals/src/arch/aarch64.rs --- 05_safe_globals/src/arch/aarch64.rs
+++ 06_drivers_gpio_uart/src/arch/aarch64.rs +++ 06_drivers_gpio_uart/src/arch/aarch64.rs
@@ -34,6 +34,8 @@ @@ -33,6 +33,8 @@
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
+pub use asm::nop; +pub use asm::nop;
+ +
@ -198,9 +198,9 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2837_gpio.rs 06_drivers_gpio_uar
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// BSP-public +// BSP-public
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+use interface::sync::Mutex; +use interface::sync::Mutex;
+ +
+/// The driver's main struct. +/// The driver's main struct.
@ -222,9 +222,9 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2837_gpio.rs 06_drivers_gpio_uar
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// OS interface implementations +// OS interface implementations
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+ +
+impl interface::driver::DeviceDriver for GPIO { +impl interface::driver::DeviceDriver for GPIO {
+ fn compatible(&self) -> &str { + fn compatible(&self) -> &str {
@ -235,7 +235,7 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2837_gpio.rs 06_drivers_gpio_uar
diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
--- 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs --- 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
+++ 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs +++ 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
@@ -0,0 +1,287 @@ @@ -0,0 +1,283 @@
+// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT
+// +//
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
@ -255,11 +255,10 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpi
+ +
+ /// Auxiliary enables + /// Auxiliary enables
+ AUX_ENABLES [ + AUX_ENABLES [
+ /// If set the mini UART is enabled. The UART will immediately + /// If set the mini UART is enabled. The UART will immediately start receiving data,
+ /// start receiving data, especially if the UART1_RX line is + /// especially if the UART1_RX line is low.
+ /// low. + ///
+ /// If clear the mini UART is disabled. That also disables any + /// If clear the mini UART is disabled. That also disables any mini UART register access
+ /// mini UART register access
+ MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] + MINI_UART_ENABLE OFFSET(0) NUMBITS(1) []
+ ], + ],
+ +
@ -285,16 +284,14 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpi
+ +
+ /// Mini Uart Line Status + /// Mini Uart Line Status
+ AUX_MU_LSR [ + AUX_MU_LSR [
+ /// This bit is set if the transmit FIFO is empty and the transmitter is + /// This bit is set if the transmit FIFO is empty and the transmitter is idle. (Finished
+ /// idle. (Finished shifting out the last bit). + /// shifting out the last bit).
+ TX_IDLE OFFSET(6) NUMBITS(1) [], + TX_IDLE OFFSET(6) NUMBITS(1) [],
+ +
+ /// This bit is set if the transmit FIFO can accept at least + /// This bit is set if the transmit FIFO can accept at least one byte.
+ /// one byte.
+ TX_EMPTY OFFSET(5) NUMBITS(1) [], + TX_EMPTY OFFSET(5) NUMBITS(1) [],
+ +
+ /// This bit is set if the receive FIFO holds at least 1 + /// This bit is set if the receive FIFO holds at least 1 symbol.
+ /// symbol.
+ DATA_READY OFFSET(0) NUMBITS(1) [] + DATA_READY OFFSET(0) NUMBITS(1) []
+ ], + ],
+ +
@ -393,12 +390,11 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpi
+ } + }
+} +}
+ +
+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, +/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
+/// which in turn are used to implement the `kernel`'s `print!` and `println!` +/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
+/// macros. By implementing `write_str()`, we get `write_fmt()` automatically. +/// we get `write_fmt()` automatically.
+/// +///
+/// The function takes an `&mut self`, so it must be implemented for the inner +/// The function takes an `&mut self`, so it must be implemented for the inner struct.
+/// struct.
+/// +///
+/// See [`src/print.rs`]. +/// See [`src/print.rs`].
+/// +///
@ -421,9 +417,9 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpi
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// BSP-public +// BSP-public
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+ +
+/// The driver's main struct. +/// The driver's main struct.
+pub struct MiniUart { +pub struct MiniUart {
@ -441,9 +437,9 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpi
+ } + }
+} +}
+ +
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+// OS interface implementations +// OS interface implementations
+//////////////////////////////////////////////////////////////////////////////// +//--------------------------------------------------------------------------------------------------
+use interface::sync::Mutex; +use interface::sync::Mutex;
+ +
+impl interface::driver::DeviceDriver for MiniUart { +impl interface::driver::DeviceDriver for MiniUart {
@ -477,16 +473,16 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 06_drivers_gpi
+} +}
+ +
+impl interface::console::Write for MiniUart { +impl interface::console::Write for MiniUart {
+ /// Passthrough of `args` to the `core::fmt::Write` implementation, but + /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
+ /// guarded by a Mutex to serialize access. + /// serialize access.
+ fn write_char(&self, c: char) { + fn write_char(&self, c: char) {
+ let mut r = &self.inner; + let mut r = &self.inner;
+ r.lock(|inner| inner.write_char(c)); + r.lock(|inner| inner.write_char(c));
+ } + }
+ +
+ fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
+ // Fully qualified syntax for the call to + // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
+ // `core::fmt::Write::write:fmt()` to increase readability. + // readability.
+ let mut r = &self.inner; + let mut r = &self.inner;
+ r.lock(|inner| fmt::Write::write_fmt(inner, args)) + r.lock(|inner| fmt::Write::write_fmt(inner, args))
+ } + }
@ -579,7 +575,7 @@ diff -uNr 05_safe_globals/src/bsp/rpi3/memory_map.rs 06_drivers_gpio_uart/src/bs
diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
--- 05_safe_globals/src/bsp/rpi3.rs --- 05_safe_globals/src/bsp/rpi3.rs
+++ 06_drivers_gpio_uart/src/bsp/rpi3.rs +++ 06_drivers_gpio_uart/src/bsp/rpi3.rs
@@ -4,115 +4,59 @@ @@ -4,114 +4,58 @@
//! Board Support Package for the Raspberry Pi 3. //! Board Support Package for the Raspberry Pi 3.
@ -613,12 +609,11 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
- } - }
-} -}
- -
-/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, -/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
-/// which in turn are used to implement the `kernel`'s `print!` and `println!` -/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
-/// macros. By implementing `write_str()`, we get `write_fmt()` automatically. -/// we get `write_fmt()` automatically.
-/// -///
-/// The function takes an `&mut self`, so it must be implemented for the inner -/// The function takes an `&mut self`, so it must be implemented for the inner struct.
-/// struct.
-/// -///
-/// See [`src/print.rs`]. -/// See [`src/print.rs`].
-/// -///
@ -641,10 +636,10 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
- } - }
-} -}
- -
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
-// BSP-public -// BSP-public
+// Global BSP driver instances +// Global BSP driver instances
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
-/// The main struct. -/// The main struct.
-pub struct QEMUOutput { -pub struct QEMUOutput {
@ -662,19 +657,19 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
+static MINI_UART: driver::MiniUart = +static MINI_UART: driver::MiniUart =
+ unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) }; + unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) };
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
-// OS interface implementations -// OS interface implementations
+// Implementation of the kernel's BSP calls +// Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
-/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded -/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
-/// by a Mutex to serialize access. -/// serialize access.
-impl interface::console::Write for QEMUOutput { -impl interface::console::Write for QEMUOutput {
- fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
- use interface::sync::Mutex; - use interface::sync::Mutex;
- -
- // Fully qualified syntax for the call to - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
- // `core::fmt::Write::write:fmt()` to increase readability. - // readability.
- let mut r = &self.inner; - let mut r = &self.inner;
- r.lock(|inner| fmt::Write::write_fmt(inner, args)) - r.lock(|inner| fmt::Write::write_fmt(inner, args))
- } - }
@ -697,9 +692,9 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
+ &MINI_UART + &MINI_UART
} }
-//////////////////////////////////////////////////////////////////////////////// -//--------------------------------------------------------------------------------------------------
-// Global instances -// Global instances
-//////////////////////////////////////////////////////////////////////////////// -//--------------------------------------------------------------------------------------------------
- -
-static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new(); -static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new();
+/// Return an array of references to all `DeviceDriver` compatible `BSP` +/// Return an array of references to all `DeviceDriver` compatible `BSP`
@ -712,18 +707,17 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
+ [&GPIO, &MINI_UART] + [&GPIO, &MINI_UART]
+} +}
-//////////////////////////////////////////////////////////////////////////////// -//--------------------------------------------------------------------------------------------------
-// Implementation of the kernel's BSP calls -// Implementation of the kernel's BSP calls
-//////////////////////////////////////////////////////////////////////////////// -//--------------------------------------------------------------------------------------------------
+/// The BSP's main initialization function. +/// The BSP's main initialization function.
+/// +///
+/// Called early on kernel start. +/// Called early on kernel start.
+pub fn init() { +pub fn init() {
+ for i in device_drivers().iter() { + for i in device_drivers().iter() {
+ if let Err(()) = i.init() { + if let Err(()) = i.init() {
+ // This message will only be readable if, at the time of failure, + // This message will only be readable if, at the time of failure, the return value of
+ // the return value of `bsp::console()` is already in functioning + // `bsp::console()` is already in functioning state.
+ // state.
+ panic!("Error loading driver: {}", i.compatible()) + panic!("Error loading driver: {}", i.compatible())
+ } + }
+ } + }
@ -759,7 +753,7 @@ diff -uNr 05_safe_globals/src/interface.rs 06_drivers_gpio_uart/src/interface.rs
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
} }
@@ -85,3 +86,20 @@ @@ -83,3 +84,20 @@
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R; fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
} }
} }
@ -784,7 +778,7 @@ diff -uNr 05_safe_globals/src/interface.rs 06_drivers_gpio_uart/src/interface.rs
diff -uNr 05_safe_globals/src/main.rs 06_drivers_gpio_uart/src/main.rs diff -uNr 05_safe_globals/src/main.rs 06_drivers_gpio_uart/src/main.rs
--- 05_safe_globals/src/main.rs --- 05_safe_globals/src/main.rs
+++ 06_drivers_gpio_uart/src/main.rs +++ 06_drivers_gpio_uart/src/main.rs
@@ -36,12 +36,23 @@ @@ -41,12 +41,23 @@
/// Entrypoint of the `kernel`. /// Entrypoint of the `kernel`.
fn kernel_entry() -> ! { fn kernel_entry() -> ! {

Binary file not shown.

Binary file not shown.

@ -11,8 +11,7 @@ use cortex_a::{asm, regs::*};
/// 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 /// The function must be named `_start`, because the linker is looking for this exact name.
/// exact name.
/// ///
/// # Safety /// # Safety
/// ///
@ -30,9 +29,9 @@ pub unsafe extern "C" fn _start() -> ! {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
pub use asm::nop; pub use asm::nop;

@ -11,13 +11,11 @@ use core::cell::UnsafeCell;
/// ///
/// Used to introduce [interior mutability]. /// Used to introduce [interior mutability].
/// ///
/// In contrast to a real Mutex implementation, does not protect against /// In contrast to a real Mutex implementation, does not protect against concurrent access to the
/// concurrent access to the contained data. This part is preserved for later /// contained data. This part is preserved for later lessons.
/// lessons.
/// ///
/// The lock will only be used as long as it is safe to do so, i.e. as long as /// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
/// the kernel is executing single-threaded, aka only running on a single core /// executing single-threaded, aka only running on a single core with interrupts disabled.
/// with interrupts disabled.
/// ///
/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html /// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
pub struct NullLock<T: ?Sized> { pub struct NullLock<T: ?Sized> {
@ -39,9 +37,8 @@ impl<T> interface::sync::Mutex for &NullLock<T> {
type Data = T; type Data = T;
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R { 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 // In a real lock, there would be code encapsulating this line that ensures that this
// ensures that this mutable reference will ever only be given out once // mutable reference will ever only be given out once at a time.
// at a time.
f(unsafe { &mut *self.data.get() }) f(unsafe { &mut *self.data.get() })
} }
} }

@ -127,9 +127,9 @@ impl GPIOInner {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// BSP-public // BSP-public
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
use interface::sync::Mutex; use interface::sync::Mutex;
/// The driver's main struct. /// The driver's main struct.
@ -151,9 +151,9 @@ impl GPIO {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// OS interface implementations // OS interface implementations
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
impl interface::driver::DeviceDriver for GPIO { impl interface::driver::DeviceDriver for GPIO {
fn compatible(&self) -> &str { fn compatible(&self) -> &str {

@ -17,11 +17,10 @@ register_bitfields! {
/// Auxiliary enables /// Auxiliary enables
AUX_ENABLES [ AUX_ENABLES [
/// If set the mini UART is enabled. The UART will immediately /// If set the mini UART is enabled. The UART will immediately start receiving data,
/// start receiving data, especially if the UART1_RX line is /// especially if the UART1_RX line is low.
/// low. ///
/// If clear the mini UART is disabled. That also disables any /// If clear the mini UART is disabled. That also disables any mini UART register access
/// mini UART register access
MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] MINI_UART_ENABLE OFFSET(0) NUMBITS(1) []
], ],
@ -47,16 +46,14 @@ register_bitfields! {
/// Mini Uart Line Status /// Mini Uart Line Status
AUX_MU_LSR [ AUX_MU_LSR [
/// This bit is set if the transmit FIFO is empty and the transmitter is /// This bit is set if the transmit FIFO is empty and the transmitter is idle. (Finished
/// idle. (Finished shifting out the last bit). /// shifting out the last bit).
TX_IDLE OFFSET(6) NUMBITS(1) [], TX_IDLE OFFSET(6) NUMBITS(1) [],
/// This bit is set if the transmit FIFO can accept at least /// This bit is set if the transmit FIFO can accept at least one byte.
/// one byte.
TX_EMPTY OFFSET(5) NUMBITS(1) [], TX_EMPTY OFFSET(5) NUMBITS(1) [],
/// This bit is set if the receive FIFO holds at least 1 /// This bit is set if the receive FIFO holds at least 1 symbol.
/// symbol.
DATA_READY OFFSET(0) NUMBITS(1) [] DATA_READY OFFSET(0) NUMBITS(1) []
], ],
@ -155,12 +152,11 @@ impl MiniUartInner {
} }
} }
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, /// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
/// which in turn are used to implement the `kernel`'s `print!` and `println!` /// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
/// macros. By implementing `write_str()`, we get `write_fmt()` automatically. /// we get `write_fmt()` automatically.
/// ///
/// The function takes an `&mut self`, so it must be implemented for the inner /// The function takes an `&mut self`, so it must be implemented for the inner struct.
/// struct.
/// ///
/// See [`src/print.rs`]. /// See [`src/print.rs`].
/// ///
@ -182,9 +178,9 @@ impl fmt::Write for MiniUartInner {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// BSP-public // BSP-public
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// The driver's main struct. /// The driver's main struct.
pub struct MiniUart { pub struct MiniUart {
@ -202,9 +198,9 @@ impl MiniUart {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// OS interface implementations // OS interface implementations
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
use interface::sync::Mutex; use interface::sync::Mutex;
impl interface::driver::DeviceDriver for MiniUart { impl interface::driver::DeviceDriver for MiniUart {
@ -238,16 +234,16 @@ impl interface::driver::DeviceDriver for MiniUart {
} }
impl interface::console::Write for MiniUart { impl interface::console::Write for MiniUart {
/// Passthrough of `args` to the `core::fmt::Write` implementation, but /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
/// guarded by a Mutex to serialize access. /// serialize access.
fn write_char(&self, c: char) { fn write_char(&self, c: char) {
let mut r = &self.inner; let mut r = &self.inner;
r.lock(|inner| inner.write_char(c)); r.lock(|inner| inner.write_char(c));
} }
fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
// Fully qualified syntax for the call to // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
// `core::fmt::Write::write:fmt()` to increase readability. // readability.
let mut r = &self.inner; let mut r = &self.inner;
r.lock(|inner| fmt::Write::write_fmt(inner, args)) r.lock(|inner| fmt::Write::write_fmt(inner, args))
} }

@ -12,17 +12,17 @@ use crate::interface;
pub const BOOT_CORE_ID: u64 = 0; pub const BOOT_CORE_ID: u64 = 0;
pub const BOOT_CORE_STACK_START: u64 = 0x80_000; pub const BOOT_CORE_STACK_START: u64 = 0x80_000;
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Global BSP driver instances // Global BSP driver instances
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) }; static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) };
static MINI_UART: driver::MiniUart = static MINI_UART: driver::MiniUart =
unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) }; unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) };
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls // Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Board identification. /// Board identification.
pub fn board_name() -> &'static str { pub fn board_name() -> &'static str {
@ -34,8 +34,7 @@ pub fn console() -> &'static impl interface::console::All {
&MINI_UART &MINI_UART
} }
/// Return an array of references to all `DeviceDriver` compatible `BSP` /// Return an array of references to all `DeviceDriver` compatible `BSP` drivers.
/// drivers.
/// ///
/// # Safety /// # Safety
/// ///
@ -50,9 +49,8 @@ pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
pub fn init() { pub fn init() {
for i in device_drivers().iter() { for i in device_drivers().iter() {
if let Err(()) = i.init() { if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure, // This message will only be readable if, at the time of failure, the return value of
// the return value of `bsp::console()` is already in functioning // `bsp::console()` is already in functioning state.
// state.
panic!("Error loading driver: {}", i.compatible()) panic!("Error loading driver: {}", i.compatible())
} }
} }

@ -54,20 +54,19 @@ pub mod console {
/// Synchronization primitives. /// Synchronization primitives.
pub mod sync { pub mod sync {
/// Any object implementing this trait guarantees exclusive access to the /// Any object implementing this trait guarantees exclusive access to the data contained within
/// data contained within the mutex for the duration of the lock. /// the mutex for the duration of the lock.
/// ///
/// The trait follows the [Rust embedded WG's /// The trait follows the [Rust embedded WG's
/// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
/// and therefore provides some goodness such as [deadlock /// provides some goodness such as [deadlock
/// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility). /// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
/// ///
/// # Example /// # Example
/// ///
/// Since the lock function takes an `&mut self` to enable /// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
/// deadlock-prevention, the trait is best implemented **for a reference to /// best implemented **for a reference to a container struct**, and has a usage pattern that
/// a container struct**, and has a usage pattern that might feel strange at /// might feel strange at first:
/// first:
/// ///
/// ``` /// ```
/// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0)); /// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
@ -81,8 +80,7 @@ pub mod sync {
/// Type of data encapsulated by the mutex. /// Type of data encapsulated by the mutex.
type Data; type Data;
/// Creates a critical section and grants temporary mutable access to /// Creates a critical section and grants temporary mutable access to the encapsulated data.
/// the encapsulated data.
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R; fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
} }
} }

@ -7,10 +7,16 @@
//! The `kernel` //! The `kernel`
//! //!
//! The `kernel` is composed by glueing together hardware-specific Board Support //! The `kernel` is composed by glueing together code from
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! //!
//! - [Hardware-specific Board Support Packages] (`BSPs`).
//! - [Architecture-specific code].
//! - HW- and architecture-agnostic `kernel` code.
//!
//! using the [`kernel::interface`] traits.
//!
//! [Hardware-specific Board Support Packages]: bsp/index.html
//! [Architecture-specific code]: arch/index.html
//! [`kernel::interface`]: interface/index.html //! [`kernel::interface`]: interface/index.html
#![feature(format_args_nl)] #![feature(format_args_nl)]
@ -19,12 +25,11 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to // `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
// `kernel_entry()`.
mod runtime_init; mod runtime_init;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.

@ -4,8 +4,8 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// then calls the kernel entry. /// kernel entry.
/// ///
/// Called from `BSP` code. /// Called from `BSP` code.
/// ///

@ -103,7 +103,7 @@ diff -uNr 06_drivers_gpio_uart/Makefile 07_uart_chainloader/Makefile
diff -uNr 06_drivers_gpio_uart/src/arch/aarch64.rs 07_uart_chainloader/src/arch/aarch64.rs diff -uNr 06_drivers_gpio_uart/src/arch/aarch64.rs 07_uart_chainloader/src/arch/aarch64.rs
--- 06_drivers_gpio_uart/src/arch/aarch64.rs --- 06_drivers_gpio_uart/src/arch/aarch64.rs
+++ 07_uart_chainloader/src/arch/aarch64.rs +++ 07_uart_chainloader/src/arch/aarch64.rs
@@ -23,7 +23,7 @@ @@ -22,7 +22,7 @@
if bsp::BOOT_CORE_ID == MPIDR_EL1.get() & CORE_MASK { if bsp::BOOT_CORE_ID == MPIDR_EL1.get() & CORE_MASK {
SP.set(bsp::BOOT_CORE_STACK_START); SP.set(bsp::BOOT_CORE_STACK_START);
@ -116,7 +116,22 @@ diff -uNr 06_drivers_gpio_uart/src/arch/aarch64.rs 07_uart_chainloader/src/arch/
diff -uNr 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 07_uart_chainloader/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs diff -uNr 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 07_uart_chainloader/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
--- 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs --- 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
+++ 07_uart_chainloader/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs +++ 07_uart_chainloader/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
@@ -251,6 +251,15 @@ @@ -50,10 +50,12 @@
/// shifting out the last bit).
TX_IDLE OFFSET(6) NUMBITS(1) [],
- /// This bit is set if the transmit FIFO can accept at least one byte.
+ /// This bit is set if the transmit FIFO can accept at least
+ /// one byte.
TX_EMPTY OFFSET(5) NUMBITS(1) [],
- /// This bit is set if the receive FIFO holds at least 1 symbol.
+ /// This bit is set if the receive FIFO holds at least 1
+ /// symbol.
DATA_READY OFFSET(0) NUMBITS(1) []
],
@@ -247,6 +249,15 @@
let mut r = &self.inner; let mut r = &self.inner;
r.lock(|inner| fmt::Write::write_fmt(inner, args)) r.lock(|inner| fmt::Write::write_fmt(inner, args))
} }
@ -132,15 +147,14 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 07_uart_c
} }
impl interface::console::Read for MiniUart { impl interface::console::Read for MiniUart {
@@ -267,14 +276,14 @@ @@ -263,14 +274,14 @@
} }
// Read one character. // Read one character.
- let mut ret = inner.AUX_MU_IO.get() as u8 as char; - let mut ret = inner.AUX_MU_IO.get() as u8 as char;
- -
- // Convert carrige return to newline. - // Convert carrige return to newline.
- if ret == ' - if ret == ' ' {
' {
- ret = ' - ret = '
' '
- } - }
@ -199,9 +213,19 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/rpi3.rs 07_uart_chainloader/src/bsp/rpi3.
+/// The address on which the RPi3 firmware loads every binary by default. +/// The address on which the RPi3 firmware loads every binary by default.
+pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x80_000; +pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x80_000;
+ +
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Global BSP driver instances // Global BSP driver instances
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
@@ -34,8 +37,7 @@
&MINI_UART
}
-/// Return an array of references to all `DeviceDriver` compatible `BSP`
-/// drivers.
+/// Return an array of references to all `DeviceDriver` compatible `BSP` drivers.
///
/// # Safety
///
diff -uNr 06_drivers_gpio_uart/src/interface.rs 07_uart_chainloader/src/interface.rs diff -uNr 06_drivers_gpio_uart/src/interface.rs 07_uart_chainloader/src/interface.rs
--- 06_drivers_gpio_uart/src/interface.rs --- 06_drivers_gpio_uart/src/interface.rs
@ -211,8 +235,8 @@ diff -uNr 06_drivers_gpio_uart/src/interface.rs 07_uart_chainloader/src/interfac
fn write_char(&self, c: char); fn write_char(&self, c: char);
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
+ +
+ /// Block execution until the last character has been physically put on + /// Block execution until the last character has been physically put on the TX wire
+ /// the TX wire (draining TX buffers/FIFOs, if any). + /// (draining TX buffers/FIFOs, if any).
+ fn flush(&self); + fn flush(&self);
} }
@ -231,21 +255,20 @@ diff -uNr 06_drivers_gpio_uart/src/interface.rs 07_uart_chainloader/src/interfac
diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
--- 06_drivers_gpio_uart/src/main.rs --- 06_drivers_gpio_uart/src/main.rs
+++ 07_uart_chainloader/src/main.rs +++ 07_uart_chainloader/src/main.rs
@@ -23,8 +23,11 @@ @@ -29,7 +29,11 @@
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to -// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
-// `kernel_entry()`.
+// `_start()` then calls `relocate::relocate_self()`. +// `_start()` then calls `relocate::relocate_self()`.
+mod relocate; +mod relocate;
+ +
+// `relocate::relocate_self()` calls `runtime_init::init()`, which on +// `relocate::relocate_self()` calls `runtime_init::init()`, which on completion, jumps to
+// completion, jumps to `kernel_entry()`. +// `kernel_entry()`.
mod runtime_init; mod runtime_init;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.
@@ -41,18 +44,48 @@ @@ -46,18 +50,48 @@
// Run the BSP's initialization code. // Run the BSP's initialization code.
bsp::init(); bsp::init();
@ -260,8 +283,8 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
+ println!("[ML] Requesting binary"); + println!("[ML] Requesting binary");
+ bsp::console().flush(); + bsp::console().flush();
+ +
+ // Clear the RX FIFOs, if any, of spurious received characters before + // Clear the RX FIFOs, if any, of spurious received characters before starting with the loader
+ // starting with the loader protocol. + // protocol.
+ bsp::console().clear(); + bsp::console().clear();
+ +
+ // Notify raspbootcom to send the binary. + // Notify raspbootcom to send the binary.
@ -309,15 +332,15 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.rs diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.rs
--- 06_drivers_gpio_uart/src/relocate.rs --- 06_drivers_gpio_uart/src/relocate.rs
+++ 07_uart_chainloader/src/relocate.rs +++ 07_uart_chainloader/src/relocate.rs
@@ -0,0 +1,47 @@ @@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT
+// +//
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
+ +
+//! Relocation code. +//! Relocation code.
+ +
+/// Relocates the own binary from `bsp::BOARD_DEFAULT_LOAD_ADDRESS` to the +/// Relocates the own binary from `bsp::BOARD_DEFAULT_LOAD_ADDRESS` to the `__binary_start` address
+/// `__binary_start` address from the linker script. +/// from the linker script.
+/// +///
+/// # Safety +/// # Safety
+/// +///
@ -341,8 +364,7 @@ diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.
+ +
+ // Copy the whole binary. + // Copy the whole binary.
+ // + //
+ // This is essentially a `memcpy()` optimized for throughput by transferring + // This is essentially a `memcpy()` optimized for throughput by transferring in chunks of T.
+ // in chunks of T.
+ let n = binary_size_in_byte / core::mem::size_of::<T>(); + let n = binary_size_in_byte / core::mem::size_of::<T>();
+ for _ in 0..n { + for _ in 0..n {
+ use core::ptr; + use core::ptr;
@ -352,28 +374,26 @@ diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.
+ src_addr = src_addr.offset(1); + src_addr = src_addr.offset(1);
+ } + }
+ +
+ // Call `init()` through a trait object, causing the jump to use an absolute + // Call `init()` through a trait object, causing the jump to use an absolute address to reach
+ // address to reach the relocated binary. An elaborate explanation can be + // the relocated binary. An elaborate explanation can be found in the runtime_init.rs source
+ // found in the runtime_init.rs source comments. + // comments.
+ crate::runtime_init::get().init() + crate::runtime_init::get().init()
+} +}
diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runtime_init.rs diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runtime_init.rs
--- 06_drivers_gpio_uart/src/runtime_init.rs --- 06_drivers_gpio_uart/src/runtime_init.rs
+++ 07_uart_chainloader/src/runtime_init.rs +++ 07_uart_chainloader/src/runtime_init.rs
@@ -4,23 +4,44 @@ @@ -4,23 +4,41 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
-/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, -/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
-/// then calls the kernel entry. -/// kernel entry.
+/// We are outsmarting the compiler here by using a trait as a layer of +/// We are outsmarting the compiler here by using a trait as a layer of indirection. Because we are
+/// indirection. Because we are generating PIC code, a static dispatch to +/// generating PIC code, a static dispatch to `init()` would generate a relative jump from the
+/// `init()` would generate a relative jump from the callee to `init()`. +/// callee to `init()`. However, when calling `init()`, code just finished copying the binary to the
+/// However, when calling `init()`, code just finished copying the binary to the +/// actual link-time address, and hence is still running at whatever location the previous loader
+/// actual link-time address, and hence is still running at whatever location +/// has put it. So we do not want a relative jump, because it would not jump to the relocated code.
+/// the previous loader has put it. So we do not want a relative jump, because
+/// it would not jump to the relocated code.
/// ///
-/// Called from `BSP` code. -/// Called from `BSP` code.
-/// -///
@ -385,12 +405,11 @@ diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runti
- // Boundaries of the .bss section, provided by the linker script. - // Boundaries of the .bss section, provided by the linker script.
- static mut __bss_start: u64; - static mut __bss_start: u64;
- static mut __bss_end: u64; - static mut __bss_end: u64;
+/// By indirecting through a trait object, we can make use of the property that +/// By indirecting through a trait object, we can make use of the property that vtables store
+/// vtables store absolute addresses. So calling `init()` this way will kick +/// absolute addresses. So calling `init()` this way will kick execution to the relocated binary.
+/// execution to the relocated binary.
+pub trait RunTimeInit { +pub trait RunTimeInit {
+ /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, + /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
+ /// then calls the kernel entry. + /// kernel entry.
+ /// + ///
+ /// Called from `BSP` code. + /// Called from `BSP` code.
+ /// + ///

Binary file not shown.

Binary file not shown.

@ -11,8 +11,7 @@ use cortex_a::{asm, regs::*};
/// 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 /// The function must be named `_start`, because the linker is looking for this exact name.
/// exact name.
/// ///
/// # Safety /// # Safety
/// ///
@ -30,9 +29,9 @@ pub unsafe extern "C" fn _start() -> ! {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code // Implementation of the kernel's architecture abstraction code
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
pub use asm::nop; pub use asm::nop;

@ -11,13 +11,11 @@ use core::cell::UnsafeCell;
/// ///
/// Used to introduce [interior mutability]. /// Used to introduce [interior mutability].
/// ///
/// In contrast to a real Mutex implementation, does not protect against /// In contrast to a real Mutex implementation, does not protect against concurrent access to the
/// concurrent access to the contained data. This part is preserved for later /// contained data. This part is preserved for later lessons.
/// lessons.
/// ///
/// The lock will only be used as long as it is safe to do so, i.e. as long as /// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
/// the kernel is executing single-threaded, aka only running on a single core /// executing single-threaded, aka only running on a single core with interrupts disabled.
/// with interrupts disabled.
/// ///
/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html /// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
pub struct NullLock<T: ?Sized> { pub struct NullLock<T: ?Sized> {
@ -39,9 +37,8 @@ impl<T> interface::sync::Mutex for &NullLock<T> {
type Data = T; type Data = T;
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R { 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 // In a real lock, there would be code encapsulating this line that ensures that this
// ensures that this mutable reference will ever only be given out once // mutable reference will ever only be given out once at a time.
// at a time.
f(unsafe { &mut *self.data.get() }) f(unsafe { &mut *self.data.get() })
} }
} }

@ -127,9 +127,9 @@ impl GPIOInner {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// BSP-public // BSP-public
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
use interface::sync::Mutex; use interface::sync::Mutex;
/// The driver's main struct. /// The driver's main struct.
@ -151,9 +151,9 @@ impl GPIO {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// OS interface implementations // OS interface implementations
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
impl interface::driver::DeviceDriver for GPIO { impl interface::driver::DeviceDriver for GPIO {
fn compatible(&self) -> &str { fn compatible(&self) -> &str {

@ -17,11 +17,10 @@ register_bitfields! {
/// Auxiliary enables /// Auxiliary enables
AUX_ENABLES [ AUX_ENABLES [
/// If set the mini UART is enabled. The UART will immediately /// If set the mini UART is enabled. The UART will immediately start receiving data,
/// start receiving data, especially if the UART1_RX line is /// especially if the UART1_RX line is low.
/// low. ///
/// If clear the mini UART is disabled. That also disables any /// If clear the mini UART is disabled. That also disables any mini UART register access
/// mini UART register access
MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] MINI_UART_ENABLE OFFSET(0) NUMBITS(1) []
], ],
@ -47,16 +46,14 @@ register_bitfields! {
/// Mini Uart Line Status /// Mini Uart Line Status
AUX_MU_LSR [ AUX_MU_LSR [
/// This bit is set if the transmit FIFO is empty and the transmitter is /// This bit is set if the transmit FIFO is empty and the transmitter is idle. (Finished
/// idle. (Finished shifting out the last bit). /// shifting out the last bit).
TX_IDLE OFFSET(6) NUMBITS(1) [], TX_IDLE OFFSET(6) NUMBITS(1) [],
/// This bit is set if the transmit FIFO can accept at least /// This bit is set if the transmit FIFO can accept at least one byte.
/// one byte.
TX_EMPTY OFFSET(5) NUMBITS(1) [], TX_EMPTY OFFSET(5) NUMBITS(1) [],
/// This bit is set if the receive FIFO holds at least 1 /// This bit is set if the receive FIFO holds at least 1 symbol.
/// symbol.
DATA_READY OFFSET(0) NUMBITS(1) [] DATA_READY OFFSET(0) NUMBITS(1) []
], ],
@ -155,12 +152,11 @@ impl MiniUartInner {
} }
} }
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, /// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
/// which in turn are used to implement the `kernel`'s `print!` and `println!` /// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
/// macros. By implementing `write_str()`, we get `write_fmt()` automatically. /// we get `write_fmt()` automatically.
/// ///
/// The function takes an `&mut self`, so it must be implemented for the inner /// The function takes an `&mut self`, so it must be implemented for the inner struct.
/// struct.
/// ///
/// See [`src/print.rs`]. /// See [`src/print.rs`].
/// ///
@ -182,9 +178,9 @@ impl fmt::Write for MiniUartInner {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// BSP-public // BSP-public
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// The driver's main struct. /// The driver's main struct.
pub struct MiniUart { pub struct MiniUart {
@ -202,9 +198,9 @@ impl MiniUart {
} }
} }
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// OS interface implementations // OS interface implementations
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
use interface::sync::Mutex; use interface::sync::Mutex;
impl interface::driver::DeviceDriver for MiniUart { impl interface::driver::DeviceDriver for MiniUart {
@ -238,16 +234,16 @@ impl interface::driver::DeviceDriver for MiniUart {
} }
impl interface::console::Write for MiniUart { impl interface::console::Write for MiniUart {
/// Passthrough of `args` to the `core::fmt::Write` implementation, but /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
/// guarded by a Mutex to serialize access. /// serialize access.
fn write_char(&self, c: char) { fn write_char(&self, c: char) {
let mut r = &self.inner; let mut r = &self.inner;
r.lock(|inner| inner.write_char(c)); r.lock(|inner| inner.write_char(c));
} }
fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
// Fully qualified syntax for the call to // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
// `core::fmt::Write::write:fmt()` to increase readability. // readability.
let mut r = &self.inner; let mut r = &self.inner;
r.lock(|inner| fmt::Write::write_fmt(inner, args)) r.lock(|inner| fmt::Write::write_fmt(inner, args))
} }

@ -15,17 +15,17 @@ pub const BOOT_CORE_STACK_START: u64 = 0x80_000;
/// The address on which the RPi3 firmware loads every binary by default. /// The address on which the RPi3 firmware loads every binary by default.
pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x80_000; pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x80_000;
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Global BSP driver instances // Global BSP driver instances
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) }; static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) };
static MINI_UART: driver::MiniUart = static MINI_UART: driver::MiniUart =
unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) }; unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) };
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls // Implementation of the kernel's BSP calls
//////////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------
/// Board identification. /// Board identification.
pub fn board_name() -> &'static str { pub fn board_name() -> &'static str {
@ -37,8 +37,7 @@ pub fn console() -> &'static impl interface::console::All {
&MINI_UART &MINI_UART
} }
/// Return an array of references to all `DeviceDriver` compatible `BSP` /// Return an array of references to all `DeviceDriver` compatible `BSP` drivers.
/// drivers.
/// ///
/// # Safety /// # Safety
/// ///
@ -53,9 +52,8 @@ pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
pub fn init() { pub fn init() {
for i in device_drivers().iter() { for i in device_drivers().iter() {
if let Err(()) = i.init() { if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure, // This message will only be readable if, at the time of failure, the return value of
// the return value of `bsp::console()` is already in functioning // `bsp::console()` is already in functioning state.
// state.
panic!("Error loading driver: {}", i.compatible()) panic!("Error loading driver: {}", i.compatible())
} }
} }

@ -27,8 +27,8 @@ pub mod console {
fn write_char(&self, c: char); fn write_char(&self, c: char);
fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result;
/// Block execution until the last character has been physically put on /// Block execution until the last character has been physically put on the TX wire
/// the TX wire (draining TX buffers/FIFOs, if any). /// (draining TX buffers/FIFOs, if any).
fn flush(&self); fn flush(&self);
} }
@ -61,20 +61,19 @@ pub mod console {
/// Synchronization primitives. /// Synchronization primitives.
pub mod sync { pub mod sync {
/// Any object implementing this trait guarantees exclusive access to the /// Any object implementing this trait guarantees exclusive access to the data contained within
/// data contained within the mutex for the duration of the lock. /// the mutex for the duration of the lock.
/// ///
/// The trait follows the [Rust embedded WG's /// The trait follows the [Rust embedded WG's
/// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
/// and therefore provides some goodness such as [deadlock /// provides some goodness such as [deadlock
/// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility). /// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
/// ///
/// # Example /// # Example
/// ///
/// Since the lock function takes an `&mut self` to enable /// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
/// deadlock-prevention, the trait is best implemented **for a reference to /// best implemented **for a reference to a container struct**, and has a usage pattern that
/// a container struct**, and has a usage pattern that might feel strange at /// might feel strange at first:
/// first:
/// ///
/// ``` /// ```
/// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0)); /// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
@ -88,8 +87,7 @@ pub mod sync {
/// Type of data encapsulated by the mutex. /// Type of data encapsulated by the mutex.
type Data; type Data;
/// Creates a critical section and grants temporary mutable access to /// Creates a critical section and grants temporary mutable access to the encapsulated data.
/// the encapsulated data.
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R; fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
} }
} }

@ -7,10 +7,16 @@
//! The `kernel` //! The `kernel`
//! //!
//! The `kernel` is composed by glueing together hardware-specific Board Support //! The `kernel` is composed by glueing together code from
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! //!
//! - [Hardware-specific Board Support Packages] (`BSPs`).
//! - [Architecture-specific code].
//! - HW- and architecture-agnostic `kernel` code.
//!
//! using the [`kernel::interface`] traits.
//!
//! [Hardware-specific Board Support Packages]: bsp/index.html
//! [Architecture-specific code]: arch/index.html
//! [`kernel::interface`]: interface/index.html //! [`kernel::interface`]: interface/index.html
#![feature(format_args_nl)] #![feature(format_args_nl)]
@ -19,15 +25,15 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// Conditionally includes the selected `architecture` code, which provides the // Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// `_start()` function, the first function to run. // the first function to run.
mod arch; mod arch;
// `_start()` then calls `relocate::relocate_self()`. // `_start()` then calls `relocate::relocate_self()`.
mod relocate; mod relocate;
// `relocate::relocate_self()` calls `runtime_init::init()`, which on // `relocate::relocate_self()` calls `runtime_init::init()`, which on completion, jumps to
// completion, jumps to `kernel_entry()`. // `kernel_entry()`.
mod runtime_init; mod runtime_init;
// Conditionally includes the selected `BSP` code. // Conditionally includes the selected `BSP` code.
@ -54,8 +60,8 @@ fn kernel_entry() -> ! {
println!("[ML] Requesting binary"); println!("[ML] Requesting binary");
bsp::console().flush(); bsp::console().flush();
// Clear the RX FIFOs, if any, of spurious received characters before // Clear the RX FIFOs, if any, of spurious received characters before starting with the loader
// starting with the loader protocol. // protocol.
bsp::console().clear(); bsp::console().clear();
// Notify raspbootcom to send the binary. // Notify raspbootcom to send the binary.

@ -4,8 +4,8 @@
//! Relocation code. //! Relocation code.
/// Relocates the own binary from `bsp::BOARD_DEFAULT_LOAD_ADDRESS` to the /// Relocates the own binary from `bsp::BOARD_DEFAULT_LOAD_ADDRESS` to the `__binary_start` address
/// `__binary_start` address from the linker script. /// from the linker script.
/// ///
/// # Safety /// # Safety
/// ///
@ -29,8 +29,7 @@ pub unsafe fn relocate_self<T>() -> ! {
// Copy the whole binary. // Copy the whole binary.
// //
// This is essentially a `memcpy()` optimized for throughput by transferring // This is essentially a `memcpy()` optimized for throughput by transferring in chunks of T.
// in chunks of T.
let n = binary_size_in_byte / core::mem::size_of::<T>(); let n = binary_size_in_byte / core::mem::size_of::<T>();
for _ in 0..n { for _ in 0..n {
use core::ptr; use core::ptr;
@ -40,8 +39,8 @@ pub unsafe fn relocate_self<T>() -> ! {
src_addr = src_addr.offset(1); src_addr = src_addr.offset(1);
} }
// Call `init()` through a trait object, causing the jump to use an absolute // Call `init()` through a trait object, causing the jump to use an absolute address to reach
// address to reach the relocated binary. An elaborate explanation can be // the relocated binary. An elaborate explanation can be found in the runtime_init.rs source
// found in the runtime_init.rs source comments. // comments.
crate::runtime_init::get().init() crate::runtime_init::get().init()
} }

@ -4,20 +4,17 @@
//! Rust runtime initialization code. //! Rust runtime initialization code.
/// We are outsmarting the compiler here by using a trait as a layer of /// We are outsmarting the compiler here by using a trait as a layer of indirection. Because we are
/// indirection. Because we are generating PIC code, a static dispatch to /// generating PIC code, a static dispatch to `init()` would generate a relative jump from the
/// `init()` would generate a relative jump from the callee to `init()`. /// callee to `init()`. However, when calling `init()`, code just finished copying the binary to the
/// However, when calling `init()`, code just finished copying the binary to the /// actual link-time address, and hence is still running at whatever location the previous loader
/// actual link-time address, and hence is still running at whatever location /// has put it. So we do not want a relative jump, because it would not jump to the relocated code.
/// the previous loader has put it. So we do not want a relative jump, because
/// it would not jump to the relocated code.
/// ///
/// By indirecting through a trait object, we can make use of the property that /// By indirecting through a trait object, we can make use of the property that vtables store
/// vtables store absolute addresses. So calling `init()` this way will kick /// absolute addresses. So calling `init()` this way will kick execution to the relocated binary.
/// execution to the relocated binary.
pub trait RunTimeInit { pub trait RunTimeInit {
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// then calls the kernel entry. /// kernel entry.
/// ///
/// Called from `BSP` code. /// Called from `BSP` code.
/// ///

@ -9,17 +9,17 @@ require 'fileutils'
require_relative 'helpers/tutorial_folders.rb' require_relative 'helpers/tutorial_folders.rb'
def clean_all def clean_all
crates = tutorial_folders crates = tutorial_folders
crates.each do |x| crates.each do |x|
x = File.dirname(x) x = File.dirname(x)
Dir.chdir(x) do Dir.chdir(x) do
puts "Cleaning #{x}" puts "Cleaning #{x}"
system('rm -rf target') || exit(1) system('rm -rf target') || exit(1)
end
end end
end
FileUtils.rm_rf('xbuild_sysroot') FileUtils.rm_rf('xbuild_sysroot')
end end
clean_all if $PROGRAM_NAME == __FILE__ clean_all if $PROGRAM_NAME == __FILE__

@ -8,16 +8,16 @@
require_relative 'helpers/tutorial_folders.rb' require_relative 'helpers/tutorial_folders.rb'
def clippy_all def clippy_all
crates = tutorial_folders crates = tutorial_folders
crates.each do |x| crates.each do |x|
x = File.dirname(x) x = File.dirname(x)
Dir.chdir(x) do Dir.chdir(x) do
puts "Clippy: #{x}" puts "Clippy: #{x}"
system('make clippy') system('make clippy')
end
end end
end
end end
clippy_all if $PROGRAM_NAME == __FILE__ clippy_all if $PROGRAM_NAME == __FILE__

@ -9,14 +9,14 @@ require 'fileutils'
require_relative 'helpers/tutorial_folders.rb' require_relative 'helpers/tutorial_folders.rb'
def diff_all def diff_all
crates = tutorial_folders crates = tutorial_folders
for i in 0..(crates.length - 2) (0..(crates.length - 2)).each do |i|
old = File.dirname(crates[i]) old = File.dirname(crates[i])
new = File.dirname(crates[i + 1]) new = File.dirname(crates[i + 1])
puts "Diffing #{old} -> #{new}" puts "Diffing #{old} -> #{new}"
system("bash utils/helpers/diff_tut_folders.bash #{old} #{new}") system("bash utils/helpers/diff_tut_folders.bash #{old} #{new}")
end end
end end
diff_all if $PROGRAM_NAME == __FILE__ diff_all if $PROGRAM_NAME == __FILE__

@ -8,16 +8,16 @@
require_relative 'helpers/tutorial_folders.rb' require_relative 'helpers/tutorial_folders.rb'
def fmt_all def fmt_all
crates = tutorial_folders crates = tutorial_folders
crates.each do |x| crates.each do |x|
x = File.dirname(x) x = File.dirname(x)
Dir.chdir(x) do Dir.chdir(x) do
puts "Formatting #{x}" puts "Formatting #{x}"
system('cargo fmt') system('cargo fmt')
end
end end
end
end end
fmt_all if $PROGRAM_NAME == __FILE__ fmt_all if $PROGRAM_NAME == __FILE__

@ -5,41 +5,41 @@
# Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com> # Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
def checkin_years(file) def checkin_years(file)
checkin_years = `git --no-pager log \ checkin_years = `git --no-pager log \
--reverse --pretty=format:'%ad' --date=format:'%Y' #{file}` --reverse --pretty=format:'%ad' --date=format:'%Y' #{file}`
checkin_years.split(/\n/).map!(&:to_i) checkin_years.split(/\n/).map!(&:to_i)
end end
def copyrighted?(file, is_being_checked_in) def copyrighted?(file, is_being_checked_in)
checkin_years = checkin_years(file) checkin_years = checkin_years(file)
checkin_years << Time.now.year if is_being_checked_in checkin_years << Time.now.year if is_being_checked_in
checkin_min = checkin_years.min checkin_min = checkin_years.min
checkin_max = checkin_years.max checkin_max = checkin_years.max
copyright_lines = File.readlines(file).grep(/.*Copyright.*/) copyright_lines = File.readlines(file).grep(/.*Copyright.*/)
min_seen = false min_seen = false
max_seen = false max_seen = false
copyright_lines.each do |x| copyright_lines.each do |x|
x.scan(/\d\d\d\d/).each do |y| x.scan(/\d\d\d\d/).each do |y|
y = y.to_i y = y.to_i
min_seen = true if y == checkin_min min_seen = true if y == checkin_min
max_seen = true if y == checkin_max max_seen = true if y == checkin_max
end
end end
end
unless min_seen && max_seen unless min_seen && max_seen
puts file + ': ' puts file + ': '
puts "\tHeader: " + copyright_lines.inspect puts "\tHeader: " + copyright_lines.inspect
puts "\tMin year: " + checkin_min.to_s puts "\tMin year: " + checkin_min.to_s
puts "\tMax year: " + checkin_max.to_s puts "\tMax year: " + checkin_max.to_s
return false return false
end end
true true
end end

@ -8,13 +8,13 @@
require 'fileutils' require 'fileutils'
def tutorial_folders def tutorial_folders
crates = Dir['**/Cargo.toml'] crates = Dir['**/Cargo.toml']
crates.delete_if do |x| crates.delete_if do |x|
!/[0-9][0-9]/.match?(x[0..1]) !/[0-9][0-9]/.match?(x[0..1])
end end
crates.sort! crates.sort!
end end
puts tutorial_folders if $PROGRAM_NAME == __FILE__ puts tutorial_folders if $PROGRAM_NAME == __FILE__

@ -8,18 +8,18 @@
require_relative 'helpers/tutorial_folders.rb' require_relative 'helpers/tutorial_folders.rb'
def make_all def make_all
crates = tutorial_folders crates = tutorial_folders
crates.each do |x| crates.each do |x|
x = File.dirname(x) x = File.dirname(x)
puts "\n\n" + x.to_s + "\n\n" puts "\n\n" + x.to_s + "\n\n"
Dir.chdir(x) do Dir.chdir(x) do
unless system('make') unless system('make')
puts "\n\nBuild failed!" puts "\n\nBuild failed!"
exit(1) # Exit with error code exit(1) # Exit with error code
end end
end
end end
end
end end
make_all if $PROGRAM_NAME == __FILE__ make_all if $PROGRAM_NAME == __FILE__

@ -9,36 +9,36 @@ require_relative 'helpers/copyrighted'
require_relative 'helpers/tutorial_folders.rb' require_relative 'helpers/tutorial_folders.rb'
def patched? def patched?
crates = tutorial_folders crates = tutorial_folders
crates.each do |f| crates.each do |f|
unless File.readlines(f).grep(/patch.crates-io/).empty? unless File.readlines(f).grep(/patch.crates-io/).empty?
puts "#{fb} contains patch.crates-io!" puts "#{fb} contains patch.crates-io!"
exit(1) exit(1)
end
end end
end
end end
def check_old_copyrights def check_old_copyrights
error = false error = false
sources = Dir.glob('**/*.{S,rs,rb}') + Dir.glob('**/Makefile') sources = Dir.glob('**/*.{S,rs,rb}') + Dir.glob('**/Makefile')
sources.delete_if do |x| sources.delete_if do |x|
!system("git ls-files --error-unmatch #{x}", %i[out err] => File::NULL) !system("git ls-files --error-unmatch #{x}", %i[out err] => File::NULL)
end end
sources.sort.reverse_each do |f| sources.sort.reverse_each do |f|
puts "Checking for copyright: #{f}" puts "Checking for copyright: #{f}"
error = true unless copyrighted?(f, false) error = true unless copyrighted?(f, false)
end end
exit(1) if error exit(1) if error
end end
def sanity_checks def sanity_checks
patched? patched?
check_old_copyrights check_old_copyrights
end end
sanity_checks if $PROGRAM_NAME == __FILE__ sanity_checks if $PROGRAM_NAME == __FILE__

Loading…
Cancel
Save