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.
#[cfg(feature = "bsp_rpi3")]
pub mod rpi3;
mod rpi3;
#[cfg(feature = "bsp_rpi3")]
pub use rpi3::*;

@ -12,8 +12,8 @@
#![no_main]
#![no_std]
// Conditionally includes the selected `architecture` code, which provides the
// `_start()` function, the first function to run.
// Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// the first function to run.
mod arch;
// 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,
+ // 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
--- 01_wait_forever/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
--- 01_wait_forever/src/main.rs
+++ 02_runtime_init/src/main.rs
@@ -16,9 +16,16 @@
// `_start()` function, the first function to run.
@@ -16,9 +16,15 @@
// 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.
@ -110,8 +125,8 @@ diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.r
+
+//! Rust runtime initialization code.
+
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
+/// then calls the kernel entry.
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
+/// kernel entry.
+///
+/// Called from `BSP` code.
+///

Binary file not shown.

Binary file not shown.

@ -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)]

@ -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::*;

@ -12,12 +12,11 @@
#![no_main]
#![no_std]
// Conditionally includes the selected `architecture` code, which provides the
// `_start()` function, the first function to run.
// Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// 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.

@ -4,8 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// 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
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
--- 02_runtime_init/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.
@ -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.
+struct QEMUOutput;
+
+/// Implementing `console::Write` enables usage of the `format_args!` macros,
+/// which in turn are used to implement the `kernel`'s `print!` and `println!`
+/// macros.
+/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
+/// to implement the `kernel`'s `print!` and `println!` macros.
+///
+/// See [`src/print.rs`].
+///
@ -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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+
+/// Returns a ready-to-use `console::Write` implementation.
+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 {
+ /// Console write functions.
+ ///
+ /// `core::fmt::Write` is exactly what we need for now. Re-export it here
+ /// because implementing `console::Write` gives a better hint to the reader
+ /// about the intention.
+ /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
+ /// implementing `console::Write` gives a better hint to the reader about the
+ /// intention.
+ pub use core::fmt::Write;
+
+ /// Console read functions.
@ -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
--- 02_runtime_init/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")]
//! The `kernel`
+//!
+//! The `kernel` is composed by glueing together hardware-specific Board Support
+//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
+//! [`kernel::interface`] traits.
+//! The `kernel` is composed by glueing together code from
+//!
+//! - [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
#![feature(asm)]
@ -132,7 +153,15 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
#![no_main]
#![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.
mod bsp;

Binary file not shown.

Binary file not shown.

@ -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)]

@ -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::*;

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

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

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

@ -4,8 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// 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
--- 03_hacky_hello_world/src/arch/aarch64.rs
+++ 04_zero_overhead_abstraction/src/arch/aarch64.rs
@@ -4,7 +4,29 @@
@@ -4,7 +4,28 @@
//! 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 function must be named `_start`, because the linker is looking for this
+/// exact name.
+/// The function must be named `_start`, because the linker is looking for this exact name.
+///
+/// # 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
@@ -13,9 +35,7 @@
@@ -13,9 +34,7 @@
/// Pause execution on the calling CPU core.
#[inline(always)]
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
--- 03_hacky_hello_world/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
-#![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)]
#![no_main]
#![no_std]
@@ -37,7 +35,8 @@
@@ -43,7 +41,8 @@
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {

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

@ -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::*;

@ -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.
struct QEMUOutput;
/// Implementing `console::Write` enables usage of the `format_args!` macros,
/// which in turn are used to implement the `kernel`'s `print!` and `println!`
/// macros.
/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
/// to implement the `kernel`'s `print!` and `println!` macros.
///
/// See [`src/print.rs`].
///
@ -32,9 +31,9 @@ impl interface::console::Write for QEMUOutput {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
/// Returns a ready-to-use `console::Write` implementation.
pub fn console() -> impl interface::console::Write {

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

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

@ -4,8 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// 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
--- 04_zero_overhead_abstraction/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
+//
+// 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].
+///
+/// In contrast to a real Mutex implementation, does not protect against
+/// concurrent access to the contained data. This part is preserved for later
+/// lessons.
+/// In contrast to a real Mutex implementation, does not protect against concurrent access to the
+/// contained data. This part is preserved for later lessons.
+///
+/// The lock will only be used as long as it is safe to do so, i.e. as long as
+/// the kernel is executing single-threaded, aka only running on a single core
+/// with interrupts disabled.
+/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is
+/// executing single-threaded, aka only running on a single core with interrupts disabled.
+///
+/// [interior mutability]: https://doc.rust-lang.org/std/cell/index.html
+pub struct NullLock<T: ?Sized> {
@ -87,9 +85,8 @@ diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/
+ type Data = T;
+
+ fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R {
+ // In a real lock, there would be code encapsulating this line that
+ // ensures that this mutable reference will ever only be given out once
+ // at a time.
+ // In a real lock, there would be code encapsulating this line that ensures that this
+ // mutable reference will ever only be given out once at a time.
+ f(unsafe { &mut *self.data.get() })
+ }
+}
@ -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
--- 04_zero_overhead_abstraction/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.
@ -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 `core::fmt::Write` enables usage of the `format_args!` macros,
/// which in turn are used to implement the `kernel`'s `print!` and `println!`
-/// macros.
+/// macros. By implementing `write_str()`, we get `write_fmt()` automatically.
-/// Implementing `console::Write` enables usage of the `format_args!` macros, which in turn are used
-/// to implement the `kernel`'s `print!` and `println!` macros.
+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
+/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
+/// we get `write_fmt()` automatically.
+///
+/// The function takes an `&mut self`, so it must be implemented for the inner
+/// struct.
+/// The function takes an `&mut self`, so it must be implemented for the inner struct.
///
/// 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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+
+/// The main struct.
+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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+
+/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded
+/// by a Mutex to serialize access.
+/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
+/// serialize access.
+impl interface::console::Write for QEMUOutput {
+ fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
+ use interface::sync::Mutex;
+
+ // Fully qualified syntax for the call to
+ // `core::fmt::Write::write:fmt()` to increase readability.
+ // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
+ // readability.
+ let mut r = &self.inner;
+ 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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+
+static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new();
+
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
-/// Returns a ready-to-use `console::Write` implementation.
-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
}
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
--- 04_zero_overhead_abstraction/src/interface.rs
+++ 05_safe_globals/src/interface.rs
@@ -20,17 +20,68 @@
@@ -20,17 +20,66 @@
/// System console operations.
pub mod console {
@ -262,9 +245,9 @@ diff -uNr 04_zero_overhead_abstraction/src/interface.rs 05_safe_globals/src/inte
+
/// Console write functions.
- ///
- /// `core::fmt::Write` is exactly what we need for now. Re-export it here
- /// because implementing `console::Write` gives a better hint to the reader
- /// about the intention.
- /// `core::fmt::Write` is exactly what we need for now. Re-export it here because
- /// implementing `console::Write` gives a better hint to the reader about the
- /// intention.
- pub use core::fmt::Write;
+ pub trait Write {
+ 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.
+pub mod sync {
+ /// Any object implementing this trait guarantees exclusive access to the
+ /// data contained within the mutex for the duration of the lock.
+ /// Any object implementing this trait guarantees exclusive access to the data contained within
+ /// the mutex for the duration of the lock.
+ ///
+ /// The trait follows the [Rust embedded WG's
+ /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md)
+ /// and therefore provides some goodness such as [deadlock
+ /// proposal](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md) and therefore
+ /// provides some goodness such as [deadlock
+ /// prevention](https://github.com/korken89/wg/blob/master/rfcs/0377-mutex-trait.md#design-decisions-and-compatibility).
+ ///
+ /// # Example
+ ///
+ /// Since the lock function takes an `&mut self` to enable
+ /// deadlock-prevention, the trait is best implemented **for a reference to
+ /// a container struct**, and has a usage pattern that might feel strange at
+ /// first:
+ /// Since the lock function takes an `&mut self` to enable deadlock-prevention, the trait is
+ /// best implemented **for a reference to a container struct**, and has a usage pattern that
+ /// might feel strange at first:
+ ///
+ /// ```
+ /// static MUT: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(0));
@ -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 Data;
+
+ /// Creates a critical section and grants temporary mutable access to
+ /// the encapsulated data.
+ /// Creates a critical section and grants temporary mutable access to the encapsulated data.
+ fn lock<R>(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R;
+ }
}
@ -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
--- 04_zero_overhead_abstraction/src/main.rs
+++ 05_safe_globals/src/main.rs
@@ -15,6 +15,7 @@
@@ -21,6 +21,7 @@
#![feature(format_args_nl)]
#![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_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`.
fn kernel_entry() -> ! {

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

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

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

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

@ -7,10 +7,16 @@
//! The `kernel`
//!
//! The `kernel` is composed by glueing together hardware-specific Board Support
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! The `kernel` is composed by glueing together code from
//!
//! - [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
#![feature(format_args_nl)]
@ -19,12 +25,11 @@
#![no_main]
#![no_std]
// Conditionally includes the selected `architecture` code, which provides the
// `_start()` function, the first function to run.
// Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// 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.

@ -4,8 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// 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
--- 05_safe_globals/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
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
+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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+use interface::sync::Mutex;
+
+/// 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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+
+impl interface::driver::DeviceDriver for GPIO {
+ 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
--- 05_safe_globals/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
+//
+// 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
+ AUX_ENABLES [
+ /// If set the mini UART is enabled. The UART will immediately
+ /// start receiving data, especially if the UART1_RX line is
+ /// low.
+ /// If clear the mini UART is disabled. That also disables any
+ /// mini UART register access
+ /// If set the mini UART is enabled. The UART will immediately start receiving data,
+ /// especially if the UART1_RX line is low.
+ ///
+ /// If clear the mini UART is disabled. That also disables any mini UART register access
+ 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
+ AUX_MU_LSR [
+ /// This bit is set if the transmit FIFO is empty and the transmitter is
+ /// idle. (Finished shifting out the last bit).
+ /// This bit is set if the transmit FIFO is empty and the transmitter is idle. (Finished
+ /// 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) []
+ ],
+
@ -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,
+/// which in turn are used to implement the `kernel`'s `print!` and `println!`
+/// macros. By implementing `write_str()`, we get `write_fmt()` automatically.
+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
+/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
+/// we get `write_fmt()` automatically.
+///
+/// The function takes an `&mut self`, so it must be implemented for the inner
+/// struct.
+/// The function takes an `&mut self`, so it must be implemented for the inner struct.
+///
+/// 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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+
+/// The driver's main struct.
+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
+////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
+use interface::sync::Mutex;
+
+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 {
+ /// Passthrough of `args` to the `core::fmt::Write` implementation, but
+ /// guarded by a Mutex to serialize access.
+ /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
+ /// serialize access.
+ fn write_char(&self, c: char) {
+ let mut r = &self.inner;
+ r.lock(|inner| inner.write_char(c));
+ }
+
+ fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
+ // Fully qualified syntax for the call to
+ // `core::fmt::Write::write:fmt()` to increase readability.
+ // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
+ // readability.
+ let mut r = &self.inner;
+ 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
--- 05_safe_globals/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.
@ -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,
-/// which in turn are used to implement the `kernel`'s `print!` and `println!`
-/// macros. By implementing `write_str()`, we get `write_fmt()` automatically.
-/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
-/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
-/// we get `write_fmt()` automatically.
-///
-/// The function takes an `&mut self`, so it must be implemented for the inner
-/// struct.
-/// The function takes an `&mut self`, so it must be implemented for the inner struct.
-///
-/// 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
+// Global BSP driver instances
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
-/// The main struct.
-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 =
+ unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) };
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
-// OS interface implementations
+// Implementation of the kernel's BSP calls
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
-/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded
-/// by a Mutex to serialize access.
-/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
-/// serialize access.
-impl interface::console::Write for QEMUOutput {
- fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
- use interface::sync::Mutex;
-
- // Fully qualified syntax for the call to
- // `core::fmt::Write::write:fmt()` to increase readability.
- // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
- // readability.
- let mut r = &self.inner;
- 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
}
-////////////////////////////////////////////////////////////////////////////////
-//--------------------------------------------------------------------------------------------------
-// Global instances
-////////////////////////////////////////////////////////////////////////////////
-//--------------------------------------------------------------------------------------------------
-
-static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new();
+/// 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]
+}
-////////////////////////////////////////////////////////////////////////////////
-//--------------------------------------------------------------------------------------------------
-// Implementation of the kernel's BSP calls
-////////////////////////////////////////////////////////////////////////////////
-//--------------------------------------------------------------------------------------------------
+/// The BSP's main initialization function.
+///
+/// Called early on kernel start.
+pub fn init() {
+ for i in device_drivers().iter() {
+ if let Err(()) = i.init() {
+ // This message will only be readable if, at the time of failure,
+ // the return value of `bsp::console()` is already in functioning
+ // state.
+ // This message will only be readable if, at the time of failure, the return value of
+ // `bsp::console()` is already in functioning state.
+ 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;
}
@@ -85,3 +86,20 @@
@@ -83,3 +84,20 @@
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
--- 05_safe_globals/src/main.rs
+++ 06_drivers_gpio_uart/src/main.rs
@@ -36,12 +36,23 @@
@@ -41,12 +41,23 @@
/// Entrypoint of the `kernel`.
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 function must be named `_start`, because the linker is looking for this
/// exact name.
/// The function must be named `_start`, because the linker is looking for this exact name.
///
/// # Safety
///
@ -30,9 +29,9 @@ pub unsafe extern "C" fn _start() -> ! {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
pub use asm::nop;

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

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

@ -17,11 +17,10 @@ register_bitfields! {
/// Auxiliary enables
AUX_ENABLES [
/// If set the mini UART is enabled. The UART will immediately
/// start receiving data, especially if the UART1_RX line is
/// low.
/// If clear the mini UART is disabled. That also disables any
/// mini UART register access
/// If set the mini UART is enabled. The UART will immediately start receiving data,
/// especially if the UART1_RX line is low.
///
/// If clear the mini UART is disabled. That also disables any mini UART register access
MINI_UART_ENABLE OFFSET(0) NUMBITS(1) []
],
@ -47,16 +46,14 @@ register_bitfields! {
/// Mini Uart Line Status
AUX_MU_LSR [
/// This bit is set if the transmit FIFO is empty and the transmitter is
/// idle. (Finished shifting out the last bit).
/// This bit is set if the transmit FIFO is empty and the transmitter is idle. (Finished
/// 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) []
],
@ -155,12 +152,11 @@ impl MiniUartInner {
}
}
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros,
/// which in turn are used to implement the `kernel`'s `print!` and `println!`
/// macros. By implementing `write_str()`, we get `write_fmt()` automatically.
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
/// we get `write_fmt()` automatically.
///
/// The function takes an `&mut self`, so it must be implemented for the inner
/// struct.
/// The function takes an `&mut self`, so it must be implemented for the inner struct.
///
/// See [`src/print.rs`].
///
@ -182,9 +178,9 @@ impl fmt::Write for MiniUartInner {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// BSP-public
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
/// The driver's main struct.
pub struct MiniUart {
@ -202,9 +198,9 @@ impl MiniUart {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// OS interface implementations
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
use interface::sync::Mutex;
impl interface::driver::DeviceDriver for MiniUart {
@ -238,16 +234,16 @@ impl interface::driver::DeviceDriver for MiniUart {
}
impl interface::console::Write for MiniUart {
/// Passthrough of `args` to the `core::fmt::Write` implementation, but
/// guarded by a Mutex to serialize access.
/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
/// serialize access.
fn write_char(&self, c: char) {
let mut r = &self.inner;
r.lock(|inner| inner.write_char(c));
}
fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
// Fully qualified syntax for the call to
// `core::fmt::Write::write:fmt()` to increase readability.
// Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
// readability.
let mut r = &self.inner;
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_STACK_START: u64 = 0x80_000;
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Global BSP driver instances
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) };
static MINI_UART: driver::MiniUart =
unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) };
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
/// Board identification.
pub fn board_name() -> &'static str {
@ -34,8 +34,7 @@ pub fn console() -> &'static impl interface::console::All {
&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
///
@ -50,9 +49,8 @@ pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
pub fn init() {
for i in device_drivers().iter() {
if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure,
// the return value of `bsp::console()` is already in functioning
// state.
// This message will only be readable if, at the time of failure, the return value of
// `bsp::console()` is already in functioning state.
panic!("Error loading driver: {}", i.compatible())
}
}

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

@ -7,10 +7,16 @@
//! The `kernel`
//!
//! The `kernel` is composed by glueing together hardware-specific Board Support
//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
//! [`kernel::interface`] traits.
//! The `kernel` is composed by glueing together code from
//!
//! - [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
#![feature(format_args_nl)]
@ -19,12 +25,11 @@
#![no_main]
#![no_std]
// Conditionally includes the selected `architecture` code, which provides the
// `_start()` function, the first function to run.
// Conditionally includes the selected `architecture` code, which provides the `_start()` function,
// 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.

@ -4,8 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// 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
--- 06_drivers_gpio_uart/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 {
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
--- 06_drivers_gpio_uart/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;
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 {
@@ -267,14 +276,14 @@
@@ -263,14 +274,14 @@
}
// Read one character.
- let mut ret = inner.AUX_MU_IO.get() as u8 as char;
-
- // Convert carrige return to newline.
- if ret == '
' {
- if 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.
+pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x80_000;
+
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// 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
--- 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_fmt(&self, args: fmt::Arguments) -> fmt::Result;
+
+ /// Block execution until the last character has been physically put on
+ /// the TX wire (draining TX buffers/FIFOs, if any).
+ /// Block execution until the last character has been physically put on the TX wire
+ /// (draining TX buffers/FIFOs, if any).
+ 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
--- 06_drivers_gpio_uart/src/main.rs
+++ 07_uart_chainloader/src/main.rs
@@ -23,8 +23,11 @@
// `_start()` function, the first function to run.
@@ -29,7 +29,11 @@
// 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()`.
+// `_start()` then calls `relocate::relocate_self()`.
+mod relocate;
+
+// `relocate::relocate_self()` calls `runtime_init::init()`, which on
+// completion, jumps to `kernel_entry()`.
+// `relocate::relocate_self()` calls `runtime_init::init()`, which on completion, jumps to
+// `kernel_entry()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@@ -41,18 +44,48 @@
@@ -46,18 +50,48 @@
// Run the BSP's initialization code.
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");
+ bsp::console().flush();
+
+ // Clear the RX FIFOs, if any, of spurious received characters before
+ // starting with the loader protocol.
+ // Clear the RX FIFOs, if any, of spurious received characters before starting with the loader
+ // protocol.
+ bsp::console().clear();
+
+ // 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
--- 06_drivers_gpio_uart/src/relocate.rs
+++ 07_uart_chainloader/src/relocate.rs
@@ -0,0 +1,47 @@
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
+
+//! Relocation code.
+
+/// Relocates the own binary from `bsp::BOARD_DEFAULT_LOAD_ADDRESS` to the
+/// `__binary_start` address from the linker script.
+/// Relocates the own binary from `bsp::BOARD_DEFAULT_LOAD_ADDRESS` to the `__binary_start` address
+/// from the linker script.
+///
+/// # Safety
+///
@ -341,8 +364,7 @@ diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.
+
+ // Copy the whole binary.
+ //
+ // This is essentially a `memcpy()` optimized for throughput by transferring
+ // in chunks of T.
+ // This is essentially a `memcpy()` optimized for throughput by transferring in chunks of T.
+ let n = binary_size_in_byte / core::mem::size_of::<T>();
+ for _ in 0..n {
+ 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);
+ }
+
+ // Call `init()` through a trait object, causing the jump to use an absolute
+ // address to reach the relocated binary. An elaborate explanation can be
+ // found in the runtime_init.rs source comments.
+ // Call `init()` through a trait object, causing the jump to use an absolute address to reach
+ // the relocated binary. An elaborate explanation can be found in the runtime_init.rs source
+ // comments.
+ crate::runtime_init::get().init()
+}
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
+++ 07_uart_chainloader/src/runtime_init.rs
@@ -4,23 +4,44 @@
@@ -4,23 +4,41 @@
//! Rust runtime initialization code.
-/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
-/// then calls the kernel entry.
+/// We are outsmarting the compiler here by using a trait as a layer of
+/// indirection. Because we are generating PIC code, a static dispatch to
+/// `init()` would generate a relative jump from the callee to `init()`.
+/// 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 has put it. So we do not want a relative jump, because
+/// it would not jump to the relocated code.
-/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
-/// kernel entry.
+/// We are outsmarting the compiler here by using a trait as a layer of indirection. Because we are
+/// generating PIC code, a static dispatch to `init()` would generate a relative jump from the
+/// callee to `init()`. 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
+/// has put it. So we do not want a relative jump, because it would not jump to the relocated 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.
- static mut __bss_start: u64;
- static mut __bss_end: u64;
+/// By indirecting through a trait object, we can make use of the property that
+/// vtables store absolute addresses. So calling `init()` this way will kick
+/// execution to the relocated binary.
+/// By indirecting through a trait object, we can make use of the property that vtables store
+/// absolute addresses. So calling `init()` this way will kick execution to the relocated binary.
+pub trait RunTimeInit {
+ /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
+ /// then calls the kernel entry.
+ /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
+ /// kernel entry.
+ ///
+ /// 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 function must be named `_start`, because the linker is looking for this
/// exact name.
/// The function must be named `_start`, because the linker is looking for this exact name.
///
/// # Safety
///
@ -30,9 +29,9 @@ pub unsafe extern "C" fn _start() -> ! {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
pub use asm::nop;

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

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

@ -17,11 +17,10 @@ register_bitfields! {
/// Auxiliary enables
AUX_ENABLES [
/// If set the mini UART is enabled. The UART will immediately
/// start receiving data, especially if the UART1_RX line is
/// low.
/// If clear the mini UART is disabled. That also disables any
/// mini UART register access
/// If set the mini UART is enabled. The UART will immediately start receiving data,
/// especially if the UART1_RX line is low.
///
/// If clear the mini UART is disabled. That also disables any mini UART register access
MINI_UART_ENABLE OFFSET(0) NUMBITS(1) []
],
@ -47,16 +46,14 @@ register_bitfields! {
/// Mini Uart Line Status
AUX_MU_LSR [
/// This bit is set if the transmit FIFO is empty and the transmitter is
/// idle. (Finished shifting out the last bit).
/// This bit is set if the transmit FIFO is empty and the transmitter is idle. (Finished
/// 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) []
],
@ -155,12 +152,11 @@ impl MiniUartInner {
}
}
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros,
/// which in turn are used to implement the `kernel`'s `print!` and `println!`
/// macros. By implementing `write_str()`, we get `write_fmt()` automatically.
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
/// we get `write_fmt()` automatically.
///
/// The function takes an `&mut self`, so it must be implemented for the inner
/// struct.
/// The function takes an `&mut self`, so it must be implemented for the inner struct.
///
/// See [`src/print.rs`].
///
@ -182,9 +178,9 @@ impl fmt::Write for MiniUartInner {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// BSP-public
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
/// The driver's main struct.
pub struct MiniUart {
@ -202,9 +198,9 @@ impl MiniUart {
}
}
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// OS interface implementations
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
use interface::sync::Mutex;
impl interface::driver::DeviceDriver for MiniUart {
@ -238,16 +234,16 @@ impl interface::driver::DeviceDriver for MiniUart {
}
impl interface::console::Write for MiniUart {
/// Passthrough of `args` to the `core::fmt::Write` implementation, but
/// guarded by a Mutex to serialize access.
/// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to
/// serialize access.
fn write_char(&self, c: char) {
let mut r = &self.inner;
r.lock(|inner| inner.write_char(c));
}
fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
// Fully qualified syntax for the call to
// `core::fmt::Write::write:fmt()` to increase readability.
// Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase
// readability.
let mut r = &self.inner;
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.
pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x80_000;
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Global BSP driver instances
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
static GPIO: driver::GPIO = unsafe { driver::GPIO::new(memory_map::mmio::GPIO_BASE) };
static MINI_UART: driver::MiniUart =
unsafe { driver::MiniUart::new(memory_map::mmio::MINI_UART_BASE) };
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's BSP calls
////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------
/// Board identification.
pub fn board_name() -> &'static str {
@ -37,8 +37,7 @@ pub fn console() -> &'static impl interface::console::All {
&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
///
@ -53,9 +52,8 @@ pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
pub fn init() {
for i in device_drivers().iter() {
if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure,
// the return value of `bsp::console()` is already in functioning
// state.
// This message will only be readable if, at the time of failure, the return value of
// `bsp::console()` is already in functioning state.
panic!("Error loading driver: {}", i.compatible())
}
}

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

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

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

@ -4,20 +4,17 @@
//! Rust runtime initialization code.
/// We are outsmarting the compiler here by using a trait as a layer of
/// indirection. Because we are generating PIC code, a static dispatch to
/// `init()` would generate a relative jump from the callee to `init()`.
/// 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 has put it. So we do not want a relative jump, because
/// it would not jump to the relocated code.
/// We are outsmarting the compiler here by using a trait as a layer of indirection. Because we are
/// generating PIC code, a static dispatch to `init()` would generate a relative jump from the
/// callee to `init()`. 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
/// 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
/// vtables store absolute addresses. So calling `init()` this way will kick
/// execution to the relocated binary.
/// By indirecting through a trait object, we can make use of the property that vtables store
/// absolute addresses. So calling `init()` this way will kick execution to the relocated binary.
pub trait RunTimeInit {
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
///

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

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

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

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

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

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

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

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

Loading…
Cancel
Save